diff --git a/pms/cbvs.py b/pms/cbvs.py index 48a504cc7..811111d51 100644 --- a/pms/cbvs.py +++ b/pms/cbvs.py @@ -8,16 +8,18 @@ from django.utils.decorators import method_decorator from django.utils.translation import gettext_lazy as _trans from base.methods import filter_own_and_subordinate_recordes, is_reportingmanager -from employee.forms import EmployeeForm +from employee.models import Employee from horilla import horilla_middlewares -from horilla.decorators import login_required, permission_required +from horilla.decorators import login_required, owner_can_enter, permission_required from horilla_views.generic.cbv import views from pms import models from pms.filters import BonusPointSettingFilter, EmployeeBonusPointFilter from pms.forms import ( BonusPointSettingForm, + BulkFeedbackForm, EmployeeBonusPointForm, EmployeeFeedbackForm, + FeedbackForm, ) from pms.methods import check_duplication @@ -275,10 +277,7 @@ class EmployeeBonusPointListView(views.HorillaListView): ####################### Feedback ######################################## -# @method_decorator(login_required, name="dispatch") -# @method_decorator( -# permission_required("pms.change_feedback"), name="dispatch" -# ) +@method_decorator(login_required, name="dispatch") class FeedbackEmployeeFormView(views.HorillaFormView): """ Feedback other employee form View @@ -301,7 +300,7 @@ class FeedbackEmployeeFormView(views.HorillaFormView): ) return super().form_invalid(form) - def form_valid(self, form: EmployeeForm) -> views.HttpResponse: + def form_valid(self, form: EmployeeFeedbackForm) -> views.HttpResponse: if form.is_valid(): message = "Feedback request sent." other_employees = check_duplication( @@ -312,3 +311,87 @@ class FeedbackEmployeeFormView(views.HorillaFormView): messages.success(self.request, _trans(message)) return self.HttpResponse("") return super().form_valid(form) + + +@method_decorator(login_required, name="dispatch") +@method_decorator(permission_required("pms.add_feedback"), name="dispatch") +class BulkFeedbackFormView(views.HorillaFormView): + """ + Feedback other employee form View + """ + + form_class = BulkFeedbackForm + model = models.Feedback + view_id = "BulkFeedbackForm" + new_display_title = _trans("Bulk Feedback request ") + template_name = "feedback/bulk_feedback_form.html" + + def get_context_data(self, **kwargs): + context = super().get_context_data(**kwargs) + return context + + def form_invalid(self, form: Any) -> HttpResponse: + if not form.is_valid(): + errors = form.errors.as_data() + return render( + self.request, self.template_name, {"form": form, "errors": errors} + ) + return super().form_invalid(form) + + def form_valid(self, form: BulkFeedbackForm) -> views.HttpResponse: + if form.is_valid(): + message = "Bulk Feedback request sent." + cleaned_data = form.cleaned_data + employees = cleaned_data["employee_ids"] + for employee in employees: + reporting_manager = employee.get_reporting_manager() + manager_id = ( + reporting_manager if cleaned_data["include_manager"] else None + ) + data = { + "review_cycle": f"{cleaned_data['title']}-{employee} feedback", + "employee_id": employee, + "manager_id": manager_id, + "question_template_id": cleaned_data["question_template_id"], + "start_date": cleaned_data["start_date"], + "end_date": cleaned_data["end_date"], + "cyclic_feedback": cleaned_data["cyclic_feedback"], + "cyclic_feedback_days_count": cleaned_data[ + "cyclic_feedback_days_count" + ], + "cyclic_feedback_period": cleaned_data["cyclic_feedback_period"], + "status": cleaned_data["status"], + } + feedback_form = FeedbackForm(data) + if feedback_form.is_valid(): + feedback = feedback_form.save() + if cleaned_data["include_keyresult"]: + keyresults = models.EmployeeKeyResult.objects.filter( + employee_objective_id__employee_id=employee.id + ) + feedback.employee_key_results_id.add(*keyresults) + if cleaned_data["include_colleagues"]: + department = employee.get_department() + # employee ids to exclude from collegue list + exclude_ids = [employee.id] + if reporting_manager: + exclude_ids.append(reporting_manager.id) + # Get employees in the same department as the employee + colleagues = Employee.objects.filter( + is_active=True, employee_work_info__department_id=department + ).exclude(id__in=exclude_ids) + feedback.colleague_id.add(*colleagues) + + if cleaned_data["include_subordinates"]: + subordinates = Employee.objects.filter( + is_active=True, + employee_work_info__reporting_manager_id=employee, + ) + feedback.subordinate_id.add(*subordinates) + other_employees = check_duplication( + feedback, cleaned_data["other_employees"] + ) + feedback.others_id.add(*other_employees) + messages.success(self.request, _trans(message)) + return self.HttpResponse("") + return super().form_valid(form) diff --git a/pms/forms.py b/pms/forms.py index 8433cec95..314d84fe5 100644 --- a/pms/forms.py +++ b/pms/forms.py @@ -1201,3 +1201,103 @@ class EmployeeFeedbackForm(HorillaModelForm): cleaned_data["others_id"] = employee_data return cleaned_data + + +class BulkFeedbackForm(HorillaModelForm): + """Form for creating feedback in bulk""" + + title = forms.CharField(required=True, label=_("Title")) + employee_ids = forms.ModelMultipleChoiceField( + queryset=Employee.objects.filter(is_active=True), required=True + ) + other_employees = forms.ModelMultipleChoiceField( + queryset=Employee.objects.filter(is_active=True), + required=False, + label=_("Other employees"), + help_text=_("Employees need to sent feedback request."), + ) + include_manager = forms.BooleanField( + initial=True, + required=False, + ) + include_subordinates = forms.BooleanField( + initial=True, required=False, label=_("Include all subordinates") + ) + include_colleagues = forms.BooleanField( + initial=True, required=False, label=_("Include all colleagues") + ) + include_keyresult = forms.BooleanField( + initial=True, + required=False, + label=_("Include all keyresults"), + help_text=_("Include all keyresults assigned to the employee."), + ) + period = forms.ModelChoiceField( + queryset=Period.objects.all(), + label=_("Period"), + required=False, + widget=forms.Select( + attrs={ + "onchange": "periodChange($(this))", + } + ), + ) + + class Meta: + model = Feedback + fields = [ + "title", + "employee_ids", + "status", + "other_employees", + "include_manager", + "include_subordinates", + "include_colleagues", + "include_keyresult", + "question_template_id", + "cyclic_feedback", + "cyclic_feedback_period", + "cyclic_feedback_days_count", + "period", + "start_date", + "end_date", + ] + widgets = { + "start_date": forms.DateInput( + attrs={"type": "date", "class": "oh-input w-100"} + ), + "end_date": forms.DateInput( + attrs={"type": "date", "class": "oh-input w-100"} + ), + } + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.fields["employee_ids"] = HorillaMultiSelectField( + queryset=Employee.objects.filter(employee_work_info__isnull=False), + widget=HorillaMultiSelectWidget( + filter_route_name="employee-widget-filter", + filter_class=EmployeeFilter, + filter_instance_contex_name="f", + filter_template_path="employee_filters.html", + form=self, + instance=self.instance, + required=True, + ), + label=_("Employees"), + ) + self.fields["status"].initial = "Not Started" + self.fields["cyclic_feedback"].widget.attrs["onchange"] = "cyclicFeedback()" + + def clean(self): + cleaned_data = super().clean() + if isinstance(self.fields["employee_ids"], HorillaMultiSelectField): + self.errors.pop("employee_ids", None) + + employee_data = self.fields["employee_ids"].queryset.filter( + id__in=self.data.getlist("employee_ids") + ) + + cleaned_data["employee_ids"] = employee_data + + return cleaned_data diff --git a/pms/static/src/feedback/action.js b/pms/static/src/feedback/action.js index 7d0de5234..fecc87476 100644 --- a/pms/static/src/feedback/action.js +++ b/pms/static/src/feedback/action.js @@ -14,7 +14,7 @@ var unarchiveMessages = { fr: "Voulez-vous vraiment désarchiver tous les retours sélectionnés?", }; -var deleteMessages = { +var deleteFeedbackMessages = { ar: "هل ترغب حقاً في حذف كل التعليقات المحددة؟", de: "Möchten Sie wirklich alle ausgewählten Rückmeldungen löschen?", es: "¿Realmente quieres eliminar todas las retroalimentaciones seleccionadas?", @@ -219,7 +219,7 @@ $("#deleteFeedback").click(function (e) { var languageCode = null; getCurrentLanguageCode(function (code) { languageCode = code; - var confirmMessage = deleteMessages[languageCode]; + var confirmMessage = deleteFeedbackMessages[languageCode]; var textMessage = norowMessages[languageCode]; var checkedRows = $(".feedback-checkbox").filter(":checked"); if (checkedRows.length === 0) { diff --git a/pms/templates/feedback/bulk_feedback_form.html b/pms/templates/feedback/bulk_feedback_form.html new file mode 100644 index 000000000..447d0a583 --- /dev/null +++ b/pms/templates/feedback/bulk_feedback_form.html @@ -0,0 +1,50 @@ +{% load static %} +{% include "generic/horilla_form.html" %} + + diff --git a/pms/templates/feedback/feedback_empty.html b/pms/templates/feedback/feedback_empty.html index 8ea9a0dcd..5c5bd9031 100644 --- a/pms/templates/feedback/feedback_empty.html +++ b/pms/templates/feedback/feedback_empty.html @@ -21,7 +21,37 @@
- + {% if perms.pms.add_feedback %} +
+
+ + +
+
+ {% endif %} {% if perms.pms.add_feedback or request.user|filtersubordinates %}