[ADD] PMS: Anonymous feedback creation in 360 feedback

This commit is contained in:
Horilla
2024-01-17 14:19:51 +05:30
parent 903ecb35b8
commit e0bdb338e6
14 changed files with 560 additions and 31 deletions

View File

@@ -285,4 +285,8 @@ _("mail-server-conf"),
_("configuration"),
_("multiple-approval-condition"),
_("skill-zone-view"),
_("view-mail-templates"),
_("view-mail-templates"),
_("view-loan"),
_("view-reimbursement"),
_("department-manager-view"),
_("date-settings"),

View File

@@ -524,7 +524,7 @@ urlpatterns = [
name="delete-notifications",
),
path("settings/currency/", views.settings, name="currency-settings"),
path("settings/date/", views.date_settings, name="date-settings"),
path("settings/date-settings/", views.date_settings, name="date-settings"),
path("settings/save-date/", views.save_date_format, name="save_date_format"),
path("settings/get-date-format/", views.get_date_format, name="get-date-format"),
path("settings/save-time/", views.save_time_format, name="save_time_format"),

View File

@@ -88,6 +88,12 @@ sidebar_urls = [
"ticket-type-view",
"mail-server-conf",
"multiple-approval-condition",
"skill-zone-view",
"view-mail-templates",
"view-loan",
"view-reimbursement",
"department-manager-view",
"date-settings",
]
remove_urls = [
"objective-detailed-view",

View File

@@ -5,7 +5,7 @@ This page is used to register PMS models with admins site.
"""
from django.contrib import admin
from simple_history.admin import SimpleHistoryAdmin
from .models import Comment, EmployeeKeyResult, Period, EmployeeObjective
from .models import AnonymousFeedback, Comment, EmployeeKeyResult, Period, EmployeeObjective
from .models import (
Question,
QuestionTemplate,

View File

@@ -13,7 +13,9 @@ from django.forms.utils import ErrorList
from django.utils.translation import gettext_lazy as _
from employee.models import Department, JobPosition
from django.forms import ModelForm
from base.forms import ModelForm as BaseForm
from pms.models import (
AnonymousFeedback,
Question,
EmployeeObjective,
EmployeeKeyResult,
@@ -681,3 +683,10 @@ class PeriodForm(ModelForm):
start_date = cleaned_data.get("start_date")
end_date = cleaned_data.get("end_date")
validate_date(start_date, end_date)
class AnonymousFeedbackForm(BaseForm):
class Meta:
model = AnonymousFeedback
fields = "__all__"
exclude = ["status", "archive"]

View File

@@ -1,2 +0,0 @@

View File

@@ -1,7 +1,7 @@
from django.db import models
from django.forms import ValidationError
from django.utils.translation import gettext_lazy as _
from base.models import Company
from base.models import Company, Department, JobPosition
from base.horilla_company_manager import HorillaCompanyManager
# importing simple history
@@ -146,8 +146,10 @@ class EmployeeKeyResult(models.Model):
if self.employee_id is None:
self.employee_id = self.employee_objective_id.employee_id
if self.target_value != 0:
self.progress_percentage = (int(self.current_value)/int(self.target_value))*100
self.progress_percentage = (
int(self.current_value) / int(self.target_value)
) * 100
super().save(*args, **kwargs)
@@ -261,12 +263,93 @@ class Feedback(models.Model):
EmployeeKeyResult,
blank=True,
)
objects = HorillaCompanyManager("employee_id__employee_work_info__company_id+")
objects = HorillaCompanyManager("employee_id__employee_work_info__company_id")
def __str__(self):
return f"{self.employee_id.employee_first_name} - {self.review_cycle}"
class AnonymousFeedback(models.Model):
"""feedback model for creating feedback"""
STATUS_CHOICES = (
("On Track", _("On Track")),
("Behind", _("Behind")),
("Closed", _("Closed")),
("At Risk", _("At Risk")),
("Not Started", _("Not Started")),
)
BASED_ON_CHOICES = (
("general", _("General")),
("employee", _("Employee")),
("department", _("Department")),
("job_position", _("Job Position")),
)
feedback_subject = models.CharField(max_length=100, null=False, blank=False)
based_on = models.CharField(
max_length=50, choices=BASED_ON_CHOICES, default="general"
)
employee_id = models.ForeignKey(
Employee,
on_delete=models.CASCADE,
null=True,
blank=True,
verbose_name=_("Employee"),
)
department_id = models.ForeignKey(
Department,
on_delete=models.CASCADE,
null=True,
blank=True,
verbose_name=_("Department"),
)
job_position_id = models.ForeignKey(
JobPosition,
on_delete=models.CASCADE,
null=True,
blank=True,
verbose_name=_("Job Position"),
)
status = models.CharField(
max_length=50, choices=STATUS_CHOICES, default="Not Started"
)
created_at = models.DateField(auto_now_add=True)
archive = models.BooleanField(null=True, blank=True, default=False)
anonymous_feedback_id = models.CharField(
max_length=10, null=True, blank=False, editable=False
)
feedback_description = models.TextField(null=True, blank=True)
def __str__(self) -> str:
return f"Feedback based on a {self.based_on}"
def clean(self, *args, **kwargs):
if self.based_on == "employee":
self._validate_required_field("employee_id", "Employee")
self.department_id = None
self.job_position_id = None
elif self.based_on == "department":
self._validate_required_field("department_id", "Department")
self.employee_id = None
self.job_position_id = None
elif self.based_on == "job_position":
self._validate_required_field("job_position_id", "Job Position")
self.employee_id = None
self.department_id = None
return super().clean(*args, **kwargs)
def _validate_required_field(self, field_name, field_label):
if not getattr(self, field_name):
raise ValidationError(
{
field_name: _(
f"The {field_label} field is required when the 'Based on' field is set to '{field_label}'."
)
}
)
class Answer(models.Model):
"""feedback answer model"""

View File

@@ -0,0 +1,72 @@
{% load i18n %}
<script>
$(document).ready(function () {
var fields = [
"#id_employee_field",
"#id_department_field",
"#id_job_position_field",
];
function updateFieldsVisibility() {
var based_on = $("#id_based_on").val();
fields.forEach(function (field) {
if (field.includes(based_on)) {
$(field).show();
} else {
$(field).hide();
}
});
}
updateFieldsVisibility();
$("#id_based_on").change(function () {
updateFieldsVisibility();
});
});
</script>
<form
hx-post='{% if create %}{% url "add-anonymous-feedback" %} {% else %} {% url "edit-anonymous-feedback" form.instance.id %}{% endif %}'
hx-target="#anonymousFeedbackFormModal"
>
{% csrf_token %}
<div class="oh-input__group">
<label class="oh-input__label" for="feedbackSubject" id="idFeedbackSubject"
>{% trans "Feedback Subject" %}:</label
>
{{form.feedback_subject}} {{form.feedback_subject.errors}}
</div>
<div class="oh-input__group">
<label class="oh-input__label" for="basedOn" id="idBasedOn">{% trans "Based on" %}:</label>
{{form.based_on}} {{form.based_on.errors}}
</div>
<div class="oh-input__group" id="id_employee_field">
<label class="oh-input__label" for="feedbackEmployee" id="idFeedbackEmployee">{% trans "Employee" %}:</label>
{{form.employee_id}} {{form.employee_id.errors}}
</div>
<div class="oh-input__group" id="id_department_field">
<label class="oh-input__label" for="feedbackDepartment" id="idFeedbackDepartment"
>{% trans "Department" %}:</label
>
{{form.department_id}} {{form.department_id.errors}}
</div>
<div class="oh-input__group" id="id_job_position_field">
<label class="oh-input__label" for="feedbackJobPosition" id="idFeedbackJobPosition"
>{% trans "Job Position" %}:</label
>
{{form.job_position_id}} {{form.job_position_id.errors}}
</div>
<div class="oh-input__group">
<label class="oh-input__label" for="keyType"
>{% trans "Feedback Desciption" %}:</label
>
{{form.feedback_description}} {{form.feedback_description.errors}}
</div>
<button
type="submit"
class="oh-btn oh-btn--small oh-btn--secondary w-100 mt-3"
>
{% trans "Save" %}
</button>
</form>

View File

@@ -0,0 +1,92 @@
{% load i18n %}
<div class="oh-modal__dialog-header">
<span class="oh-modal__dialog-title" id="addEmployeeObjectiveModalLabel">
<h5 style="margin-bottom: 20px">{% trans "Anonymous Feedback" %}</h5>
</span>
<button
type="button"
class="oh-modal__close"
data-dismiss="oh-modal"
aria-label="Close"
data-toggle="oh-modal-toggle"
hx-target="#OneAllowanceTarget"
>
<ion-icon name="close-outline"></ion-icon>
</button>
<div class="row">
<div class="oh-timeoff-modal__stat">
<span class="oh-timeoff-modal__stat-title">{% trans "Subject" %}</span>
<span class="oh-timeoff-modal__stat-count"
>{{feedback.feedback_subject}}</span
>
</div>
</div>
<div class="oh-timeoff-modal__stats-container mt-3 mb-3">
<div class="oh-timeoff-modal__stat">
<span class="oh-timeoff-modal__stat-title"
>{% trans "Based on" %}</span
>
<span class="oh-timeoff-modal__stat-count">
{{feedback.get_based_on_display}}
</span>
</div>
{% if not feedback.based_on == "general" %}
<div class="oh-timeoff-modal__stat" style="margin-left: 20px">
{% if feedback.based_on == "employee" %}
<span class="oh-timeoff-modal__stat-title">{% trans "Employee" %}</span>
<span class="oh-timeoff-modal__stat-count">{{feedback.employee_id}}</span>
{% endif %}
{% if feedback.based_on == "department" %}
<span class="oh-timeoff-modal__stat-title">{% trans "Department" %}</span>
<span class="oh-timeoff-modal__stat-count">{{feedback.department_id}}</span>
{% endif %}
{% if feedback.based_on == "job_position" %}
<span class="oh-timeoff-modal__stat-title">{% trans "Job Position" %}</span>
<span class="oh-timeoff-modal__stat-count">{{feedback.job_position_id}}</span>
{% endif %}
</div>
{% endif %}
</div>
<div class="row">
<div class="oh-timeoff-modal__stat">
<span class="oh-timeoff-modal__stat-title">
{% trans "Description" %}
</span>
<span class="oh-timeoff-modal__stat-title" style="font-size:1.0rem;color:hsl(0deg 0% 0%);">{{feedback.feedback_description}}</span>
</div>
</div>
{% comment %} {% if perms.payroll.change_allowance or
perms.payroll.delete_allowance %}
<div class="oh-modal__button-container text-center">
<div class="oh-btn-group">
<a
href="{% url 'update-allowance' allowance.id %}"
class="oh-btn oh-btn--info"
style="width: 50%"
>
<ion-icon
name="create-outline"
role="img"
class="md hydrated"
aria-label="create outline"
></ion-icon
>{% trans "Edit" %}
</a>
<a
href="{% url 'delete-allowance' allowance.id %}"
onclick="event.preventDefault();event.stopPropagation(); confirm(`Do you want to delete this allowance?`)"
class="oh-btn oh-btn--danger"
style="width: 50%"
>
<ion-icon
name="trash-outline"
role="img"
class="md hydrated"
aria-label="create outline"
></ion-icon
>{% trans "Delete" %}
</a>
</div>
</div>
{% endif %} {% endcomment %}
</div>

View File

@@ -15,6 +15,13 @@
{% endfor %}
</ul>
{% endif %}
<style>
.oh-feedback-container {
display: flex;
align-items: center;
}
</style>
{% include 'filter_tags.html' %}
<div class="d-flex flex-row-reverse">
@@ -57,7 +64,15 @@
<span class="oh-badge oh-badge--secondary oh-badge--small oh-badge--round ms-2 mr-2" id="" data-category-id="1" title="{{all_feedbacks|length}} feedback" onclick="event.stopPropagation()">{{all_feedbacks|length}}</span>
</li>
{% endif %}
<li class="oh-tabs__tab" data-target="#tab_4">
{% trans "Anonymous Feedback" %}
<div class="oh-feedback-container">
<span class="oh-badge oh-badge--secondary oh-badge--small oh-badge--round ms-2 mr-2" id="" data-category-id="1" title="{{requested_feedback|length}}" onclick="event.stopPropagation()">{{requested_feedback|length}}</span>
<button class="oh-btn oh-btn--secondary-outline oh-stop-prop oh-accordion-meta__btn p-2" data-toggle="oh-modal-toggle" title="{% trans 'Add' %}" hx-get = {% url "add-anonymous-feedback" %} data-target="#anonymousFeedbackModal" hx-target="#anonymousFeedbackFormModal">
<ion-icon class="md hydrated" name="add-outline" role="img" aria-label="add outline"></ion-icon>
</button>
</div>
</li>
</ul>
<div >
<div class="oh-tabs__contents">
@@ -477,6 +492,95 @@
{% endif %}
</div>
<div class="oh-tabs__content" id="tab_4">
{% if anonymous_feedback %}
<div class="oh-sticky-table">
<div class="oh-sticky-table__table">
<div class="oh-sticky-table__thead">
<div class="oh-sticky-table__tr">
<div class="oh-sticky-table__th" style="width:10px;">
<div class="centered-div">
<input
type="checkbox"
class="requested-feedbacks oh-input oh-input__checkbox"
id = "requestedFeedback"
title='{% trans "Select All" %}'
/>
</div>
</div>
<div class="oh-sticky-table__th">{% trans "Subject" %}</div>
<div class="oh-sticky-table__th">{% trans "Based on" %}</div>
<div class="oh-sticky-table__th">{% trans "Create At" %}</div>
<div class="oh-sticky-table__th"></div>
</div>
</div>
<div class="oh-sticky-table__tbody">
{% for feedback in anonymous_feedback %}
<div class="oh-sticky-table__tr" draggable="true" data-toggle="oh-modal-toggle" data-target ="#FeedbackModal" hx-get="{% url 'single-anonymous-feedback-view' feedback.id %}" hx-target = "#OneFeedbackTarget">
<div class="oh-sticky-table__sd">
<div class="centered-div">
<input
type="checkbox"
id="{{feedback.id}}"
value="{{feedback.id}}"
class="oh-input feedback-checkbox oh-input__checkbox requested-feedback-row ms-2"
/>
</div>
</div>
<div class="oh-sticky-table__sd" >
{{feedback.feedback_subject}}
</div>
<div class="oh-sticky-table__sd">
{% trans "Based on" %} :
{% if feedback.based_on == "employee" %}
{{feedback.employee_id}}
{% elif feedback.based_on == "department" %}
{{feedback.department_id}}
{% elif feedback.based_on == "job_position" %}
{{feedback.job_position_id}}
{% else %}
{{feedback.get_based_on_display}}
{% endif %}
</div>
<div class="oh-sticky-table__sd">
{{feedback.created_at}}
</div>
<div class="oh-sticky-table__sd" onclick="event.stopPropagation();">
<div class="oh-btn-group">
<a class="oh-btn w-100" data-toggle="oh-modal-toggle" data-target="#anonymousFeedbackModal" hx-get="{% url 'edit-anonymous-feedback' feedback.id %}" title="{% trans 'Edit' %}" hx-target="#anonymousFeedbackFormModal"><ion-icon name="create-outline"></ion-icon></a>
<form action="{% url 'archive-anonymous-feedback' id=feedback.id %}" method="post" style="display: contents">
{% if feedback.archive == True %}
<button class="oh-btn oh-btn--danger-outline w-100 " title="{% trans 'Un-archive' %}" >
{% else %}
<button class="oh-btn oh-btn--danger-outline w-100 " title="{% trans 'Archive' %}" >
{% endif %}
{% csrf_token %}
<ion-icon name="archive-sharp" type="submit"></ion-icon>
</button>
</form>
{% if perms.pms.delete_feedback %}
<form action="{% url 'delete-anonymous-feedback' id=feedback.id %}" method="post" onsubmit="return confirm('{% trans "Do you want Delete this Feedback ?" %}')" style="display: contents">
{% csrf_token %}
<button class="oh-btn oh-btn--danger-outline w-100" title="{% trans 'Delete' %}" >
<ion-icon name="trash-outline" role="img" class="md hydrated" aria-label="trash outline"></ion-icon>
</button>
</form>
{% endif %}
</div>
</div>
</div>
{% endfor%}
</div>
</div>
</div>
{% else %}
<div class="d-flex justify-content-center align-items-center" style="height:60vh">
<h5 class="oh-404__subtitle">{% trans "There are no Anonymous Feedbacks available." %}</h5>
</div>
{% endif %}
</div>
</div>
</div>
</div>

View File

@@ -192,10 +192,38 @@
</section>
<div class="oh-wrapper" id="feedback_list">
{% include 'feedback/feedback_list.html' %}
</div>
<div
class="oh-modal"
id="anonymousFeedbackModal"
role="dialog"
aria-labelledby="anonymousFeedbackModal"
aria-hidden="true"
>
<div class="oh-modal__dialog">
<div class="oh-modal__dialog-header">
<h5 class="oh-modal__dialog-title" id="anonymousFeedbackModalLabel">
{% trans "Anonymous Feedback" %}
</h5>
<button class="oh-modal__close" aria-label="Close">
<ion-icon name="close-outline"></ion-icon>
</button>
</div>
<div class="oh-modal__dialog-body" id="anonymousFeedbackFormModal"></div>
</div>
</div>
<div
class="oh-modal"
id="FeedbackModal"
role="dialog"
aria-labelledby="FeedbackModal"
aria-hidden="true"
>
<div class="oh-modal__dialog">
<div class="oh-modal__dialog-body" id="OneFeedbackTarget"></div>
</div>
</div>
</main>
<script src="{% static 'src/feedback/action.js' %}"></script>

View File

@@ -208,4 +208,25 @@ urlpatterns = [
views.objective_select_filter,
name="objective-select-filter",
),
path(
"add-anonymous-feedback",
views.anonymous_feedback_add,
name="add-anonymous-feedback",
),
path(
"edit-anonymous-feedback/<int:id>/",
views.edit_anonymous_feedback,
name="edit-anonymous-feedback",
),
path("archive-anonymous-feedback/<int:id>/",views.archive_anonymous_feedback,name="archive-anonymous-feedback"),
path(
"delete-anonymous-feedback/<int:id>/",
views.delete_anonymous_feedback,
name="delete-anonymous-feedback",
),
path(
"single-anonymous-feedback-view/<int:id>/",
views.view_single_anonymous_feedback,
name="single-anonymous-feedback-view",
),
]

View File

@@ -7,6 +7,7 @@ from django.db.utils import IntegrityError
from django.db.models import Q
from django.forms import modelformset_factory
from django.contrib import messages
from django.contrib.auth.models import User
from django.core.paginator import Paginator
from django.utils.translation import gettext_lazy as _
from django.shortcuts import get_object_or_404, render, redirect
@@ -24,6 +25,7 @@ from pms.filters import (
)
from django.db.models import ProtectedError
from pms.models import (
AnonymousFeedback,
EmployeeKeyResult,
EmployeeObjective,
Comment,
@@ -36,6 +38,7 @@ from pms.models import (
KeyResultFeedback,
)
from .forms import (
AnonymousFeedbackForm,
QuestionForm,
ObjectiveForm,
KeyResultForm,
@@ -965,7 +968,7 @@ def feedback_update(request, id):
@login_required
def filter_pagination_feedback(
request, self_feedback, requested_feedback, all_feedback
request, self_feedback, requested_feedback, all_feedback, anonymous_feedback
):
"""
This view is used to filter or search the feedback object ,
@@ -990,7 +993,7 @@ def filter_pagination_feedback(
feedback_filter_all = FeedbackFilter(
request.GET or initial_data, queryset=all_feedback
)
anonymous_feedback = anonymous_feedback
feedback_paginator_own = Paginator(feedback_filter_own.qs, 50)
feedback_paginator_requested = Paginator(feedback_filter_requested.qs, 50)
feedback_paginator_all = Paginator(feedback_filter_all.qs, 50)
@@ -1006,6 +1009,7 @@ def filter_pagination_feedback(
"superuser": "true",
"self_feedback": feedbacks_own,
"requested_feedback": feedbacks_requested,
"anonymous_feedback": anonymous_feedback,
"all_feedbacks": feedbacks_all,
"feedback_filter_form": feedback_filter_own.form,
"pg": previous_data,
@@ -1047,11 +1051,16 @@ def feedback_list_search(request):
review_cycle__icontains=feedback
)
all_feedback = Feedback.objects.all().filter(review_cycle__icontains=feedback)
anonymous_feedback = (
AnonymousFeedback.objects.filter(employee_id=employee_id)
if not request.user.has_perm("pms.view_feedback")
else AnonymousFeedback.objects.all()
)
reporting_manager_to = employee_id.reporting_manager.all()
if request.user.has_perm("pms.view_feedback"):
context = filter_pagination_feedback(
request, self_feedback, requested_feedback, all_feedback
request, self_feedback, requested_feedback, all_feedback, anonymous_feedback
)
elif reporting_manager_to:
employees_id = [i.id for i in reporting_manager_to]
@@ -1059,12 +1068,12 @@ def feedback_list_search(request):
review_cycle__icontains=feedback
)
context = filter_pagination_feedback(
request, self_feedback, requested_feedback, all_feedback
request, self_feedback, requested_feedback, all_feedback, anonymous_feedback
)
else:
all_feedback = Feedback.objects.none()
context = filter_pagination_feedback(
request, self_feedback, requested_feedback, all_feedback
request, self_feedback, requested_feedback, all_feedback, anonymous_feedback
)
return render(request, "feedback/feedback_list.html", context)
@@ -1081,9 +1090,9 @@ def feedback_list_view(request):
user = request.user
employee = Employee.objects.filter(employee_user_id=user).first()
feedback_requested_ids = Feedback.objects.filter(
Q(manager_id=employee,manager_id__is_active=True)
| Q(colleague_id=employee,colleague_id__is_active=True)
| Q(subordinate_id=employee,subordinate_id__is_active=True)
Q(manager_id=employee, manager_id__is_active=True)
| Q(colleague_id=employee, colleague_id__is_active=True)
| Q(subordinate_id=employee, subordinate_id__is_active=True)
).values_list("id", flat=True)
feedback_own = Feedback.objects.filter(employee_id=employee).filter(
archive=False, employee_id__is_active=True
@@ -1094,24 +1103,32 @@ def feedback_list_view(request):
feedback_all = Feedback.objects.all().filter(
archive=False, employee_id__is_active=True
)
anonymous_feedback = (
AnonymousFeedback.objects.filter(employee_id=employee, archive=False)
if not request.user.has_perm("pms.view_feedback")
else AnonymousFeedback.objects.filter(archive=False)
)
anonymous_feedback = anonymous_feedback | AnonymousFeedback.objects.filter(
anonymous_feedback_id=request.user.id, archive=False
)
employees = Employee.objects.filter(
employee_work_info__reporting_manager_id=employee, is_active=True
) # checking the user is reporting manager or not
feedback_available = Feedback.objects.all()
if request.user.has_perm("pms.view_feedback"):
context = filter_pagination_feedback(
request, feedback_own, feedback_requested, feedback_all
request, feedback_own, feedback_requested, feedback_all, anonymous_feedback
)
elif employees:
# based on the reporting manager
feedback_all = Feedback.objects.filter(employee_id__in=employees)
context = filter_pagination_feedback(
request, feedback_own, feedback_requested, feedback_all
request, feedback_own, feedback_requested, feedback_all, anonymous_feedback
)
else:
feedback_all = Feedback.objects.none()
context = filter_pagination_feedback(
request, feedback_own, feedback_requested, feedback_all
request, feedback_own, feedback_requested, feedback_all, anonymous_feedback
)
if feedback_available.exists():
template = "feedback/feedback_list_view.html"
@@ -2072,9 +2089,7 @@ def objective_select(request):
page_number = request.GET.get("page")
table = request.GET.get("tableName")
user = request.user.employee_get
employees = EmployeeObjective.objects.filter(
employee_id=user, archive=False
)
employees = EmployeeObjective.objects.filter(employee_id=user, archive=False)
if page_number == "all":
if table == "all":
if request.user.has_perm("pms.view_employeeobjective"):
@@ -2114,13 +2129,14 @@ def objective_select_filter(request):
if table == "all":
if request.user.has_perm("pms.view_employeeobjective"):
employee_filter = ObjectiveFilter(
filters, queryset=EmployeeObjective.objects.all()
)
filters, queryset=EmployeeObjective.objects.all()
)
else:
employee_filter = ObjectiveFilter(
filters, queryset=EmployeeObjective.objects.filter(
filters,
queryset=EmployeeObjective.objects.filter(
employee_id__employee_work_info__reporting_manager_id__employee_user_id=request.user
)
),
)
else:
employee_filter = ObjectiveFilter(
@@ -2135,3 +2151,99 @@ def objective_select_filter(request):
context = {"employee_ids": employee_ids, "total_count": total_count}
return JsonResponse(context)
@login_required
def anonymous_feedback_add(request):
if request.method == "POST":
form = AnonymousFeedbackForm(request.POST)
anonymous_id = request.user.id
if form.is_valid():
feedback = form.save(commit=False)
feedback.anonymous_feedback_id = anonymous_id
feedback.save()
if feedback.based_on == "employee":
try:
notify.send(
User.objects.filter(username="Horilla Bot").first(),
recipient=feedback.employee_id.employee_user_id,
verb="You received an anonymous feedback!",
verb_ar="لقد تلقيت تقييمًا مجهولًا!",
verb_de="Sie haben anonymes Feedback erhalten!",
verb_es="¡Has recibido un comentario anónimo!",
verb_fr="Vous avez reçu un feedback anonyme!",
redirect="/pms/feedback-view/",
icon="bag-check",
)
except:
pass
return HttpResponse("<script>window.location.reload();</script>")
else:
form = AnonymousFeedbackForm()
context = {"form": form, "create": True}
return render(request, "anonymous/anonymous_feedback_form.html", context)
@login_required
def edit_anonymous_feedback(request, id):
feedback = AnonymousFeedback.objects.get(id=id)
form = AnonymousFeedbackForm(instance=feedback)
anonymous_id = request.user.id
if request.method == "POST":
form = AnonymousFeedbackForm(request.POST, instance=feedback)
if form.is_valid():
feedback = form.save(commit=False)
feedback.anonymous_feedback_id = anonymous_id
feedback.save()
return HttpResponse("<script>window.location.reload();</script>")
context = {"form": form, "create": False}
return render(request, "anonymous/anonymous_feedback_form.html", context)
@login_required
def archive_anonymous_feedback(request, id):
"""
this function is used to archive the feedback for employee
args:
id(int): primarykey of feedback
"""
feedback = AnonymousFeedback.objects.get(id=id)
if feedback.archive:
feedback.archive = False
feedback.save()
messages.info(request, _("Feedback un-archived successfully!."))
elif not feedback.archive:
feedback.archive = True
feedback.save()
messages.info(request, _("Feedback archived successfully!."))
return redirect(feedback_list_view)
@login_required
def delete_anonymous_feedback(request, id):
try:
feedback = AnonymousFeedback.objects.get(id=id)
feedback.delete()
messages.success(request, _("Feedback deleted successfully!"))
except IntegrityError:
messages.error(
request, _("Failed to delete feedback: Feedback template is in use.")
)
except AnonymousFeedback.DoesNotExist:
messages.error(request, _("Feedback not found."))
except ProtectedError:
messages.error(request, _("Related entries exists"))
return redirect(feedback_list_view)
@login_required
def view_single_anonymous_feedback(request, id):
feedback = AnonymousFeedback.objects.get(id=id)
return render(request, "anonymous/single_view.html", {"feedback": feedback})

View File

@@ -32,7 +32,7 @@
{% else %}
<p class="oh-navbar__notification-text" :class="markRead ? '' : 'oh-navbar__notification-text--unread' ">{{ notification.verb }}</p>
{% endif %}
<span class="oh-navbar__notification-date">{{ notification.timesince }} {% trans "ago by" %} {{ notification.actor.employee_first_name }}</span>
<span class="oh-navbar__notification-date">{{ notification.timesince }} {% trans "ago by" %} {% if notification.actor.employee_first_name %}{{ notification.actor.employee_first_name }}{% else %}{% trans "Anonymous" %}{% endif %}</span>
</div>
<div>
<div class="oh-navbar__notification-image">