diff --git a/src/main/java/com/gcc/commissionerreview/service/AttendanceService.java b/src/main/java/com/gcc/commissionerreview/service/AttendanceService.java index 58f3bf0..9260451 100644 --- a/src/main/java/com/gcc/commissionerreview/service/AttendanceService.java +++ b/src/main/java/com/gcc/commissionerreview/service/AttendanceService.java @@ -298,6 +298,34 @@ public class AttendanceService { + toDateTime + ", Zone: " + zone); return jdbcTemplate.queryForList(sql, params.toArray()); + } else if (category != null && category.equalsIgnoreCase("total")) { + + String sql = "SELECT et.enrollment_id, et.name, et.designation, et.department, " + + "et.incharge_name, et.incharge_phoneno, et.phone_number as emp_mobile, " + + "COALESCE(pd.park_name, '') AS park_name, et.park_id, " + + "COALESCE(pd.supervisor_name, '') AS supervisor_name, COALESCE(pd.supervisor_mobile, '') AS supervisor_mobile " + + "FROM enrollment_table et " + + "LEFT JOIN park_details pd ON et.park_id = pd.park_id AND pd.is_active = 1 AND pd.is_delete = 0 " + + "WHERE et.isactive = 1 AND et.isdelete = 0 AND et.emp_type = ? AND et.zone != 0 "; + java.util.List params = new java.util.ArrayList<>(); + params.add(empType); + + if (zone != null) { + sql += " AND et.zone = ? "; + params.add(zone); + } + + if (parkName != null && !parkName.isEmpty() && !parkName.equals("-")) { + sql += " AND et.park_id = ? "; + params.add(parkName); + } + + sql += " ORDER BY pd.park_name, et.name "; + + System.out.println("Total - EmpType: " + empType + ", From: " + fromDateTime + ", To: " + + toDateTime + ", Zone: " + zone + ", ParkName: " + parkName); + return jdbcTemplate.queryForList(sql, params.toArray()); + } else { switch (category == null ? "present" : category.toLowerCase()) { diff --git a/src/main/resources/templates/modules/attendance-dashboard.html b/src/main/resources/templates/modules/attendance-dashboard.html index 3d124c7..e307a73 100644 --- a/src/main/resources/templates/modules/attendance-dashboard.html +++ b/src/main/resources/templates/modules/attendance-dashboard.html @@ -289,7 +289,9 @@ // const supervisor = Number(r.SupervisorCount) || 0; html += `${zone || '-'}`; - html += `${total}`; + html += `` + (total > 0 + ? `${total}` + : `${total}`) + ``; html += `${facialRegistered}`; html += `` + (facialNotRegistered > 0 ? `${facialNotRegistered}` @@ -437,10 +439,38 @@ if (!Array.isArray(data)) { modalBody.innerText = JSON.stringify(data); return; } if (data.length === 0) { modalBody.innerHTML = '
No park-wise records
'; return; } + // Filter parks: when a category is selected, only show parks with count > 0 for that category + const catLower = (category || '').toLowerCase(); + const displayData = !catLower ? data : data.filter(r => { + const total = Number(r.TotalCount) || 0; + const present = Number(r.AttendanceMarked) || 0; + const od = Number(r.ODCount) || 0; + const leave = Number(r.LeaveCount) || 0; + const facialNotRegistered = Number(r.facialNotRegistered) || 0; + const notMarked = Math.max(0, total - present - od - leave - facialNotRegistered); + if (catLower === 'total') return total > 0; + if (catLower === 'present') return present > 0; + if (catLower === 'od') return od > 0; + if (catLower === 'leave') return leave > 0; + if (catLower === 'notmarked') return notMarked > 0; + if (catLower === 'notregistered') return facialNotRegistered > 0; + return true; + }); + + if (displayData.length === 0) { modalBody.innerHTML = '
No parks with ' + (category || '').toUpperCase() + ' count
'; return; } + + const showAll = !catLower; + let html = '
'; - html += ''; + html += ''; + if (showAll) { + html += ''; + } else { + const categoryLabel = { present: 'Present', od: 'OD', leave: 'Leave', notmarked: 'Not Marked', notregistered: 'Facial Not Registered' }; + html += ``; + } html += ''; - data.forEach(r => { + displayData.forEach(r => { const parkId = r.park_id || ''; const park = r.park_name || ''; const parkDisplay = park === '' ? (parkId || 'Unknown') : park; @@ -458,19 +488,29 @@ html += ``; html += ``; html += ``; - html += ``; - html += ``; - // html += ``; - html += ``; - html += ``; - html += ``; - html += ``; - html += ``; + if (showAll) { + html += ``; + html += ``; + html += ``; + html += ``; + html += ``; + html += ``; + html += ``; + } else { + // Show only the selected category column + let catValue = 0; + if (catLower === 'present') catValue = present; + else if (catLower === 'od') catValue = od; + else if (catLower === 'leave') catValue = leave; + else if (catLower === 'notmarked') catValue = notMarked; + else if (catLower === 'notregistered') catValue = facialNotRegistered; + html += ``; + } html += ''; }); - // Compute grand totals for park-wise summary - let grandTotal = 0, grandSupervisor = 0, grandFacialReg = 0, grandFacialNotReg = 0, grandPresent = 0, grandOd = 0, grandLeave = 0, grandNotMarked = 0; + // Compute grand totals from ALL data to match zone summary (no count mismatch) + let grandTotal = 0, grandFacialReg = 0, grandFacialNotReg = 0, grandPresent = 0, grandOd = 0, grandLeave = 0, grandNotMarked = 0; data.forEach(r => { const total = Number(r.TotalCount) || 0; const facialRegistered = Number(r.facialRegistered) || 0; @@ -490,13 +530,23 @@ html += ''; html += ''; html += ''; - html += ``; - html += ``; - html += ``; - html += ``; - html += ``; - html += ``; - html += ``; + if (showAll) { + html += ``; + html += ``; + html += ``; + html += ``; + html += ``; + html += ``; + html += ``; + } else { + let grandCatValue = 0; + if (catLower === 'present') grandCatValue = grandPresent; + else if (catLower === 'od') grandCatValue = grandOd; + else if (catLower === 'leave') grandCatValue = grandLeave; + else if (catLower === 'notmarked') grandCatValue = grandNotMarked; + else if (catLower === 'notregistered') grandCatValue = grandFacialNotReg; + html += ``; + } html += '
Park IDPark NameSupervisor NameSupervisor MobileTotalFacial RegisteredFacial Not RegisteredPresentODLeaveNot MarkedPark IDPark NameSupervisor NameSupervisor MobileTotalFacial RegisteredFacial Not RegisteredPresentODLeaveNot Marked${categoryLabel[catLower] || category}
${parkDisplay}${supervisorName}${supervisorMobile}${total}${facialRegistered}${facialNotRegistered}` + (facialNotRegistered > 0 ? `${facialNotRegistered}` : `${facialNotRegistered}`) + `` + (present > 0 ? `${present}` : `${present}`) + `` + (od > 0 ? `${od}` : `${od}`) + `` + (leave > 0 ? `${leave}` : `${leave}`) + `` + (notMarked > 0 ? `${notMarked}` : `${notMarked}`) + `${total}${facialRegistered}` + (facialNotRegistered > 0 ? `${facialNotRegistered}` : `${facialNotRegistered}`) + `` + (present > 0 ? `${present}` : `${present}`) + `` + (od > 0 ? `${od}` : `${od}`) + `` + (leave > 0 ? `${leave}` : `${leave}`) + `` + (notMarked > 0 ? `${notMarked}` : `${notMarked}`) + `` + (catValue > 0 ? `${catValue}` : `${catValue}`) + `
Total${grandTotal}${grandFacialReg}${grandFacialNotReg}${grandPresent}${grandOd}${grandLeave}${grandNotMarked}${grandTotal}${grandFacialReg}${grandFacialNotReg}${grandPresent}${grandOd}${grandLeave}${grandNotMarked}${grandCatValue}
'; modalBody.innerHTML = html; } catch (e) { @@ -583,7 +633,9 @@ let displayColumns = []; const catLower = (category || 'present').toLowerCase(); - if (catLower === 'present') { + if (catLower === 'total') { + displayColumns = ['park_name', 'supervisor_name', 'supervisor_mobile', 'enrollment_id', 'name', 'emp_mobile']; + } else if (catLower === 'present') { displayColumns = ['enrollment_id', 'name', 'designation', 'department', 'incharge_name', 'incharge_phoneno', 'App Version', 'App Type', 'Location']; if (empType === 'Park') displayColumns.push('park_name'); displayColumns.push('intime', 'inphoto', 'outtime', 'outphoto'); @@ -642,6 +694,9 @@ location: 'Location', image: 'Image', supervisor_id: 'Supervisor ID', + supervisor_name: 'Supervisor Name', + supervisor_mobile: 'Supervisor Mobile', + emp_mobile: 'Employee Mobile', }; if (map[key]) return map[key]; return key.replace(/_/g, ' ').replace(/\b\w/g, c => c.toUpperCase()); @@ -715,8 +770,8 @@ const zone = zoneAnchor.getAttribute('data-zone'); const empType = zoneAnchor.getAttribute('data-emptype'); const category = zoneAnchor.getAttribute('data-category'); - // Supervisor: show employee details directly (no park-wise drill-down) - if (category === 'supervisor') { + // Supervisor & Total: show employee details directly (no park-wise drill-down) + if (category === 'supervisor' || category === 'total') { loadDetailed(empType, category, zone); } else if (empType === 'Park') { loadParkWiseSummary(zone, category);