""" This page handles the cbv methods for existing process """ import re from datetime import datetime, timedelta from django import forms from django.contrib import messages from django.http import HttpResponse from django.urls import reverse, reverse_lazy from django.utils.decorators import method_decorator from django.utils.translation import gettext_lazy as _ from base.context_processors import intial_notice_period from base.methods import eval_validate from horilla_views.cbv_methods import login_required, permission_required from horilla_views.generic.cbv.pipeline import Pipeline from horilla_views.generic.cbv.views import ( HorillaDetailedView, HorillaFormView, HorillaListView, HorillaNavView, HorillaSectionView, HorillaTabView, ) from notifications.signals import notify from offboarding.cbv_decorators import ( any_manager_can_enter, offboarding_manager_can_enter, offboarding_or_stage_manager_can_enter, ) from offboarding.filters import ( PipelineEmployeeFilter, PipelineFilter, PipelineStageFilter, ) from offboarding.forms import ( OffboardingEmployeeForm, OffboardingForm, OffboardingStageForm, TaskForm, ) from offboarding.models import ( EmployeeTask, Offboarding, OffboardingEmployee, OffboardingStage, OffboardingTask, ) from offboarding.templatetags.offboarding_filter import ( any_manager, is_offboarding_manager, ) @method_decorator(login_required, name="dispatch") @method_decorator( offboarding_manager_can_enter("offboarding.add_offboardingstage"), name="dispatch" ) class OffboardingStageFormView(HorillaFormView): """ form view for create button """ form_class = OffboardingStageForm model = OffboardingStage new_display_title = _("Create Offboarding Stage") def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) offboarding_id = self.request.GET["offboarding_id"] self.form.fields["offboarding_id"].initial = offboarding_id self.form.fields["offboarding_id"].widget = forms.HiddenInput() if self.form.instance.pk: self.form_class.verbose_name = _("Update Offboarding Stage") return context def form_valid(self, form: OffboardingStageForm) -> HttpResponse: if form.is_valid(): if form.instance.pk: message = _("Offboarding Stage Updated Successfully") else: message = _("Offboarding Stage Created Successfully") form.save() messages.success(self.request, message) return self.HttpResponse("") return super().form_valid(form) @method_decorator( any_manager_can_enter("offboarding.add_offboardingemployee"), name="dispatch" ) class OffboardingStageAddEmployeeForm(HorillaFormView): """ form view for create button """ form_class = OffboardingEmployeeForm model = OffboardingEmployee new_display_title = _("Add Employee") def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) default_notice_period = ( intial_notice_period(self.request)["get_initial_notice_period"] if intial_notice_period(self.request)["get_initial_notice_period"] else 0 ) end_date = datetime.today() + timedelta(days=default_notice_period) stage_id = self.request.GET["stage_id"] self.form.fields["stage_id"].initial = stage_id self.form.fields["notice_period_ends"].initial = end_date if self.form.instance.pk: self.form_class.verbose_name = _("Update Employee") return context def form_valid(self, form: OffboardingEmployeeForm) -> HttpResponse: stage_id = self.request.GET["stage_id"] stage = OffboardingStage.objects.get(id=stage_id) if form.is_valid(): if form.instance.pk: message = _("Updated Employee") else: message = _("Added Employee") instance = form.save() notify.send( self.request.user.employee_get, recipient=instance.employee_id.employee_user_id, verb=f"You have been added to the {stage} of {stage.offboarding_id}", verb_ar=f"لقد تمت إضافتك إلى {stage} من {stage.offboarding_id}", verb_de=f"Du wurdest zu {stage} von {stage.offboarding_id} hinzugefügt", verb_es=f"Has sido añadido a {stage} de {stage.offboarding_id}", verb_fr=f"Vous avez été ajouté à {stage} de {stage.offboarding_id}", redirect=reverse("offboarding-pipeline"), icon="information", ) form.save() messages.success(self.request, message) return self.HttpResponse("") @method_decorator(login_required, name="dispatch") @method_decorator(permission_required("offboarding.add_offboarding"), name="dispatch") class OffboardingCreateFormView(HorillaFormView): """ form view for create and edit offboarding """ form_class = OffboardingForm model = Offboarding new_display_title = _("Create Offboarding") def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) if self.form.instance.pk: self.form_class.verbose_name = _("Update Offboarding") return context def form_valid(self, form: OffboardingForm) -> HttpResponse: if form.is_valid(): if form.instance.pk: message = _("Offboarding Updated") else: message = _("Offboarding saved") form.save() messages.success(self.request, message) return HttpResponse("") return super().form_valid(form) @method_decorator(login_required, name="dispatch") @method_decorator( offboarding_or_stage_manager_can_enter("offboarding.add_offboardingtask"), name="dispatch", ) class OffboardingTaskFormView(HorillaFormView): """ form view for create and edit offboarding tasks """ model = OffboardingTask form_class = TaskForm new_display_title = _("Create Task") def get_initial(self) -> dict: initial = super().get_initial() stage_id = self.request.GET.get("stage_id") employees = OffboardingEmployee.objects.filter(stage_id=stage_id) if stage_id: initial["stage_id"] = stage_id initial["tasks_to"] = employees return initial def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) stage_id = self.request.GET.get("stage_id") employees = OffboardingEmployee.objects.filter(stage_id=stage_id) if self.form.instance.pk: self.form.fields["stage_id"].initial = stage_id self.form.fields["tasks_to"].initial = employees self.form.fields["tasks_to"].queryset = employees self.form_class.verbose_name = _("Update Task") return context def form_valid(self, form: TaskForm) -> HttpResponse: if form.is_valid(): if form.instance.pk: message = _("Task Updated") else: message = _("Task Added") form.save() messages.success(self.request, message) return self.HttpResponse() return super().form_valid(form) @method_decorator(login_required, name="dispatch") class ExitProcessDetailView(HorillaDetailedView): """ detail view """ model = OffboardingEmployee title = _("Details") header = { "title": "employee_id__get_full_name", "subtitle": "detail_subtitle", "avatar": "employee_id__get_avatar", } empty_template = "cbv/exit_process/detailed_page_empty.html" body = [ (_("Email"), "employee_id__employee_work_info__email"), (_("Job Position"), "employee_id__employee_work_info__job_position_id"), (_("Contact"), "employee_id__phone"), (_("Notice Period start Date"), "notice_period_starts"), (_("Notice Period end Date"), "notice_period_ends"), (_("Stage"), "get_stage_col"), (_("Tasks"), "detail_view_task_custom", "custom_template"), ] cols = { "detail_view_task_custom": 12, } @method_decorator(login_required, name="dispatch") class OffboardingPipelineView(HorillaSectionView): """ Offboarding Pipeline View """ template_name = "cbv/exit_process/pipeline_view.html" nav_url = reverse_lazy("offboarding-pipeline-nav") view_url = reverse_lazy("get-offboarding-tab") view_container_id = "pipelineContainer" @method_decorator(login_required, name="dispatch") class OffboardingPipelineNav(HorillaNavView): """ Offboarding Pipeline Navigation View """ nav_title = "Pipeline" search_swap_target = "#pipelineContainer" search_url = reverse_lazy("get-offboarding-tab") filter_body_template = "cbv/exit_process/pipeline_filter.html" def __init__(self, **kwargs): super().__init__(**kwargs) if self.request.user.has_perm("offboarding.create_offboarding"): self.create_attrs = f""" class="oh-btn oh-btn--secondary" hx-get="{reverse_lazy("create-offboarding")}" hx-target="#objectDetailsModalTarget" data-toggle="oh-modal-toggle" data-target="#objectDetailsModal" """ def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) context["employee_filter"] = PipelineEmployeeFilter() context["pipeline_filter"] = PipelineFilter() context["stage_filter"] = PipelineStageFilter() return context @method_decorator(login_required, name="dispatch") class PipeLineTabView(HorillaTabView): """ Pipeline List View """ def __init__(self, **kwargs): super().__init__(**kwargs) offboardings = PipelineFilter(self.request.GET).qs.filter(is_active=True) self.tabs = [] for offboarding in offboardings: tab = {} tab["actions"] = [] tab["title"] = offboarding.title tab["url"] = reverse( "get-offboarding-stage", kwargs={"offboarding_id": offboarding.pk} ) tab["badge_label"] = _("Stages") if self.request.user.has_perm( "offboarding.add_offboardingstage" ) or is_offboarding_manager(self.request.user.employee_get): tab["actions"].append( { "action": _("Add Stage"), "attrs": f""" data-toggle="oh-modal-toggle" data-target="#genericModal" hx-get="{reverse("create-offboarding-stage")}?offboarding_id={offboarding.pk}" hx-target="#genericModalBody" style="cursor: pointer;" """, } ) tab["actions"].append( { "action": _("Manage Stage Order"), "attrs": f""" data-toggle="oh-modal-toggle" data-target="#genericModal" hx-get="{reverse("update-stage-sequence",kwargs={"pk": offboarding.pk})}" hx-target="#genericModalBody" style="cursor: pointer;" """, } ) if self.request.user.has_perm( "offboarding.change_offboarding" ) or is_offboarding_manager(self.request.user.employee_get): tab["actions"].append( { "action": _("Edit"), "attrs": f""" data-toggle="oh-modal-toggle" data-target="#genericModal" hx-get="{reverse("update-offboarding", kwargs={"pk": offboarding.pk})}" hx-target="#genericModalBody" style="cursor: pointer;" """, } ) if self.request.user.has_perm("offboarding.delete_offboarding"): tab["actions"].append( { "action": _("Delete"), "attrs": f""" data-toggle="oh-modal-toggle" data-target="#deleteConfirmation" hx-get="{reverse('generic-delete')}?model=offboarding.Offboarding&pk={offboarding.pk}" hx-target="#deleteConfirmationBody" style="cursor: pointer;" """, } ) self.tabs.append(tab) @method_decorator(login_required, name="dispatch") class OffboardingPipelineStage(Pipeline): """ Offboarding Pipeline Stage """ model = OffboardingEmployee filter_class = PipelineEmployeeFilter grouper = "stage_id" selected_instances_key_name = "OffboardingEmployeeRecords" allowed_fields = [ { "field": "stage_id", "model": OffboardingStage, "filter": PipelineStageFilter, "url": reverse_lazy("get-offboarding-employees-cbv"), "parameters": [ "offboarding_stage_id={pk}", "offboarding_id={offboarding_id__pk}", ], "actions": [ { "action": "Add Employee", "accessibility": "offboarding.cbv.accessibility.add_employee_accessibility", "attrs": """ data-toggle="oh-modal-toggle" data-target="#genericModal" hx-get="{get_add_employee_url}" hx-target="#genericModalBody" class="oh-dropdown__link" """, }, { "action": "Edit", "accessibility": "offboarding.cbv.accessibility.edit_stage_accessibility", "attrs": """ hx-target="#genericModalBody" hx-get="{get_update_url}" data-toggle="oh-modal-toggle" data-target="#genericModal" """, }, { "action": "Delete", "accessibility": "offboarding.cbv.accessibility.delete_stage_accessibility", "attrs": """ data-target="#deleteConfirmation" data-toggle="oh-modal-toggle" hx-get="{get_delete_url}" hx-target="#deleteConfirmationBody" """, }, ], } ] def get_queryset(self): queryset = super().get_queryset() self.queryset = queryset.order_by("sequence") return self.queryset @method_decorator(login_required, name="dispatch") class OffboardingEmployeeList(HorillaListView): """ Offboarding Employee List View """ model = OffboardingEmployee filter_class = PipelineEmployeeFilter search_url = reverse_lazy("get-offboarding-tab") filter_keys_to_remove = ["offboarding_stage_id", "offboarding_id"] next_prev = False quick_export = False filter_selected = False custom_empty_template = "cbv/pipeline/empty.html" columns = [ ("Employee", "employee_id", "employee_id__get_avatar"), ("Notice Period", "get_notice_period_col"), ("Start Date", "notice_period_starts"), ("End Date", "notice_period_ends"), ("Stage", "get_stage_col"), ("Created At", "get_created_at_date"), ("Task Status", "get_task_status_col"), ] action_method = """get_action_col""" row_attrs = """ class = "fw-bold" hx-get='{get_individual_url}' hx-target='#genericModalBody' data-toggle = 'oh-modal-toggle' data-target="#genericModal" """ bulk_update_fields = ["stage_id"] def get(self, request, *args, **kwargs): self.selected_instances_key_id = ( f"OffboardingEmployeeRecords{self.request.GET['offboarding_stage_id']}" ) return super().get(request, *args, **kwargs) def get_queryset(self, queryset=None, filtered=False, *args, **kwargs): if not getattr(self, "queryset", None): qs = OffboardingEmployee.objects.entire() queryset = super().get_queryset(qs, filtered, *args, **kwargs) if not ( self.request.user.has_perm("offboarding.view_offboarding") or any_manager(self.request.user.employee_get) ): queryset = queryset.filter(employee_id=self.request.user.employee_get) self.queryset = queryset return self.queryset def __init__(self, **kwargs): super().__init__(**kwargs) self.view_id = ( f"offboardingStageContainer{self.request.GET.get('offboarding_stage_id')}" ) self.managing_offboarding_tasks = OffboardingTask.objects.filter( managers__employee_user_id=self.request.user ).values_list("pk", flat=True) self.request.managing_offboarding_tasks = self.managing_offboarding_tasks self.managing_offboarding_stages = OffboardingStage.objects.filter( managers__employee_user_id=self.request.user ).values_list("pk", flat=True) self.request.managing_offboarding_stages = self.managing_offboarding_stages self.managing_offboardings = Offboarding.objects.filter( managers__employee_user_id=self.request.user ).values_list("pk", flat=True) self.request.managing_offboardings = self.managing_offboardings def get_context_data(self, **kwargs): stage_id = self.request.GET["offboarding_stage_id"] tasks = OffboardingTask.objects.filter(stage_id=stage_id) context = super().get_context_data(**kwargs) for task in tasks: context["columns"].append( ( f"""
""", f"get_{task.pk}_task", ) ) if self.request.user.has_perm( "perms.offboarding.add_offboardingtask" ) or any_manager(self.request.user.employee_get): context["columns"].append( ( f""" """, "", ) ) return context def bulk_update_accessibility(self): return ( self.request.user.has_perm("offboarding.change_offboardingstage") or self.request.user.has_perm("offboarding.change_offboarding") or any_manager(self.request.user.employee_get) ) def get_bulk_form(self): form = super().get_bulk_form() offboarding_id = self.request.GET.get("offboarding_id") offboarding_stage_id = self.request.GET.get("offboarding_stage_id") form.fields.get("stage_id").queryset = form.fields.get( "stage_id" ).queryset.filter(offboarding_id=offboarding_id) tasks = OffboardingTask.objects.filter(stage_id=offboarding_stage_id) for task in tasks: form.fields[f"bulk_task_status_{task.pk}"] = forms.ChoiceField( choices=[ ("", "----------"), ] + list(EmployeeTask.statuses), label=task.title, required=False, widget=forms.Select(attrs={"class": "oh-select oh-select-2 w-100"}), ) if not self.bulk_update_accessibility(): del form["stage_id"] return form def handle_bulk_submission(self, request): response = super().handle_bulk_submission(request) mapped_data = { int(re.search(r"bulk_task_status_(\d+)", key).group(1)): value for key, value in request.POST.items() if re.search(r"bulk_task_status_(\d+)", key) } instance_ids = request.POST.get("instance_ids", "[]") instance_ids = eval_validate(instance_ids) for pk, status in mapped_data.items(): EmployeeTask.objects.filter( employee_id__in=instance_ids, task_id=pk ).update(status=status) return response