diff --git a/app.py b/app.py index 9265d21..5fab4e9 100644 --- a/app.py +++ b/app.py @@ -3001,7 +3001,8 @@ def attendance_report(): date_to = request.args.get('date_to', '') location_filter = request.args.get('location', '') employee_filter = request.args.get('employee', '') - + project_filter = request.args.get('project', '') + # Build base query - conditional based on column existence if has_location_accuracy: # New query with location accuracy @@ -3068,6 +3069,11 @@ def attendance_report(): conditions.append("ad.employee_id ILIKE :employee") params['employee'] = f"%{employee_filter}%" + if project_filter: + # Join with QRCode and filter by project_id + query = query.join(QRCode, AttendanceData.qr_code_id == QRCode.id).filter(QRCode.project_id == int(project_filter)) + print(f"📊 Applied project filter: {project_filter}") + # Add conditions to query if conditions: base_query += " AND " + " AND ".join(conditions) @@ -3170,6 +3176,23 @@ def attendance_report(): except Exception as e: print(f"⚠️ Error loading locations: {e}") locations = [] + + # Update the locations query to get only active projects for the dropdown + try: + projects = db.session.execute(text(""" + SELECT p.id, p.name, COUNT(DISTINCT ad.id) as attendance_count + FROM projects p + LEFT JOIN qr_codes qc ON qc.project_id = p.id + LEFT JOIN attendance_data ad ON ad.qr_code_id = qc.id + WHERE p.active_status = true + GROUP BY p.id, p.name + HAVING COUNT(DISTINCT ad.id) > 0 + ORDER BY p.name + """)).fetchall() + print(f"✅ Loaded {len(projects)} projects with attendance data") + except Exception as e: + print(f"⚠️ Error loading projects: {e}") + projects = [] # Get attendance statistics try: @@ -3222,11 +3245,13 @@ def attendance_report(): return render_template('attendance_report.html', attendance_records=processed_records, locations=locations, + projects=projects, stats=stats, date_from=date_from, date_to=date_to, location_filter=location_filter, employee_filter=employee_filter, + project_filter=project_filter, today_date=today_date, current_date_formatted=current_date_formatted, has_location_accuracy_feature=has_location_accuracy) @@ -3452,7 +3477,8 @@ def export_configuration(): 'date_from': request.args.get('date_from', ''), 'date_to': request.args.get('date_to', ''), 'location_filter': request.args.get('location', ''), - 'employee_filter': request.args.get('employee', '') + 'employee_filter': request.args.get('employee', ''), + 'project_filter': request.args.get('project', '') } print(f"📊 Filters: {filters}") @@ -3670,6 +3696,11 @@ def create_excel_export(selected_columns, column_names, filters): query = query.filter(AttendanceData.employee_id.ilike(f"%{filters['employee_filter']}%")) print(f"📊 Applied employee filter: {filters['employee_filter']}") + # Apply project filter + if filters.get('project_filter'): + query = query.filter(QRCode.project_id == int(filters['project_filter'])) + print(f"📊 Applied project filter to export: {filters['project_filter']}") + # Execute query and get results results = query.order_by(AttendanceData.check_in_date.desc(), AttendanceData.check_in_time.desc()).all() print(f"📊 Found {len(results)} records for export") diff --git a/static/js/attendance_report.js b/static/js/attendance_report.js index dbf7298..a4c8a8b 100644 --- a/static/js/attendance_report.js +++ b/static/js/attendance_report.js @@ -947,66 +947,75 @@ function exportAttendanceWithAccuracy() { } function exportAttendance() { - // Log export action - console.log('Export button clicked - redirecting to configuration page'); - - // Get current filters - const currentFilters = getCurrentFilters(); - - // Build URL with current filters - const params = new URLSearchParams(); - if (currentFilters.date_from) params.append('date_from', currentFilters.date_from); - if (currentFilters.date_to) params.append('date_to', currentFilters.date_to); - if (currentFilters.location) params.append('location', currentFilters.location); - if (currentFilters.employee) params.append('employee', currentFilters.employee); - - // Navigate to export configuration page - const configUrl = '/export-configuration' + (params.toString() ? '?' + params.toString() : ''); - window.location.href = configUrl; + // Log export action + console.log("Export button clicked - redirecting to configuration page"); + + // Get current filters + const currentFilters = getCurrentFilters(); + + // Build URL with current filters + const params = new URLSearchParams(); + if (currentFilters.date_from) + params.append("date_from", currentFilters.date_from); + if (currentFilters.date_to) params.append("date_to", currentFilters.date_to); + if (currentFilters.location) + params.append("location", currentFilters.location); + if (currentFilters.employee) + params.append("employee", currentFilters.employee); + + // Navigate to export configuration page + const configUrl = + "/export-configuration" + + (params.toString() ? "?" + params.toString() : ""); + window.location.href = configUrl; } function getCurrentFilters() { - // Extract current filter values from the page - return { - date_from: document.getElementById('date_from')?.value || '', - date_to: document.getElementById('date_to')?.value || '', - location: document.getElementById('location')?.value || '', - employee: document.getElementById('employee')?.value || '' - }; + // Extract current filter values from the page + return { + date_from: document.getElementById("date_from")?.value || "", + date_to: document.getElementById("date_to")?.value || "", + location: document.getElementById("location")?.value || "", + employee: document.getElementById("employee")?.value || "", + project: document.getElementById("project")?.value || "", + }; } // Add a quick CSV export function as backup (keep existing functionality) function exportAttendanceCSV() { - // Build export URL with current filters for CSV - const params = new URLSearchParams(); - const filters = getCurrentFilters(); - - if (filters.date_from) params.append('date_from', filters.date_from); - if (filters.date_to) params.append('date_to', filters.date_to); - if (filters.location) params.append('location', filters.location); - if (filters.employee) params.append('employee', filters.employee); - params.append('export', 'csv'); - - // Create a temporary link and click it to download - const downloadUrl = window.location.pathname + '?' + params.toString(); - window.open(downloadUrl, '_blank'); + // Build export URL with current filters for CSV + const params = new URLSearchParams(); + const filters = getCurrentFilters(); + + if (filters.date_from) params.append("date_from", filters.date_from); + if (filters.date_to) params.append("date_to", filters.date_to); + if (filters.location) params.append("location", filters.location); + if (filters.employee) params.append("employee", filters.employee); + if (filters.project) params.append("project", filters.project); + params.append("export", "csv"); + + // Create a temporary link and click it to download + const downloadUrl = window.location.pathname + "?" + params.toString(); + window.open(downloadUrl, "_blank"); } // Enhanced export menu (if you want to add dropdown with multiple export options) function showExportMenu() { - // Create export options menu - const existingMenu = document.getElementById('exportMenu'); - if (existingMenu) { - existingMenu.remove(); - return; - } - - const exportBtn = document.querySelector('button[onclick="exportAttendance()"]'); - if (!exportBtn) return; - - const menu = document.createElement('div'); - menu.id = 'exportMenu'; - menu.style.cssText = ` + // Create export options menu + const existingMenu = document.getElementById("exportMenu"); + if (existingMenu) { + existingMenu.remove(); + return; + } + + const exportBtn = document.querySelector( + 'button[onclick="exportAttendance()"]' + ); + if (!exportBtn) return; + + const menu = document.createElement("div"); + menu.id = "exportMenu"; + menu.style.cssText = ` position: absolute; top: 100%; right: 0; @@ -1018,8 +1027,8 @@ function showExportMenu() { min-width: 200px; margin-top: 5px; `; - - menu.innerHTML = ` + + menu.innerHTML = `