diff --git a/attendance/forms.py b/attendance/forms.py index b960447f3..d7f3e363d 100644 --- a/attendance/forms.py +++ b/attendance/forms.py @@ -568,6 +568,7 @@ class NewRequestForm(AttendanceRequestForm): excluded_fields = [ "id", + "attendance_id__employee_id", "requested_data", "at_work_second", "approved_overtime_second", @@ -615,7 +616,7 @@ class LateComeEarlyOutExportForm(forms.Form): ] model_fields_2 = Attendance._meta.get_fields() field_choices_2 = [ - (field.name, field.verbose_name) + ("attendance_id__" + field.name, field.verbose_name) for field in model_fields_2 if hasattr(field, "verbose_name") and field.name not in excluded_fields ] @@ -627,7 +628,11 @@ class LateComeEarlyOutExportForm(forms.Form): initial=[ "employee_id", "type", - "is_active", + "attendance_id__attendance_date", + "attendance_id__attendance_clock_in_date", + "attendance_id__attendance_clock_in", + "attendance_id__attendance_clock_out_date", + "attendance_id__attendance_clock_out", ], ) diff --git a/attendance/static/attendance/actions.js b/attendance/static/attendance/actions.js index 68d59a1d4..e17135e34 100644 --- a/attendance/static/attendance/actions.js +++ b/attendance/static/attendance/actions.js @@ -402,6 +402,40 @@ function addingActivityIds() { }); } +function addinglatecomeIds() { + var ids = JSON.parse($("#selectedLatecome").attr("data-ids") || "[]"); + var selectedCount = 0; + + $(".all-latecome-row").each(function () { + if ($(this).is(":checked")) { + ids.push(this.id); + } else { + var index = ids.indexOf(this.id); + if (index > -1) { + ids.splice(index, 1); + } + } + }); + + ids = makelatecomeListUnique(ids); + selectedCount = ids.length; + + getCurrentLanguageCode(function (code) { + languageCode = code; + var message = rowMessages[languageCode]; + + $("#selectedLatecome").attr("data-ids", JSON.stringify(ids)); + + if (selectedCount === 0) { + $("#selectedShowLatecome").css("display", "none"); + $("#exportLatecome").css("display", "none"); + } else { + $("#exportLatecome").css("display", "inline-flex"); + $("#selectedShowLatecome").css("display", "inline-flex"); + $("#selectedShowLatecome").text(selectedCount + " - " + message); + } + }); +} function selectAllActivity() { $("#selectedActivity").attr("data-clicked", 1); $("#selectedShowActivity").removeAttr("style"); @@ -554,6 +588,125 @@ $("#attendance-info-import").click(function (e) { }); }); +$(".all-latecome-row").change(function () { + addinglatecomeIds(); +}); + +$(".all-latecome").change(function () { + setTimeout(() => { + addinglatecomeIds(); + }, 100); +}); + +$("#selectAllLatecome").click(function () { + $("#selectedLatecome").attr("data-clicked", 1); + $("#selectedShowLatecome").removeAttr("style"); + var savedFilters = JSON.parse(localStorage.getItem("savedFilters")); + + if (savedFilters && savedFilters["filterData"] !== null) { + var filter = savedFilters["filterData"]; + + $.ajax({ + url: "/attendance/latecome-attendance-select-filter", + data: { page: "all", filter: JSON.stringify(filter) }, + type: "GET", + dataType: "json", + success: function (response) { + var employeeIds = response.employee_ids; + + if (Array.isArray(employeeIds)) { + // Continue + } else { + console.error("employee_ids is not an array:", employeeIds); + } + + var selectedCount = employeeIds.length; + + for (var i = 0; i < employeeIds.length; i++) { + var empId = employeeIds[i]; + $("#" + empId).prop("checked", true); + } + $("#selectedLatecome").attr("data-ids", JSON.stringify(employeeIds)); + + count = makelatecomeListUnique(employeeIds); + ticklatecomeCheckboxes(count); + }, + error: function (xhr, status, error) { + console.error("Error:", error); + }, + }); + } else { + $.ajax({ + url: "/attendance/latecome-attendance-select", + data: { page: "all" }, + type: "GET", + dataType: "json", + success: function (response) { + var employeeIds = response.employee_ids; + + if (Array.isArray(employeeIds)) { + // Continue + } else { + console.error("employee_ids is not an array:", employeeIds); + } + + var selectedCount = employeeIds.length; + + for (var i = 0; i < employeeIds.length; i++) { + var empId = employeeIds[i]; + $("#" + empId).prop("checked", true); + } + var previousIds = $("#selectedLatecome").attr("data-ids"); + $("#selectedLatecome").attr( + "data-ids", + JSON.stringify( + Array.from(new Set([...employeeIds, ...JSON.parse(previousIds)])) + ) + ); + + count = makelatecomeListUnique(employeeIds); + ticklatecomeCheckboxes(count); + }, + error: function (xhr, status, error) { + console.error("Error:", error); + }, + }); + } +}); + +$("#unselectAllLatecome").click(function () { + $("#selectedLatecome").attr("data-clicked", 0); + + $.ajax({ + url: "/attendance/latecome-attendance-select", + data: { page: "all", filter: "{}" }, + type: "GET", + dataType: "json", + success: function (response) { + var employeeIds = response.employee_ids; + + if (Array.isArray(employeeIds)) { + // Continue + } else { + console.error("employee_ids is not an array:", employeeIds); + } + + for (var i = 0; i < employeeIds.length; i++) { + var empId = employeeIds[i]; + $("#" + empId).prop("checked", false); + $(".all-latecome").prop("checked", false); + } + $("#selectedLatecome").attr("data-ids", JSON.stringify([])); + + count = []; + ticklatecomeCheckboxes(count); + }, + error: function (xhr, status, error) { + console.error("Error:", error); + }, + }); +}); + $("#select-all-fields").change(function () { const isChecked = $(this).prop("checked"); $('[name="selected_fields"]').prop("checked", isChecked); @@ -561,7 +714,13 @@ $("#select-all-fields").change(function () { $(".all-latecome").change(function () { const isLateChecked = $(this).prop("checked"); - $(".all-latecome-row").prop("checked", isLateChecked); + var closest = $(this) + .closest(".oh-sticky-table__thead") + .siblings(".oh-sticky-table__tbody"); + $(closest) + .children() + .find(".all-latecome-row") + .prop("checked", isLateChecked); }); $(".all-attendance-activity").change(function () { @@ -718,6 +877,8 @@ $("#approveOt").click(function (e) { }); }); +// -------------------------------------------Data Export Handlers--------------------------------------------------------------- + $("#exportAccounts").click(function (e) { var currentDate = new Date().toISOString().slice(0, 10); var languageCode = null; @@ -766,6 +927,106 @@ $("#exportAccounts").click(function (e) { }); }); +$("#exportActivity").click(function (e) { + var currentDate = new Date().toISOString().slice(0, 10); + var languageCode = null; + ids = []; + ids.push($("#selectedActivity").attr("data-ids")); + ids = JSON.parse($("#selectedActivity").attr("data-ids")); + getCurrentLanguageCode(function (code) { + languageCode = code; + var confirmMessage = excelMessages[languageCode]; + Swal.fire({ + text: confirmMessage, + icon: "question", + showCancelButton: true, + confirmButtonColor: "#008000", + cancelButtonColor: "#d33", + confirmButtonText: "Confirm", + }).then(function (result) { + if (result.isConfirmed) { + $.ajax({ + type: "GET", + url: "/attendance/attendance-activity-info-export", + data: { + ids: JSON.stringify(ids), + }, + 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 = "Attendance_activity" + currentDate + ".xlsx"; + document.body.appendChild(link); + link.click(); + }, + error: function (xhr, textStatus, errorThrown) { + console.error("Error downloading file:", errorThrown); + }, + }); + } + }); + }); +}); + +$("#exportLatecome").click(function (e) { + var currentDate = new Date().toISOString().slice(0, 10); + var languageCode = null; + ids = []; + ids.push($("#selectedLatecome").attr("data-ids")); + ids = JSON.parse($("#selectedLatecome").attr("data-ids")); + getCurrentLanguageCode(function (code) { + languageCode = code; + var confirmMessage = excelMessages[languageCode]; + Swal.fire({ + text: confirmMessage, + icon: "question", + showCancelButton: true, + confirmButtonColor: "#008000", + cancelButtonColor: "#d33", + confirmButtonText: "Confirm", + }).then(function (result) { + if (result.isConfirmed) { + $.ajax({ + type: "GET", + url: "/attendance/late-come-early-out-info-export", + data: { + ids: JSON.stringify(ids), + }, + 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 = "Late_come" + currentDate + ".xlsx"; + document.body.appendChild(link); + link.click(); + }, + error: function (xhr, textStatus, errorThrown) { + console.error("Error downloading file:", errorThrown); + }, + }); + } + }); + }); +}); + +// ------------------------------------------------------------------------------------------------------------------------------ + +// -------------------------------------------------Data Delete Handlers--------------------------------------------------------- + $("#bulkDelete").click(function (e) { e.preventDefault(); var languageCode = null; @@ -814,6 +1075,102 @@ $("#bulkDelete").click(function (e) { }); }); +$("#hourAccountbulkDelete").click(function (e) { + e.preventDefault(); + var languageCode = null; + getCurrentLanguageCode(function (code) { + languageCode = code; + var confirmMessage = deleteMessages[languageCode]; + var textMessage = norowdeleteMessages[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) { + ids = []; + ids.push($("#selectedInstances").attr("data-ids")); + ids = JSON.parse($("#selectedInstances").attr("data-ids")); + $.ajax({ + type: "POST", + url: "/attendance/attendance-account-bulk-delete", + data: { + csrfmiddlewaretoken: getCookie("csrftoken"), + ids: JSON.stringify(ids), + }, + success: function (response, textStatus, jqXHR) { + if (jqXHR.status === 200) { + location.reload(); + } + }, + }); + } + }); + } + }); +}); + +$("#attendanceActivityDelete").click(function (e) { + e.preventDefault(); + var languageCode = null; + getCurrentLanguageCode(function (code) { + languageCode = code; + var confirmMessage = deleteMessages[languageCode]; + var textMessage = norowdeleteMessages[languageCode]; + ids = []; + ids.push($("#selectedActivity").attr("data-ids")); + ids = JSON.parse($("#selectedActivity").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) { + ids = []; + ids.push($("#selectedActivity").attr("data-ids")); + ids = JSON.parse($("#selectedActivity").attr("data-ids")); + $.ajax({ + type: "POST", + url: "/attendance/attendance-activity-bulk-delete", + data: { + csrfmiddlewaretoken: getCookie("csrftoken"), + ids: JSON.stringify(ids), + }, + success: function (response, textStatus, jqXHR) { + if (jqXHR.status === 200) { + location.reload(); + } + }, + }); + } + }); + } + }); +}); + $("#lateComeBulkDelete").click(function (e) { e.preventDefault(); var languageCode = null; @@ -862,145 +1219,4 @@ $("#lateComeBulkDelete").click(function (e) { }); }); -$("#exportActivity").click(function (e) { - var currentDate = new Date().toISOString().slice(0, 10); - var languageCode = null; - ids = []; - ids.push($("#selectedActivity").attr("data-ids")); - ids = JSON.parse($("#selectedActivity").attr("data-ids")); - getCurrentLanguageCode(function (code) { - languageCode = code; - var confirmMessage = excelMessages[languageCode]; - Swal.fire({ - text: confirmMessage, - icon: "question", - showCancelButton: true, - confirmButtonColor: "#008000", - cancelButtonColor: "#d33", - confirmButtonText: "Confirm", - }).then(function (result) { - if (result.isConfirmed) { - $.ajax({ - type: "GET", - url: "/attendance/attendance-activity-info-export", - data: { - ids: JSON.stringify(ids), - }, - 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 = "Attendance_activity" + currentDate + ".xlsx"; - document.body.appendChild(link); - link.click(); - }, - error: function (xhr, textStatus, errorThrown) { - console.error("Error downloading file:", errorThrown); - }, - }); - } - }); - }); -}); -$("#attendanceActivityDelete").click(function (e) { - e.preventDefault(); - var languageCode = null; - getCurrentLanguageCode(function (code) { - languageCode = code; - var confirmMessage = deleteMessages[languageCode]; - var textMessage = norowdeleteMessages[languageCode]; - ids = []; - ids.push($("#selectedActivity").attr("data-ids")); - ids = JSON.parse($("#selectedActivity").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) { - ids = []; - ids.push($("#selectedActivity").attr("data-ids")); - ids = JSON.parse($("#selectedActivity").attr("data-ids")); - $.ajax({ - type: "POST", - url: "/attendance/attendance-activity-bulk-delete", - data: { - csrfmiddlewaretoken: getCookie("csrftoken"), - ids: JSON.stringify(ids), - }, - success: function (response, textStatus, jqXHR) { - if (jqXHR.status === 200) { - location.reload(); - } - }, - }); - } - }); - } - }); -}); - -$("#hourAccountbulkDelete").click(function (e) { - e.preventDefault(); - var languageCode = null; - getCurrentLanguageCode(function (code) { - languageCode = code; - var confirmMessage = deleteMessages[languageCode]; - var textMessage = norowdeleteMessages[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) { - ids = []; - ids.push($("#selectedInstances").attr("data-ids")); - ids = JSON.parse($("#selectedInstances").attr("data-ids")); - $.ajax({ - type: "POST", - url: "/attendance/attendance-account-bulk-delete", - data: { - csrfmiddlewaretoken: getCookie("csrftoken"), - ids: JSON.stringify(ids), - }, - success: function (response, textStatus, jqXHR) { - if (jqXHR.status === 200) { - location.reload(); - } - }, - }); - } - }); - } - }); -}); +// ------------------------------------------------------------------------------------------------------------------------------ diff --git a/attendance/templates/attendance/late_come_early_out/report_list.html b/attendance/templates/attendance/late_come_early_out/report_list.html index d0fb08f4a..463005cf5 100644 --- a/attendance/templates/attendance/late_come_early_out/report_list.html +++ b/attendance/templates/attendance/late_come_early_out/report_list.html @@ -118,169 +118,3 @@ - - diff --git a/attendance/templates/attendance/late_come_early_out/reports.html b/attendance/templates/attendance/late_come_early_out/reports.html index c9abef564..8956be97e 100644 --- a/attendance/templates/attendance/late_come_early_out/reports.html +++ b/attendance/templates/attendance/late_come_early_out/reports.html @@ -23,5 +23,4 @@ {% include 'attendance/late_come_early_out/report_list.html' %} - {% endblock %} diff --git a/attendance/views/views.py b/attendance/views/views.py index 4d59d34cf..1d9c48371 100644 --- a/attendance/views/views.py +++ b/attendance/views/views.py @@ -299,21 +299,28 @@ def attendance_view(request): else: template = "attendance/attendance/attendance_empty.html" validate_attendances_ids = json.dumps( - list(validate_attendances.values_list("id", flat=True)) + [ + instance.id + for instance in paginator_qry( + validate_attendances, request.GET.get("vpage") + ).object_list + ] ) ot_attendances_ids = json.dumps( - list( - paginator_qry( + [ + instance.id + for instance in paginator_qry( ot_attendances, request.GET.get("opage") - ).object_list.values_list("id", flat=True) - ) + ).object_list + ] ) attendances_ids = json.dumps( - list( - paginator_qry(attendances, request.GET.get("page")).object_list.values_list( - "id", flat=True - ) - ) + [ + instance.id + for instance in paginator_qry( + attendances, request.GET.get("page") + ).object_list + ] ) return render( request, @@ -492,7 +499,12 @@ def view_my_attendance(request): else: template = "attendance/own_attendance/own_empty.html" attendances_ids = json.dumps( - list(employee_attendances.values_list("id", flat=True)) + [ + instance.id + for instance in paginator_qry( + employee_attendances, request.GET.get("page") + ).object_list + ] ) return render( request, @@ -535,19 +547,20 @@ def attendance_overtime_view(request): This method is used to view attendance account or overtime account. """ previous_data = request.GET.urlencode() - accounts = AttendanceOverTime.objects.all() - if accounts.exists(): + filter_obj = AttendanceOverTimeFilter(request.GET) + if filter_obj.qs.exists(): template = "attendance/attendance_account/attendance_overtime_view.html" else: template = "attendance/attendance_account/overtime_empty.html" accounts = filtersubordinates( - request, accounts, "attendance.view_attendanceovertime" + request, filter_obj.qs, "attendance.view_attendanceovertime" ) form = AttendanceOverTimeForm() form = choosesubordinates(request, form, "attendance.add_attendanceovertime") - filter_obj = AttendanceOverTimeFilter() export_obj = AttendanceOverTimeFilter() export_fields = AttendanceOverTimeExportForm() + data_dict = parse_qs(previous_data) + get_key_instances(AttendanceOverTime, data_dict) return render( request, template, @@ -559,6 +572,7 @@ def attendance_overtime_view(request): "export_obj": export_obj, "export_fields": export_fields, "gp_fields": AttendanceOvertimeReGroup.fields, + "filter_dict": data_dict, }, ) @@ -965,12 +979,12 @@ def late_come_early_out_bulk_delete(request): ids = json.loads(ids) for attendance_id in ids: try: - latecome = AttendanceLateComeEarlyOut.objects.get(id=attendance_id) - latecome.delete() + late_come = AttendanceLateComeEarlyOut.objects.get(id=attendance_id) + late_come.delete() messages.success( request, _("{employee} Late-in early-out deleted.").format( - employee=latecome.employee_id + employee=late_come.employee_id ), ) except AttendanceLateComeEarlyOut.DoesNotExist: @@ -986,27 +1000,53 @@ def late_come_early_out_export(request): This view function takes a GET request and exports attendance late come early out data into an Excel file. The exported Excel file will include the selected fields from the AttendanceLateComeEarlyOut model. """ + late_come_data = {} + selected_columns = [] + form = LateComeEarlyOutExportForm() today_date = date.today().strftime("%Y-%m-%d") file_name = f"Late_come_{today_date}.xlsx" attendances = LateComeEarlyOutFilter(request.GET).qs selected_fields = request.GET.getlist("selected_fields") - model_fields = AttendanceLateComeEarlyOut._meta.get_fields() - lateCome_data = {} - for field in model_fields: - field_name = field.name - if field_name in selected_fields: - lateCome_data[field.verbose_name] = [] - for attendance in attendances: - value = getattr(attendance, field_name) - if value is True: - value = "Yes" - elif value is False: - value = "No" - lateCome_data[field.verbose_name].append(value) - data_frame = pd.DataFrame(data=lateCome_data) + + if not selected_fields: + selected_fields = form.fields["selected_fields"].initial + ids = request.GET.get("ids") + id_list = json.loads(ids) + attendances = AttendanceLateComeEarlyOut.objects.filter(id__in=id_list) + + for field in form.fields["selected_fields"].choices: + value = field[0] + key = field[1] + if value in selected_fields: + selected_columns.append((value, key)) + + for column_value, column_name in selected_columns: + nested_attributes = column_value.split("__") + late_come_data[column_name] = [] + for attendance in attendances: + value = attendance + for attr in nested_attributes: + value = getattr(value, attr, None) + if value is None: + break + data = str(value) if value is not None else "" + if data == "True": + data = _("Yes") + elif data == "False": + data = _("No") + late_come_data[column_name].append(data) + + data_frame = pd.DataFrame(data=late_come_data) + data_frame = data_frame.style.applymap( + lambda x: "text-align: center", subset=pd.IndexSlice[:, :] + ) response = HttpResponse(content_type="application/ms-excel") response["Content-Disposition"] = f'attachment; filename="{file_name}"' - data_frame.to_excel(response, index=False) + writer = pd.ExcelWriter(response, engine="xlsxwriter") + data_frame.to_excel(writer, index=False, sheet_name="Sheet1") + worksheet = writer.sheets["Sheet1"] + worksheet.set_column("A:Z", 20) + writer.close() return response