Update verification photo pages

This commit is contained in:
2025-12-27 11:08:12 -05:00
parent c32cb40333
commit d71403b1cf
3 changed files with 197 additions and 15 deletions
+77 -10
View File
@@ -5348,9 +5348,12 @@ def verification_review():
status_filter = request.args.get('status', 'pending')
date_from = request.args.get('date_from', '')
date_to = request.args.get('date_to', '')
project_filter = request.args.get('project', '')
location_filter = request.args.get('location', '')
employee_filter = request.args.get('employee', '')
# Build query
query = AttendanceData.query.filter(
# Build query - join with QRCode to access project_id
query = AttendanceData.query.join(QRCode).filter(
AttendanceData.verification_required == True
)
@@ -5363,11 +5366,54 @@ def verification_review():
if date_to:
query = query.filter(AttendanceData.check_in_date <= date_to)
# Apply project filter
if project_filter:
try:
query = query.filter(QRCode.project_id == int(project_filter))
except (ValueError, TypeError):
pass
# Apply location filter
if location_filter:
query = query.filter(AttendanceData.location_name.ilike(f'%{location_filter}%'))
# Apply employee ID filter
if employee_filter:
query = query.filter(AttendanceData.employee_id.ilike(f'%{employee_filter}%'))
# Get records with QR code information
verifications = query.join(QRCode).order_by(
verifications = query.order_by(
AttendanceData.verification_timestamp.desc()
).all()
# Build a dictionary for employee names lookup
employee_names = {}
for record in verifications:
if record.employee_id and record.employee_id not in employee_names:
try:
employee = Employee.query.filter_by(id=int(record.employee_id)).first()
if employee:
employee_names[record.employee_id] = f"{employee.lastName}, {employee.firstName}"
else:
employee_names[record.employee_id] = None
except (ValueError, TypeError):
employee_names[record.employee_id] = None
# Build a dictionary for project names lookup
project_names = {}
for record in verifications:
if record.qr_code and record.qr_code.project_id:
project_id = record.qr_code.project_id
if project_id not in project_names:
try:
project = Project.query.get(project_id)
if project:
project_names[project_id] = project.name
else:
project_names[project_id] = None
except Exception:
project_names[project_id] = None
# Get counts for status badges
pending_count = AttendanceData.query.filter(
AttendanceData.verification_status == 'pending'
@@ -5381,6 +5427,20 @@ def verification_review():
AttendanceData.verification_status == 'rejected'
).count()
# Get all projects for filter dropdown
projects = Project.query.filter_by(active_status=True).order_by(Project.name).all()
# Get unique locations for filter dropdown
locations = db.session.query(AttendanceData.location_name).filter(
AttendanceData.verification_required == True
).distinct().order_by(AttendanceData.location_name).all()
location_list = [loc[0] for loc in locations if loc[0]]
# Log access
logger_handler.logger.info(
f"User {session.get('username')} ({session.get('role')}) accessed verification review page"
)
return render_template('verification_review.html',
verifications=verifications,
pending_count=pending_count,
@@ -5388,7 +5448,14 @@ def verification_review():
rejected_count=rejected_count,
status_filter=status_filter,
date_from=date_from,
date_to=date_to)
date_to=date_to,
project_filter=project_filter,
location_filter=location_filter,
employee_filter=employee_filter,
projects=projects,
locations=location_list,
employee_names=employee_names,
project_names=project_names)
except Exception as e:
logger_handler.logger.error(f"Error in verification review: {e}")
@@ -5586,12 +5653,12 @@ def verification_review_detail(record_id):
check_in_time = str(record.check_in_time) if record.check_in_time else 'N/A'
return render_template('verification_review_detail.html',
record=record,
qr_code=qr_code,
check_in_date=check_in_date,
check_in_time=check_in_time,
employee_name=employee_name,
location_event=location_event)
record=record,
qr_code=qr_code,
check_in_date=check_in_date,
check_in_time=check_in_time,
employee_name=employee_name,
location_event=location_event)
except Exception as e:
logger_handler.logger.error(f"Error loading verification review detail: {e}")
+117 -2
View File
@@ -60,6 +60,36 @@
</select>
</div>
<div class="filter-group">
<label for="project">Project</label>
<select name="project" id="project" class="filter-select">
<option value="">All Projects</option>
{% for project in projects %}
<option value="{{ project.id }}" {% if project_filter == project.id|string %}selected{% endif %}>
{{ project.name }}
</option>
{% endfor %}
</select>
</div>
<div class="filter-group">
<label for="location">Location</label>
<select name="location" id="location" class="filter-select">
<option value="">All Locations</option>
{% for location in locations %}
<option value="{{ location }}" {% if location_filter == location %}selected{% endif %}>
{{ location }}
</option>
{% endfor %}
</select>
</div>
<div class="filter-group">
<label for="employee">Employee ID</label>
<input type="text" name="employee" id="employee" value="{{ employee_filter }}"
class="filter-input" placeholder="Search by ID...">
</div>
<div class="filter-group">
<label for="date_from">From Date</label>
<input type="date" name="date_from" id="date_from" value="{{ date_from }}" class="filter-input">
@@ -70,10 +100,13 @@
<input type="date" name="date_to" id="date_to" value="{{ date_to }}" class="filter-input">
</div>
<div class="filter-group">
<div class="filter-group filter-buttons">
<button type="submit" class="btn-filter">
<i class="fas fa-filter"></i> Apply Filters
</button>
<a href="{{ url_for('verification_review') }}" class="btn-reset">
<i class="fas fa-undo"></i> Reset
</a>
</div>
</div>
</form>
@@ -89,7 +122,10 @@
<div class="verification-info">
<h3>
<i class="fas fa-user"></i>
Employee {{ record.employee_id }}
{{ record.employee_id }}
{% if employee_names.get(record.employee_id) %}
<span class="employee-name">- {{ employee_names.get(record.employee_id) }}</span>
{% endif %}
</h3>
<div class="verification-meta">
<span class="meta-item">
@@ -104,7 +140,21 @@
<i class="fas fa-map-marker-alt"></i>
{{ record.location_name }}
</span>
{% if record.qr_code and record.qr_code.location_event %}
<span class="meta-item event-badge {{ 'check-in' if record.qr_code.location_event == 'Check In' else 'check-out' }}">
<i class="fas fa-{{ 'sign-in-alt' if record.qr_code.location_event == 'Check In' else 'sign-out-alt' }}"></i>
{{ record.qr_code.location_event }}
</span>
{% endif %}
</div>
{% if record.qr_code and record.qr_code.project_id and project_names.get(record.qr_code.project_id) %}
<div class="verification-project">
<span class="project-badge">
<i class="fas fa-folder"></i>
{{ project_names.get(record.qr_code.project_id) }}
</span>
</div>
{% endif %}
</div>
<div class="verification-status">
{% if record.verification_status == 'pending' %}
@@ -330,6 +380,71 @@
background: #2563eb;
}
.btn-reset {
width: 100%;
padding: 0.625rem 1.5rem;
background: #6b7280;
color: white;
border: none;
border-radius: 0.375rem;
font-weight: 600;
cursor: pointer;
transition: background 0.2s;
text-decoration: none;
text-align: center;
display: inline-block;
margin-top: 0.5rem;
}
.btn-reset:hover {
background: #4b5563;
color: white;
}
.filter-buttons {
display: flex;
flex-direction: column;
}
.employee-name {
font-weight: 500;
color: #4b5563;
font-size: 0.95em;
}
.verification-project {
margin-top: 0.5rem;
}
.project-badge {
display: inline-flex;
align-items: center;
gap: 0.375rem;
padding: 0.25rem 0.75rem;
background: #e0e7ff;
color: #3730a3;
border-radius: 9999px;
font-size: 0.8rem;
font-weight: 500;
}
.event-badge {
padding: 0.25rem 0.5rem;
border-radius: 0.25rem;
font-weight: 600;
font-size: 0.75rem;
}
.event-badge.check-in {
background: #d1fae5;
color: #065f46;
}
.event-badge.check-out {
background: #fef3c7;
color: #92400e;
}
.verifications-grid {
display: grid;
gap: 2rem;
+1 -1
View File
@@ -345,7 +345,7 @@ QR Code Management{% endblock %} {% block extra_head %}
<div class="info-row">
<span class="info-label">QR Address</span>
<span class="info-value"
>{{ qr_code.address if qr_code else 'N/A' }}</span
>{{ qr_code.location_address if qr_code else 'N/A' }}</span
>
</div>
<div class="info-row">