diff --git a/pms/views.py b/pms/views.py
index f74988214..fcf4688c8 100644
--- a/pms/views.py
+++ b/pms/views.py
@@ -753,6 +753,14 @@ def objective_detailed_view(request, obj_id, **kwargs):
emp_objectives = EmployeeObjective.objects.filter(
objective_id=objective, archive=False
)
+ if not (
+ request.user.employee_get in objective.managers.all()
+ or request.user.has_perm("pms.view_employeeobjective")
+ or emp_objectives.filter(employee_id=request.user.employee_get).exists()
+ ):
+ messages.info(request, _("You dont have permission."))
+ return redirect("objective-list-view")
+
previous_data = request.GET.urlencode()
data_dict = parse_qs(previous_data)
now = datetime.datetime.now()
@@ -1241,6 +1249,8 @@ def change_employee_objective_status(request):
and (emp_objective.employee_id == request.user.employee_get)
)
):
+ messages.info(request, _("You dont have permission."))
+ else:
if emp_objective.status != status:
emp_objective.status = status
emp_objective.save()
@@ -1273,9 +1283,6 @@ def change_employee_objective_status(request):
messages.info(
request, _("The status of the objective is the same as selected.")
)
-
- else:
- messages.info(request, _("You dont have permission."))
return HttpResponse("")
@@ -1457,10 +1464,10 @@ def key_result_update(request, id):
# feedback section
-def send_feedback_notifications(request, form):
+def send_feedback_notifications(request, feedback):
# Send notification to employee
- if form.employee_id:
- employee = form.employee_id
+ if feedback.employee_id:
+ employee = feedback.employee_id
notify.send(
request.user.employee_get,
recipient=employee.employee_user_id,
@@ -1469,57 +1476,23 @@ def send_feedback_notifications(request, form):
verb_de="Sie haben Feedback erhalten!",
verb_es="¡Has recibido retroalimentación!",
verb_fr="Vous avez reçu des commentaires !",
- redirect=reverse("feedback-detailed-view", kwargs={"id": form.id}),
+ redirect=reverse("feedback-detailed-view", kwargs={"id": feedback.id}),
icon="chatbox-ellipses",
)
-
- # Send notification to manager
- if form.manager_id:
- manager = form.manager_id
+ all_employees = feedback.requested_employees()
+ for employee in all_employees:
notify.send(
request.user.employee_get,
- recipient=manager.employee_user_id,
- verb="You have been assigned as a manager in a feedback!",
- verb_ar="لقد تم تعيينك كمدير في ملاحظة!",
- verb_de="Sie wurden als Manager in einem Feedback zugewiesen!",
- verb_es="¡Has sido asignado como manager en un feedback!",
- verb_fr="Vous avez été désigné comme manager dans un commentaire !",
- redirect=reverse("feedback-detailed-view", kwargs={"id": form.id}),
+ recipient=employee.employee_user_id,
+ verb="You have been requested to provide feedback!",
+ verb_ar="لقد طُلب منك تقديم ملاحظات!",
+ verb_de="Sie wurden gebeten, Feedback zu geben!",
+ verb_es="Se le ha solicitado que proporcione comentarios.",
+ verb_fr="Il vous a été demandé de fournir des commentaires.",
+ redirect=reverse("feedback-detailed-view", kwargs={"id": feedback.id}),
icon="chatbox-ellipses",
)
- # Send notification to subordinates
- if form.subordinate_id:
- subordinates = form.subordinate_id.all()
- for subordinate in subordinates:
- notify.send(
- request.user.employee_get,
- recipient=subordinate.employee_user_id,
- verb="You have been assigned as a subordinate in a feedback!",
- verb_ar="لقد تم تعيينك كمرؤوس في ملاحظة!",
- verb_de="Sie wurden als Untergebener in einem Feedback zugewiesen!",
- verb_es="¡Has sido asignado como subordinado en un feedback!",
- verb_fr="Vous avez été désigné comme subordonné dans un commentaire !",
- redirect=reverse("feedback-detailed-view", kwargs={"id": form.id}),
- icon="chatbox-ellipses",
- )
-
- # Send notification to colleagues
- if form.colleague_id:
- colleagues = form.colleague_id.all()
- for colleague in colleagues:
- notify.send(
- request.user.employee_get,
- recipient=colleague.employee_user_id,
- verb="You have been assigned as a colleague in a feedback!",
- verb_ar="لقد تم تعيينك كزميل في ملاحظة!",
- verb_de="Sie wurden als Kollege in einem Feedback zugewiesen!",
- verb_es="¡Has sido asignado como colega en un feedback!",
- verb_fr="Vous avez été désigné comme collègue dans un commentaire !",
- redirect=reverse("feedback-detailed-view", kwargs={"id": form.id}),
- icon="chatbox-ellipses",
- )
-
@login_required
@manager_can_enter(perm="pms.add_feedback")
@@ -1630,15 +1603,15 @@ def feedback_update(request, id):
).first()
feedback_form = form.save()
feedback_form.employee_key_results_id.add(key_result)
- instance = form.save(commit=False)
+ instance = form.save()
instance.subordinate_id.set(employees)
other_employees = check_duplication(
form.instance, form.instance.others_id.all()
)
form.cleaned_data["others_id"] = other_employees
- form = form.save()
+ feedback = form.save()
messages.info(request, _("Feedback updated successfully!."))
- send_feedback_notifications(request, form)
+ send_feedback_notifications(request, feedback)
response = render(request, "feedback/feedback_update.html", context)
return HttpResponse(
response.content.decode("utf-8") + ""
@@ -3883,9 +3856,10 @@ def dashboard_feedback_answer(request):
).distinct()
feedbacks = feedback_requested.exclude(feedback_answer__employee_id=employee)
feedbacks = paginator_qry(feedbacks, page_number)
+
return render(
request,
- "request_and_approve/feedback_answer.html",
+ "dashboard/feedback_answer.html",
{
"feedbacks": feedbacks,
"pd": previous_data,
diff --git a/project/cbv/projects.py b/project/cbv/projects.py
index 526cba95d..1890fc552 100644
--- a/project/cbv/projects.py
+++ b/project/cbv/projects.py
@@ -88,6 +88,8 @@ class ProjectsNavView(HorillaNavView):
"attrs": """
id="archiveProject"
style="cursor: pointer;"
+ onclick="validateProjectIds(event);"
+ data-action="archive"
""",
},
{
@@ -95,6 +97,8 @@ class ProjectsNavView(HorillaNavView):
"attrs": """
id="unArchiveProject"
style="cursor: pointer;"
+ onclick="validateProjectIds(event);"
+ data-action="unarchive"
""",
},
{
@@ -103,6 +107,7 @@ class ProjectsNavView(HorillaNavView):
class="oh-dropdown__link--danger"
data-action ="delete"
id="deleteProject"
+ onclick="validateProjectIds(event);"
style="cursor: pointer; color:red !important"
""",
},
diff --git a/project/static/project/project_action.js b/project/static/project/project_action.js
index 5f31947fa..626a0adfa 100644
--- a/project/static/project/project_action.js
+++ b/project/static/project/project_action.js
@@ -1,631 +1,339 @@
-var archiveMessagesSelected = {
- // ar: "هل ترغب حقًا في أرشفة جميع الموظفين المحددين؟",
- // de: "Möchten Sie wirklich alle ausgewählten Mitarbeiter archivieren?",
- // es: "¿Realmente quieres archivar a todos los empleados seleccionados?",
- en: "Do you really want to archive all the selected projects?",
- // fr: "Voulez-vous vraiment archiver tous les employés sélectionnés ?",
- };
-
- var unarchiveMessagesSelected = {
- // ar: "هل ترغب حقًا في إلغاء أرشفة جميع الموظفين المحددين؟",
- // de: "Möchten Sie wirklich alle ausgewählten Mitarbeiter aus der Archivierung zurückholen?",
- // es: "¿Realmente quieres desarchivar a todos los empleados seleccionados?",
- en: "Do you really want to unarchive all the selected projects?",
- // fr: "Voulez-vous vraiment désarchiver tous les employés sélectionnés?",
- };
-
- var deleteMessage = {
- // ar: "هل ترغب حقًا في حذف جميع الموظفين المحددين؟",
- // de: "Möchten Sie wirklich alle ausgewählten Mitarbeiter löschen?",
- // es: "¿Realmente quieres eliminar a todos los empleados seleccionados?",
- en: "Do you really want to delete all the selected projects?",
- // fr: "Voulez-vous vraiment supprimer tous les employés sélectionnés?",
- };
-
- var exportMessages = {
+var exportMessages = {
// ar: "هل ترغب حقًا في حذف جميع الموظفين المحددين؟",
// de: "Möchten Sie wirklich alle ausgewählten Mitarbeiter löschen?",
// es: "¿Realmente quieres eliminar a todos los empleados seleccionados?",
en: "Do you really want to export all the selected projects?",
// fr: "Voulez-vous vraiment supprimer tous les employés sélectionnés?",
- };
+};
- var downloadMessages = {
+var downloadMessages = {
ar: "هل ترغب في تنزيل القالب؟",
de: "Möchten Sie die Vorlage herunterladen?",
es: "¿Quieres descargar la plantilla?",
en: "Do you want to download the template?",
fr: "Voulez-vous télécharger le modèle ?",
- };
+};
- var norowMessagesSelected = {
+var norowMessagesSelected = {
// ar: "لم يتم تحديد أي صفوف.",
// de: "Es wurden keine Zeilen ausgewählt.",
// es: "No se han seleccionado filas.",
en: "No rows have been selected.",
// fr: "Aucune ligne n'a été sélectionnée.",
- };
+};
- function getCookie(name) {
+function getCookie(name) {
let cookieValue = null;
if (document.cookie && document.cookie !== "") {
- const cookies = document.cookie.split(";");
- for (let i = 0; i < cookies.length; i++) {
- const cookie = cookies[i].trim();
- // Does this cookie string begin with the name we want?
- if (cookie.substring(0, name.length + 1) === name + "=") {
- cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
- break;
+ const cookies = document.cookie.split(";");
+ for (let i = 0; i < cookies.length; i++) {
+ const cookie = cookies[i].trim();
+ // Does this cookie string begin with the name we want?
+ if (cookie.substring(0, name.length + 1) === name + "=") {
+ cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
+ break;
+ }
}
- }
}
return cookieValue;
- }
+}
- function getCurrentLanguageCode(callback) {
+function getCurrentLanguageCode(callback) {
$.ajax({
- type: "GET",
- url: "/employee/get-language-code/",
- success: function (response) {
- var languageCode = response.language_code;
- callback(languageCode); // Pass the language code to the callback
- },
+ type: "GET",
+ url: "/employee/get-language-code/",
+ success: function (response) {
+ var languageCode = response.language_code;
+ callback(languageCode); // Pass the language code to the callback
+ },
});
- }
+}
+function validateProjectIds(event) {
+ getCurrentLanguageCode(function (code) {
+ languageCode = code;
+ var textMessage = norowMessagesSelected[languageCode];
+ var takeAction = $(event.currentTarget).data("action");
- // // Get the form element
- // var form = document.getElementById("projectImportForm");
+ var idsRaw = $("#selectedInstances").attr("data-ids");
+ if (!idsRaw) {
+ Swal.fire({
+ text: textMessage,
+ icon: "warning",
+ confirmButtonText: "Close",
+ });
+ return;
+ }
- // // Add an event listener to the form submission
- // form.addEventListener("submit", function (event) {
- // // Prevent the default form submission
- // event.preventDefault();
+ var ids = JSON.parse(idsRaw);
+ if (ids.length === 0) {
+ Swal.fire({
+ text: textMessage,
+ icon: "warning",
+ confirmButtonText: "Close",
+ });
+ return;
+ }
- // // Create a new form data object
- // var formData = new FormData();
+ let triggerId;
+ if (takeAction === "archive") {
+ triggerId = "#bulkArchiveProject";
+ } else if (takeAction === "unarchive") {
+ triggerId = "#bulkUnArchiveProject";
+ } else if (takeAction === "delete") {
+ triggerId = "#bulkDeleteProject";
+ } else {
+ console.warn("Unsupported action:", takeAction);
+ return;
+ }
- // // Append the file to the form data object
- // var fileInput = document.querySelector("#projectImportFile");
- // formData.append("file", fileInput.files[0]);
- // $.ajax({
- // type: "POST",
- // url: "/project/project-import",
- // dataType: "binary",
- // data: formData,
- // processData: false,
- // contentType: false,
- // headers: {
- // "X-CSRFToken": getCookie('csrftoken'), // Replace with your csrf token value
- // },
- // xhrFields: {
- // responseType: "blob",
- // },
- // success: function (response) {
- // const file = new Blob([response], {
- // type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
- // });
- // const url = URL.createObjectURL(file);
- // const link = document.createElement("a");
- // link.href = url;
- // link.download = "ImportError.xlsx";
- // document.body.appendChild(link);
- // link.click();
- // },
- // error: function (xhr, textStatus, errorThrown) {
- // console.error("Error downloading file:", errorThrown);
- // },
- // });
- // });
+ const $triggerElement = $(triggerId);
+ if ($triggerElement.length) {
+ $triggerElement.attr("hx-vals", JSON.stringify({ ids })).click();
+ } else {
+ console.warn("Trigger element not found for:", triggerId);
+ }
+ });
+}
- // $("#importProject").click(function (e) {
- // e.preventDefault();
- // var languageCode = null;
- // getCurrentLanguageCode(function (code) {
- // languageCode = code;
- // var confirmMessage = downloadMessages[languageCode];
- // // Use SweetAlert for the confirmation dialog
- // Swal.fire({
- // text: confirmMessage,
- // icon: 'question',
- // showCancelButton: true,
- // confirmButtonColor: '#008000',
- // cancelButtonColor: '#d33',
- // confirmButtonText: 'Confirm'
- // }).then(function(result) {
- // if (result.isConfirmed) {
- // $.ajax({
- // type: "GET",
- // url: "/project/project-import",
- // dataType: "binary",
- // xhrFields: {
- // responseType: "blob",
- // },
- // success: function (response) {
- // const file = new Blob([response], {
- // type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
- // });
- // const url = URL.createObjectURL(file);
- // const link = document.createElement("a");
- // link.href = url;
- // link.download = "project_template.xlsx";
- // document.body.appendChild(link);
- // link.click();
- // },
- // error: function (xhr, textStatus, errorThrown) {
- // console.error("Error downloading file:", errorThrown);
- // },
- // });
- // }
- // });
- // });
- // });
-
- // $('#importProject').click(function (e) {
- // $.ajax({
- // type: 'POST',
- // url: '/project/project-import',
- // dataType: 'binary',
- // xhrFields: {
- // responseType: 'blob'
- // },
- // success: function(response) {
- // const file = new Blob([response], {type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'});
- // const url = URL.createObjectURL(file);
- // const link = document.createElement('a');
- // link.href = url;
- // link.download = 'project.xlsx';
- // document.body.appendChild(link);
- // link.click();
- // },
- // error: function(xhr, textStatus, errorThrown) {
- // console.error('Error downloading file:', errorThrown);
- // }
- // });
- // });
-
-
- $(".all-projects").change(function (e) {
+$(".all-projects").change(function (e) {
var is_checked = $(this).is(":checked");
if (is_checked) {
- $(".all-project-row").prop("checked", true);
+ $(".all-project-row").prop("checked", true);
} else {
- $(".all-project-row").prop("checked", false);
+ $(".all-project-row").prop("checked", false);
}
- });
+});
- $("#exportProject").click(function (e) {
+$("#exportProject").click(function (e) {
e.preventDefault();
var languageCode = null;
getCurrentLanguageCode(function (code) {
- languageCode = code;
- var confirmMessage = exportMessages[languageCode];
- var textMessage = norowMessagesSelected[languageCode];
- var checkedRows = $(".all-project-row").filter(":checked");
- if (checkedRows.length === 0) {
- Swal.fire({
- text: textMessage,
- icon: "warning",
- confirmButtonText: "Close",
- });
- } else {
- Swal.fire({
- text: confirmMessage,
- icon: "info",
- showCancelButton: true,
- confirmButtonColor: "#008000",
- cancelButtonColor: "#d33",
- confirmButtonText: "Confirm",
- }).then(function (result) {
- if (result.isConfirmed) {
- var checkedRows = $(".all-project-row").filter(":checked");
- ids = [];
- checkedRows.each(function () {
- ids.push($(this).attr("id"));
+ languageCode = code;
+ var confirmMessage = exportMessages[languageCode];
+ var textMessage = norowMessagesSelected[languageCode];
+ var checkedRows = $(".all-project-row").filter(":checked");
+ if (checkedRows.length === 0) {
+ Swal.fire({
+ text: textMessage,
+ icon: "warning",
+ confirmButtonText: "Close",
});
+ } else {
+ Swal.fire({
+ text: confirmMessage,
+ icon: "info",
+ showCancelButton: true,
+ confirmButtonColor: "#008000",
+ cancelButtonColor: "#d33",
+ confirmButtonText: "Confirm",
+ }).then(function (result) {
+ if (result.isConfirmed) {
+ var checkedRows = $(".all-project-row").filter(":checked");
+ ids = [];
+ checkedRows.each(function () {
+ ids.push($(this).attr("id"));
+ });
- $.ajax({
- type: "POST",
- url: "/project/project-bulk-export",
- dataType: "binary",
- xhrFields: {
- responseType: "blob",
- },
- data: {
- csrfmiddlewaretoken: getCookie("csrftoken"),
- ids: JSON.stringify(ids),
- },
- success: function (response, textStatus, jqXHR) {
- const file = new Blob([response], {
- type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
- });
- const url = URL.createObjectURL(file);
- const link = document.createElement("a");
- link.href = url;
- link.download = "project details.xlsx";
- document.body.appendChild(link);
- link.click();
- },
- });
- }
- });
- }
- });
- });
-
- $(document).on('click', '#exportProject', function (e) {
- e.preventDefault();
- var languageCode = null;
- getCurrentLanguageCode(function (code) {
- languageCode = code;
- var confirmMessage = exportMessages[languageCode];
- var textMessage = norowMessagesSelected[languageCode];
- ids = [];
- ids.push($("#selectedInstances").attr("data-ids"));
- ids = JSON.parse($("#selectedInstances").attr("data-ids"));
- if (ids.length === 0) {
- Swal.fire({
- text: textMessage,
- icon: "warning",
- confirmButtonText: "Close",
- });
- } else {
- Swal.fire({
- text: confirmMessage,
- icon: "info",
- showCancelButton: true,
- confirmButtonColor: "#008000",
- cancelButtonColor: "#d33",
- confirmButtonText: "Confirm",
- }).then(function (result) {
- if (result.isConfirmed) {
- // var checkedRows = $(".all-project-row").filter(":checked");
- // ids = [];
- // checkedRows.each(function () {
- // ids.push($(this).attr("id"));
- // });
-
- $.ajax({
- type: "POST",
- url: "/project/project-bulk-export",
- dataType: "binary",
- xhrFields: {
- responseType: "blob",
- },
- data: {
- csrfmiddlewaretoken: getCookie("csrftoken"),
- ids: JSON.stringify(ids),
- },
- success: function (response, textStatus, jqXHR) {
- const file = new Blob([response], {
- type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
- });
- const url = URL.createObjectURL(file);
- const link = document.createElement("a");
- link.href = url;
- link.download = "project details.xlsx";
- document.body.appendChild(link);
- link.click();
- },
- });
- }
- });
- }
- });
- });
-
-
- $("#archiveProject").click(function (e) {
- e.preventDefault();
- var languageCode = null;
- getCurrentLanguageCode(function (code) {
- languageCode = code;
- var confirmMessage = archiveMessagesSelected[languageCode];
- var textMessage = norowMessagesSelected[languageCode];
- var checkedRows = $(".all-project-row").filter(":checked");
- if (checkedRows.length === 0) {
- Swal.fire({
- text: textMessage,
- icon: "warning",
- confirmButtonText: "Close",
- });
- } else {
- Swal.fire({
- text: confirmMessage,
- icon: "info",
- showCancelButton: true,
- confirmButtonColor: "#008000",
- cancelButtonColor: "#d33",
- confirmButtonText: "Confirm",
- }).then(function (result) {
- if (result.isConfirmed) {
- e.preventDefault();
- ids = [];
- checkedRows.each(function () {
- ids.push($(this).attr("id"));
- });
-
- $.ajax({
- type: "POST",
- url: "/project/project-bulk-archive?is_active=False",
- data: {
- csrfmiddlewaretoken: getCookie("csrftoken"),
- ids: JSON.stringify(ids),
- },
- success: function (response, textStatus, jqXHR) {
- if (jqXHR.status === 200) {
- location.reload(); // Reload the current page
- } else {
- // console.log("Unexpected HTTP status:", jqXHR.status);
+ $.ajax({
+ type: "POST",
+ url: "/project/project-bulk-export",
+ dataType: "binary",
+ xhrFields: {
+ responseType: "blob",
+ },
+ data: {
+ csrfmiddlewaretoken: getCookie("csrftoken"),
+ ids: JSON.stringify(ids),
+ },
+ success: function (response, textStatus, jqXHR) {
+ const file = new Blob([response], {
+ type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
+ });
+ const url = URL.createObjectURL(file);
+ const link = document.createElement("a");
+ link.href = url;
+ link.download = "project details.xlsx";
+ document.body.appendChild(link);
+ link.click();
+ },
+ });
}
- },
});
- }
- });
- }
+ }
});
- });
+});
-
- $(document).on('click', '#archiveProject', function (e) {
+$(document).on('click', '#exportProject', function (e) {
e.preventDefault();
var languageCode = null;
getCurrentLanguageCode(function (code) {
- languageCode = code;
- var confirmMessage = archiveMessagesSelected[languageCode];
- var textMessage = norowMessagesSelected[languageCode];
- ids = [];
- ids.push($("#selectedInstances").attr("data-ids"));
- ids = JSON.parse($("#selectedInstances").attr("data-ids"));
- if (ids.length === 0) {
- Swal.fire({
- text: textMessage,
- icon: "warning",
- confirmButtonText: "Close",
- });
- } else {
- Swal.fire({
- text: confirmMessage,
- icon: "info",
- showCancelButton: true,
- confirmButtonColor: "#008000",
- cancelButtonColor: "#d33",
- confirmButtonText: "Confirm",
- }).then(function (result) {
- if (result.isConfirmed) {
- // e.preventDefault();
- // ids = [];
- // checkedRows.each(function () {
- // ids.push($(this).attr("id"));
- // });
+ languageCode = code;
+ var confirmMessage = exportMessages[languageCode];
+ var textMessage = norowMessagesSelected[languageCode];
+ ids = [];
+ ids.push($("#selectedInstances").attr("data-ids"));
+ ids = JSON.parse($("#selectedInstances").attr("data-ids"));
+ if (ids.length === 0) {
+ Swal.fire({
+ text: textMessage,
+ icon: "warning",
+ confirmButtonText: "Close",
+ });
+ } else {
+ Swal.fire({
+ text: confirmMessage,
+ icon: "info",
+ showCancelButton: true,
+ confirmButtonColor: "#008000",
+ cancelButtonColor: "#d33",
+ confirmButtonText: "Confirm",
+ }).then(function (result) {
+ if (result.isConfirmed) {
+ // var checkedRows = $(".all-project-row").filter(":checked");
+ // ids = [];
+ // checkedRows.each(function () {
+ // ids.push($(this).attr("id"));
+ // });
- $.ajax({
- type: "POST",
- url: "/project/project-bulk-archive?is_active=False",
- data: {
- csrfmiddlewaretoken: getCookie("csrftoken"),
- ids: JSON.stringify(ids),
- },
- success: function (response, textStatus, jqXHR) {
- if (jqXHR.status === 200) {
- location.reload(); // Reload the current page
- } else {
- // console.log("Unexpected HTTP status:", jqXHR.status);
+ $.ajax({
+ type: "POST",
+ url: "/project/project-bulk-export",
+ dataType: "binary",
+ xhrFields: {
+ responseType: "blob",
+ },
+ data: {
+ csrfmiddlewaretoken: getCookie("csrftoken"),
+ ids: JSON.stringify(ids),
+ },
+ success: function (response, textStatus, jqXHR) {
+ const file = new Blob([response], {
+ type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
+ });
+ const url = URL.createObjectURL(file);
+ const link = document.createElement("a");
+ link.href = url;
+ link.download = "project details.xlsx";
+ document.body.appendChild(link);
+ link.click();
+ },
+ });
}
- },
});
- }
- });
- }
+ }
});
- });
+});
-$("#unArchiveProject").click(function (e) {
- e.preventDefault();
- var languageCode = null;
- getCurrentLanguageCode(function (code) {
- languageCode = code;
- var confirmMessage = unarchiveMessagesSelected[languageCode];
- var textMessage = norowMessagesSelected[languageCode];
- var checkedRows = $(".all-project-row").filter(":checked");
- if (checkedRows.length === 0) {
- Swal.fire({
- text: textMessage,
- icon: "warning",
- confirmButtonText: "Close",
- });
- } else {
- Swal.fire({
- text: confirmMessage,
- icon: "info",
- showCancelButton: true,
- confirmButtonColor: "#008000",
- cancelButtonColor: "#d33",
- confirmButtonText: "Confirm",
- }).then(function (result) {
- if (result.isConfirmed) {
- var checkedRows = $(".all-project-row").filter(":checked");
- ids = [];
- checkedRows.each(function () {
- ids.push($(this).attr("id"));
- });
-
- $.ajax({
- type: "POST",
- url: "/project/project-bulk-archive?is_active=True",
- data: {
- csrfmiddlewaretoken: getCookie("csrftoken"),
- ids: JSON.stringify(ids),
- },
- success: function (response, textStatus, jqXHR) {
- if (jqXHR.status === 200) {
- location.reload(); // Reload the current page
- } else {
- // console.log("Unexpected HTTP status:", jqXHR.status);
- }
- },
- });
- }
- });
- }
- });
- });
-
- $(document).on('click', '#unArchiveProject', function (e) {
- e.preventDefault();
- var languageCode = null;
- getCurrentLanguageCode(function (code) {
- languageCode = code;
- var confirmMessage = unarchiveMessagesSelected[languageCode];
- var textMessage = norowMessagesSelected[languageCode];
- ids = [];
- ids.push($("#selectedInstances").attr("data-ids"));
- ids = JSON.parse($("#selectedInstances").attr("data-ids"));
- if (ids.length === 0) {
- Swal.fire({
- text: textMessage,
- icon: "warning",
- confirmButtonText: "Close",
- });
- } else {
- Swal.fire({
- text: confirmMessage,
- icon: "info",
- showCancelButton: true,
- confirmButtonColor: "#008000",
- cancelButtonColor: "#d33",
- confirmButtonText: "Confirm",
- }).then(function (result) {
- if (result.isConfirmed) {
- // var checkedRows = $(".all-project-row").filter(":checked");
- // ids = [];
- // checkedRows.each(function () {
- // ids.push($(this).attr("id"));
- // });
-
- $.ajax({
- type: "POST",
- url: "/project/project-bulk-archive?is_active=True",
- data: {
- csrfmiddlewaretoken: getCookie("csrftoken"),
- ids: JSON.stringify(ids),
- },
- success: function (response, textStatus, jqXHR) {
- if (jqXHR.status === 200) {
- location.reload(); // Reload the current page
- } else {
- // console.log("Unexpected HTTP status:", jqXHR.status);
- }
- },
- });
- }
- });
- }
- });
- });
-
-$("#deleteProject").click(function (e) {
- e.preventDefault();
- var languageCode = null;
- getCurrentLanguageCode(function (code) {
- languageCode = code;
- var confirmMessage = deleteMessage[languageCode];
- var textMessage = norowMessagesSelected[languageCode];
- var checkedRows = $(".all-project-row").filter(":checked");
- if (checkedRows.length === 0) {
- Swal.fire({
- text: textMessage,
- icon: "warning",
- confirmButtonText: "Close",
- });
- } else {
- Swal.fire({
- text: confirmMessage,
- icon: "error",
- showCancelButton: true,
- confirmButtonColor: "#008000",
- cancelButtonColor: "#d33",
- confirmButtonText: "Confirm",
- }).then(function (result) {
- if (result.isConfirmed) {
- var checkedRows = $(".all-project-row").filter(":checked");
- ids = [];
- checkedRows.each(function () {
- ids.push($(this).attr("id"));
- });
-
- $.ajax({
- type: "POST",
- url: "/project/project-bulk-delete",
- data: {
- csrfmiddlewaretoken: getCookie("csrftoken"),
- ids: JSON.stringify(ids),
- },
- success: function (response, textStatus, jqXHR) {
- if (jqXHR.status === 200) {
- location.reload(); // Reload the current page
- } else {
- // console.log("Unexpected HTTP status:", jqXHR.status);
- }
- },
- });
- }
- });
- }
- });
- });
- $(document).on('click', '#deleteProject', function (e) {
- e.preventDefault();
- var languageCode = null;
- getCurrentLanguageCode(function (code) {
- languageCode = code;
- var confirmMessage = deleteMessage[languageCode];
- var textMessage = norowMessagesSelected[languageCode];
- ids = [];
- ids.push($("#selectedInstances").attr("data-ids"));
- ids = JSON.parse($("#selectedInstances").attr("data-ids"));
- if (ids.length === 0) {
- Swal.fire({
- text: textMessage,
- icon: "warning",
- confirmButtonText: "Close",
- });
- } else {
- Swal.fire({
- text: confirmMessage,
- icon: "error",
- showCancelButton: true,
- confirmButtonColor: "#008000",
- cancelButtonColor: "#d33",
- confirmButtonText: "Confirm",
- }).then(function (result) {
- if (result.isConfirmed) {
- // var checkedRows = $(".all-project-row").filter(":checked");
- // ids = [];
- // checkedRows.each(function () {
- // ids.push($(this).attr("id"));
- // });
+// // Get the form element
+// var form = document.getElementById("projectImportForm");
- $.ajax({
- type: "POST",
- url: "/project/project-bulk-delete",
- data: {
- csrfmiddlewaretoken: getCookie("csrftoken"),
- ids: JSON.stringify(ids),
- },
- success: function (response, textStatus, jqXHR) {
- if (jqXHR.status === 200) {
- location.reload(); // Reload the current page
- } else {
- // console.log("Unexpected HTTP status:", jqXHR.status);
- }
- },
- });
- }
- });
- }
- });
- });
+// // Add an event listener to the form submission
+// form.addEventListener("submit", function (event) {
+// // Prevent the default form submission
+// event.preventDefault();
+
+// // Create a new form data object
+// var formData = new FormData();
+
+// // Append the file to the form data object
+// var fileInput = document.querySelector("#projectImportFile");
+// formData.append("file", fileInput.files[0]);
+// $.ajax({
+// type: "POST",
+// url: "/project/project-import",
+// dataType: "binary",
+// data: formData,
+// processData: false,
+// contentType: false,
+// headers: {
+// "X-CSRFToken": getCookie('csrftoken'), // Replace with your csrf token value
+// },
+// xhrFields: {
+// responseType: "blob",
+// },
+// success: function (response) {
+// const file = new Blob([response], {
+// type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
+// });
+// const url = URL.createObjectURL(file);
+// const link = document.createElement("a");
+// link.href = url;
+// link.download = "ImportError.xlsx";
+// document.body.appendChild(link);
+// link.click();
+// },
+// error: function (xhr, textStatus, errorThrown) {
+// console.error("Error downloading file:", errorThrown);
+// },
+// });
+// });
+
+// $("#importProject").click(function (e) {
+// e.preventDefault();
+// var languageCode = null;
+// getCurrentLanguageCode(function (code) {
+// languageCode = code;
+// var confirmMessage = downloadMessages[languageCode];
+// // Use SweetAlert for the confirmation dialog
+// Swal.fire({
+// text: confirmMessage,
+// icon: 'question',
+// showCancelButton: true,
+// confirmButtonColor: '#008000',
+// cancelButtonColor: '#d33',
+// confirmButtonText: 'Confirm'
+// }).then(function(result) {
+// if (result.isConfirmed) {
+// $.ajax({
+// type: "GET",
+// url: "/project/project-import",
+// dataType: "binary",
+// xhrFields: {
+// responseType: "blob",
+// },
+// success: function (response) {
+// const file = new Blob([response], {
+// type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
+// });
+// const url = URL.createObjectURL(file);
+// const link = document.createElement("a");
+// link.href = url;
+// link.download = "project_template.xlsx";
+// document.body.appendChild(link);
+// link.click();
+// },
+// error: function (xhr, textStatus, errorThrown) {
+// console.error("Error downloading file:", errorThrown);
+// },
+// });
+// }
+// });
+// });
+// });
+
+// $('#importProject').click(function (e) {
+// $.ajax({
+// type: 'POST',
+// url: '/project/project-import',
+// dataType: 'binary',
+// xhrFields: {
+// responseType: 'blob'
+// },
+// success: function(response) {
+// const file = new Blob([response], {type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'});
+// const url = URL.createObjectURL(file);
+// const link = document.createElement('a');
+// link.href = url;
+// link.download = 'project.xlsx';
+// document.body.appendChild(link);
+// link.click();
+// },
+// error: function(xhr, textStatus, errorThrown) {
+// console.error('Error downloading file:', errorThrown);
+// }
+// });
+// });
diff --git a/project/templates/cbv/projects/project_nav.html b/project/templates/cbv/projects/project_nav.html
index c893659f4..347f79915 100644
--- a/project/templates/cbv/projects/project_nav.html
+++ b/project/templates/cbv/projects/project_nav.html
@@ -1,9 +1,18 @@
{% load i18n %}
{% include "generic/horilla_nav.html" %}
+
+
+
+
+
+
diff --git a/project/views.py b/project/views.py
index 10496b681..4924169c2 100644
--- a/project/views.py
+++ b/project/views.py
@@ -527,7 +527,7 @@ def project_import(request):
@login_required
-# @permission_required("employee.delete_employee")
+# @permission_required("project.view_project")
# @require_http_methods(["POST"])
def project_bulk_export(request):
"""
@@ -618,48 +618,84 @@ def project_bulk_export(request):
@login_required
-# @project_delete_permission
def project_bulk_archive(request):
- """
- This method is used to archive bulk of Project instances
- """
- ids = request.POST["ids"]
- ids = json.loads(ids)
+ try:
+ ids = request.POST.getlist("ids")
+ except Exception:
+ messages.error(request, _("Could not retrieve project IDs."))
+ return HttpResponse("")
+
+ is_active_raw = request.GET.get("is_active", "").lower()
+
+ if is_active_raw in ["true"]:
+ is_active = True
+ message = "Un-Archived"
+ elif is_active_raw in ["false"]:
+ is_active = False
+ message = "Archived"
+ else:
+ messages.error(
+ request, _("Invalid value for 'is_active'. Use 'true' or 'false'.")
+ )
+ return HttpResponse("")
+
for project_id in ids:
project = Project.objects.filter(id=project_id).first()
if project and is_project_manager_or_super_user(request, project):
- is_active = eval(request.GET.get("is_active"))
- message = "Archived"
- if is_active:
- message = "Un-Archived"
project.is_active = is_active
project.save()
messages.success(request, f"{project} is {message} successfully.")
- return JsonResponse({"message": "Success"})
+ else:
+ messages.warning(
+ request, f"Permission denied or project not found: ID {project_id}"
+ )
+
+ return HttpResponse("")
@login_required
-# @permission_required("employee.delete_employee")
+# @permission_required("project.delete_project")
def project_bulk_delete(request):
"""
- This method is used to delete set of Employee instances
+ This method deletes a set of Project instances in bulk, after verifying permissions.
"""
- ids = request.POST["ids"]
- ids = json.loads(ids)
- del_id = []
- for project_id in ids:
- project = Project.objects.get(id=project_id)
- try:
- if is_project_manager_or_super_user(request, project):
- project.delete()
- del_id.append(project)
- except Exception as error:
- messages.error(request, error)
- messages.error(
- request, _("You cannot delete %(project)s.") % {"project": project}
- )
- messages.success(request, _("{} Projects deleted".format(len(del_id))))
- return JsonResponse({"message": "Success"})
+ try:
+ ids = request.POST.getlist("ids")
+ if not ids:
+ messages.warning(request, _("No project IDs were provided."))
+ return HttpResponse("")
+ except Exception:
+ messages.error(request, _("Could not retrieve project IDs."))
+ return HttpResponse("")
+
+ projects = Project.objects.filter(id__in=ids)
+ deletable_projects = []
+ skipped_projects = []
+
+ for project in projects:
+ if is_project_manager_or_super_user(request, project):
+ deletable_projects.append(project)
+ else:
+ skipped_projects.append(str(project))
+
+ # Delete in bulk
+ if deletable_projects:
+ # Project.objects.filter(id__in=[p.id for p in deletable_projects]).delete()
+ messages.success(
+ request,
+ _("{count} project(s) deleted successfully.").format(
+ count=len(deletable_projects)
+ ),
+ )
+
+ if skipped_projects:
+ messages.warning(
+ request,
+ _("Permission denied or skipped for: %(projects)s.")
+ % {"projects": ", ".join(skipped_projects)},
+ )
+
+ return HttpResponse("")
@login_required
@@ -1166,7 +1202,7 @@ def task_all_filter(request):
@login_required
-# @permission_required("employee.delete_employee")
+# @permission_required("project.change_task")
# @require_http_methods(["POST"])
def task_all_bulk_archive(request):
"""
@@ -1189,7 +1225,7 @@ def task_all_bulk_archive(request):
@login_required
-# @permission_required("employee.delete_employee")
+# @permission_required("project.delete_task")
def task_all_bulk_delete(request):
"""
This method is used to delete set of Task instances
@@ -1210,7 +1246,7 @@ def task_all_bulk_delete(request):
@login_required
-# @permission_required("employee.delete_employee")
+# @permission_required("project.change_task")
def task_all_archive(request, task_id):
"""
This method is used to archive project instance
diff --git a/recruitment/models.py b/recruitment/models.py
index 6febe3598..2f6d37ef3 100644
--- a/recruitment/models.py
+++ b/recruitment/models.py
@@ -1089,11 +1089,8 @@ class Candidate(HorillaModel):
)
def save(self, *args, **kwargs):
- # Check if the 'stage_id' attribute is not None
if self.stage_id is not None:
- # Check if the stage type is 'hired'
- if self.stage_id.stage_type == "hired":
- self.hired = True
+ self.hired = self.stage_id.stage_type == "hired"
if not self.recruitment_id.is_event_based and self.job_position_id is None:
self.job_position_id = self.recruitment_id.job_position_id
diff --git a/recruitment/views/surveys.py b/recruitment/views/surveys.py
index 70ec61180..0503fa0ce 100644
--- a/recruitment/views/surveys.py
+++ b/recruitment/views/surveys.py
@@ -108,6 +108,8 @@ def question_order_update(request):
return JsonResponse({"error": "Invalid request method"}, status=405)
+@login_required
+@is_recruitment_manager(perm="recruitment.view_recruitmentsurvey")
def candidate_survey(request):
"""
Used to render survey form to the candidate
diff --git a/recruitment/views/views.py b/recruitment/views/views.py
index 0820f7f51..1bd6de025 100644
--- a/recruitment/views/views.py
+++ b/recruitment/views/views.py
@@ -590,11 +590,15 @@ def update_candidate_sequence(request):
.first()
)
data = {}
+
for index, cand_id in enumerate(order_list):
candidate = CACHE.get(request.session.session_key + "pipeline")[
"candidates"
].filter(id=cand_id)
- candidate.update(sequence=index, stage_id=stage)
+ candidate.update(
+ sequence=index, stage_id=stage, hired=(stage.stage_type == "hired")
+ )
+
return JsonResponse(data)
@@ -671,7 +675,7 @@ def change_candidate_stage(request):
if stage.recruitment_id.is_vacancy_filled():
context["message"] = _("Vaccancy is filled")
context["vacancy"] = stage.recruitment_id.vacancy
- messages.success(request, "Candidate stage updated")
+ messages.success(request, _("Candidate stage updated"))
except Candidate.DoesNotExist:
messages.error(request, _("Candidate not found."))
else:
@@ -689,7 +693,7 @@ def change_candidate_stage(request):
context["vacancy"] = stage.recruitment_id.vacancy
candidate.stage_id = stage
candidate.save()
- messages.success(request, "Candidate stage updated")
+ messages.success(request, _("Candidate stage updated"))
except Candidate.DoesNotExist:
messages.error(request, _("Candidate not found."))
return JsonResponse(context)
@@ -702,7 +706,7 @@ def change_candidate_stage(request):
if stage:
candidate.stage_id = stage
candidate.save()
- messages.success(request, "Candidate stage updated")
+ messages.success(request, _("Candidate stage updated"))
return stage_component(request)
diff --git a/report/templates/report/recruitment_report.html b/report/templates/report/recruitment_report.html
index f37dde34f..e74212e29 100644
--- a/report/templates/report/recruitment_report.html
+++ b/report/templates/report/recruitment_report.html
@@ -60,7 +60,7 @@
{{ f.form.job_position_id }}
-
+
-
+
-
+
-
+