From 792e84f4398965ce9a5b1fcde20a6a0300306d31 Mon Sep 17 00:00:00 2001 From: NguyenND Date: Tue, 9 Jun 2026 13:26:09 -0400 Subject: [PATCH] 06/09 Add Inspecter filters, and allow customer to flag issue --- app/routes/inspections.py | 42 ++++++++++++ app/routes/issues.py | 33 +++++++--- app/templates/inspections/list.html | 99 ++++++++++++++++++++--------- app/templates/issues/form.html | 11 +++- app/templates/issues/list.html | 2 +- 5 files changed, 145 insertions(+), 42 deletions(-) diff --git a/app/routes/inspections.py b/app/routes/inspections.py index d6284f3..6f64eb7 100644 --- a/app/routes/inspections.py +++ b/app/routes/inspections.py @@ -232,6 +232,11 @@ def index(): facility_filter = request.args.get('facility_id', '') follow_up_filter = request.args.get('follow_up', '') contract_filter = request.args.get('contract_id', '') + date_from_filter = request.args.get('date_from', '') + date_to_filter = request.args.get('date_to', '') + score_min_filter = request.args.get('score_min', '') + score_max_filter = request.args.get('score_max', '') + inspector_filter = request.args.get('inspector_id', '') if status_filter: q = q.filter(Inspection.status == status_filter) @@ -247,6 +252,29 @@ def index(): Inspection.follow_up_required == True, Inspection.status == 'completed', ).filter(~Inspection.follow_ups.any()) + if date_from_filter: + try: + q = q.filter(Inspection.inspection_date >= datetime.strptime(date_from_filter, '%Y-%m-%d')) + except ValueError: + date_from_filter = '' + if date_to_filter: + try: + _dt = datetime.strptime(date_to_filter, '%Y-%m-%d').replace(hour=23, minute=59, second=59) + q = q.filter(Inspection.inspection_date <= _dt) + except ValueError: + date_to_filter = '' + if score_min_filter: + try: + q = q.filter(Inspection.overall_score >= float(score_min_filter)) + except ValueError: + score_min_filter = '' + if score_max_filter: + try: + q = q.filter(Inspection.overall_score <= float(score_max_filter)) + except ValueError: + score_max_filter = '' + if inspector_filter.isdigit() and current_user.role != 'inspector': + q = q.filter(Inspection.inspector_id == int(inspector_filter)) inspections = q.paginate(page=page, per_page=20, error_out=False) @@ -276,14 +304,28 @@ def index(): else: projects = Project.query.filter_by(active=True).order_by(Project.name).all() + # Inspector dropdown — shown to all roles except inspector (they only see their own) + if current_user.role != 'inspector': + inspectors = (User.query + .filter(User.role == 'inspector', User.active == True) + .order_by(User.full_name, User.username).all()) + else: + inspectors = [] + return render_template('inspections/list.html', inspections=inspections, facilities=facilities, projects=projects, + inspectors=inspectors, status_filter=status_filter, facility_filter=facility_filter, follow_up_filter=follow_up_filter, contract_filter=contract_filter, + date_from_filter=date_from_filter, + date_to_filter=date_to_filter, + score_min_filter=score_min_filter, + score_max_filter=score_max_filter, + inspector_filter=inspector_filter, now=now_eastern()) diff --git a/app/routes/issues.py b/app/routes/issues.py index 9ca7303..1b1d119 100644 --- a/app/routes/issues.py +++ b/app/routes/issues.py @@ -478,16 +478,33 @@ def unfollow(issue_id): @bp.route('/new', methods=['GET', 'POST']) @login_required -@supervisor_required def create(): - from app.models.project import Project - form = IssueForm() - facilities = Facility.query.filter_by(active=True).order_by(Facility.name).all() - projects = Project.query.filter_by(active=True).order_by(Project.name).all() - staff = User.query.filter(User.role.in_(['admin', 'director', 'inspector'])).order_by(User.username).all() + if current_user.role not in ('admin', 'director', 'customer'): + abort(403) - form.facility_id.choices = [(f.id, f.name) for f in facilities] - form.assigned_to.choices = [(0, '— Unassigned —')] + [(u.id, u.username) for u in staff] + from app.models.project import Project, CustomerAssignment + form = IssueForm() + + if current_user.role == 'customer': + cids = get_customer_scope(current_user) or [] + facilities = (Facility.query + .filter(Facility.id.in_(cids), Facility.active == True) + .order_by(Facility.name).all()) if cids else [] + assigned_pids = { + a.project_id for a in + CustomerAssignment.query.filter_by(user_id=current_user.id).all() + } + projects = Project.query.filter( + Project.active == True, Project.id.in_(assigned_pids) + ).order_by(Project.name).all() + staff = [] + else: + facilities = Facility.query.filter_by(active=True).order_by(Facility.name).all() + projects = Project.query.filter_by(active=True).order_by(Project.name).all() + staff = User.query.filter(User.role.in_(['admin', 'director', 'inspector'])).order_by(User.username).all() + + form.facility_id.choices = [(f.id, f.name) for f in facilities] + form.assigned_to.choices = [(0, '— Unassigned —')] + [(u.id, u.username) for u in staff] # On POST validation error: identify which contract the submitted facility # belongs to so the contract selector can be restored on re-render. diff --git a/app/templates/inspections/list.html b/app/templates/inspections/list.html index d41802b..7cb6ca5 100644 --- a/app/templates/inspections/list.html +++ b/app/templates/inspections/list.html @@ -13,37 +13,74 @@ {# Filters #}
-
-
- - + +
+
+ + +
+
+ + +
+
+ + +
+ {% if inspectors %} +
+ + +
+ {% endif %}
-
- - -
-
- - -
-
- - Clear +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + Clear +
@@ -125,7 +162,7 @@ {% for p in inspections.iter_pages(left_edge=1, right_edge=1, left_current=2, right_current=2) %} {% if p %}
  • - {{ p }} + {{ p }}
  • {% else %}
  • diff --git a/app/templates/issues/form.html b/app/templates/issues/form.html index 8dfa229..817ba11 100644 --- a/app/templates/issues/form.html +++ b/app/templates/issues/form.html @@ -29,14 +29,21 @@ {% for e in form.facility_id.errors %}
    {{ e }}
    {% endfor %}
    - {# Remaining fields #} - {% for field in [form.severity, form.description, form.photo, form.assigned_to] %} + {# Remaining fields — assigned_to hidden from customer role #} + {% for field in [form.severity, form.description, form.photo] %}
    {{ field.label(class="form-label fw-semibold") }} {{ field(class="form-select" if field.type == 'SelectField' else "form-control", rows=4 if field.type == 'TextAreaField' else none) }} {% for e in field.errors %}
    {{ e }}
    {% endfor %}
    {% endfor %} + {% if current_user.role != 'customer' %} +
    + {{ form.assigned_to.label(class="form-label fw-semibold") }} + {{ form.assigned_to(class="form-select") }} + {% for e in form.assigned_to.errors %}
    {{ e }}
    {% endfor %} +
    + {% endif %}
    diff --git a/app/templates/issues/list.html b/app/templates/issues/list.html index cfef68a..ee4503a 100644 --- a/app/templates/issues/list.html +++ b/app/templates/issues/list.html @@ -3,7 +3,7 @@ {% block content %}

    Issues

    - {% if current_user.role in ['admin','director'] %} + {% if current_user.role in ['admin','director','customer'] %} Log Issue