[ADD] PMS: Anonymous feedback creation in 360 feedback
This commit is contained in:
@@ -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"),
|
||||
@@ -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"),
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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"]
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
|
||||
|
||||
|
||||
@@ -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"""
|
||||
|
||||
|
||||
72
pms/templates/anonymous/anonymous_feedback_form.html
Normal file
72
pms/templates/anonymous/anonymous_feedback_form.html
Normal 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>
|
||||
92
pms/templates/anonymous/single_view.html
Normal file
92
pms/templates/anonymous/single_view.html
Normal 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>
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
21
pms/urls.py
21
pms/urls.py
@@ -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",
|
||||
),
|
||||
]
|
||||
|
||||
148
pms/views.py
148
pms/views.py
@@ -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})
|
||||
|
||||
@@ -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">
|
||||
|
||||
Reference in New Issue
Block a user