Mar 06 2026: fixed attendance report page, searchable ID only
This commit is contained in:
@@ -5384,18 +5384,20 @@ def save_manual_attendance():
|
||||
@login_required
|
||||
def search_employees_api():
|
||||
"""
|
||||
API endpoint to search employees by name or ID
|
||||
Returns JSON with employee list
|
||||
API endpoint to search employees by name or ID.
|
||||
Returns matches from the Employee table first, then appends any IDs found
|
||||
in attendance_data that have no Employee record — so unregistered IDs
|
||||
that have attendance records can still be filtered on the attendance page.
|
||||
"""
|
||||
try:
|
||||
search_query = request.args.get('q', '').strip()
|
||||
|
||||
|
||||
if not search_query or len(search_query) < 2:
|
||||
return jsonify({'employees': []})
|
||||
|
||||
# Search by ID or name
|
||||
|
||||
search_pattern = f"%{search_query}%"
|
||||
|
||||
|
||||
# 1. Registered employees — search by ID or name
|
||||
employees = Employee.query.filter(
|
||||
db.or_(
|
||||
Employee.id.like(search_pattern),
|
||||
@@ -5404,16 +5406,49 @@ def search_employees_api():
|
||||
db.func.concat(Employee.firstName, ' ', Employee.lastName).like(search_pattern)
|
||||
)
|
||||
).limit(10).all()
|
||||
|
||||
|
||||
employee_list = [{
|
||||
'id': emp.id,
|
||||
'firstName': emp.firstName,
|
||||
'lastName': emp.lastName,
|
||||
'full_name': f"{emp.firstName} {emp.lastName}"
|
||||
} for emp in employees]
|
||||
|
||||
|
||||
registered_ids = {str(emp.id) for emp in employees}
|
||||
|
||||
# 2. Unregistered IDs — present in attendance_data but not in Employee table.
|
||||
# Only add when the search term looks like (part of) a numeric ID and we
|
||||
# still have room in the result list.
|
||||
if len(employee_list) < 10:
|
||||
remaining_slots = 10 - len(employee_list)
|
||||
try:
|
||||
unregistered_rows = db.session.execute(
|
||||
text("""
|
||||
SELECT DISTINCT ad.employee_id
|
||||
FROM attendance_data ad
|
||||
LEFT JOIN employee e ON CAST(ad.employee_id AS UNSIGNED) = e.id
|
||||
WHERE e.id IS NULL
|
||||
AND ad.employee_id LIKE :pattern
|
||||
ORDER BY ad.employee_id
|
||||
LIMIT :lim
|
||||
"""),
|
||||
{'pattern': search_pattern, 'lim': remaining_slots}
|
||||
).fetchall()
|
||||
|
||||
for row in unregistered_rows:
|
||||
emp_id = str(row[0])
|
||||
if emp_id not in registered_ids:
|
||||
employee_list.append({
|
||||
'id': emp_id,
|
||||
'firstName': f'ID: {emp_id}',
|
||||
'lastName': '(no record)',
|
||||
'full_name': f'ID: {emp_id} (no record)'
|
||||
})
|
||||
except Exception as unreg_err:
|
||||
logger_handler.logger.warning(f"Could not search unregistered employee IDs: {unreg_err}")
|
||||
|
||||
return jsonify({'employees': employee_list})
|
||||
|
||||
|
||||
except Exception as e:
|
||||
logger_handler.logger.error(f"Error searching employees: {e}")
|
||||
return jsonify({'employees': [], 'error': str(e)}), 500
|
||||
|
||||
@@ -765,19 +765,29 @@ document.addEventListener('DOMContentLoaded', function() {
|
||||
if (employeeSearchFilter) {
|
||||
employeeSearchFilter.addEventListener('input', function() {
|
||||
const searchTerm = this.value.trim();
|
||||
|
||||
|
||||
// Clear hidden field if input is cleared
|
||||
if (searchTerm.length === 0) {
|
||||
employeeHiddenFilter.value = '';
|
||||
autocompleteResultsFilter.classList.remove('show');
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// If the visible input is a plain numeric ID, keep the hidden field
|
||||
// in sync immediately so the user can just type an ID and submit
|
||||
// without having to pick from the dropdown (handles IDs not in Employee table).
|
||||
if (/^\d+$/.test(searchTerm)) {
|
||||
employeeHiddenFilter.value = searchTerm;
|
||||
} else {
|
||||
// Non-numeric input — clear hidden field until a suggestion is picked
|
||||
employeeHiddenFilter.value = '';
|
||||
}
|
||||
|
||||
if (searchTerm.length < 2) {
|
||||
autocompleteResultsFilter.classList.remove('show');
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// Debounce search
|
||||
clearTimeout(searchFilterTimeout);
|
||||
searchFilterTimeout = setTimeout(() => {
|
||||
|
||||
Reference in New Issue
Block a user