diff --git a/app/models/issue.py b/app/models/issue.py index cfbf644..c810a3e 100644 --- a/app/models/issue.py +++ b/app/models/issue.py @@ -2,6 +2,23 @@ from app import db from datetime import datetime +class IssueComment(db.Model): + __tablename__ = 'issue_comments' + + id = db.Column(db.Integer, primary_key=True) + issue_id = db.Column(db.Integer, db.ForeignKey('issues.id'), nullable=False) + user_id = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=False) + status_at_time = db.Column(db.String(20)) # snapshot of issue status when comment was made + body = db.Column(db.Text, nullable=False) + created_at = db.Column(db.DateTime, default=datetime.utcnow, nullable=False) + + # Relationships + author = db.relationship('User', foreign_keys=[user_id]) + + def __repr__(self): + return f'' + + class Issue(db.Model): __tablename__ = 'issues' @@ -20,6 +37,9 @@ class Issue(db.Model): # Relationships assigned_user = db.relationship('User', foreign_keys=[assigned_to], backref='assigned_issues') + comments = db.relationship('IssueComment', backref='issue', lazy='dynamic', + order_by='IssueComment.created_at', + cascade='all, delete-orphan') def __repr__(self): return f'' \ No newline at end of file diff --git a/app/routes/issues.py b/app/routes/issues.py index 3447183..50db69d 100644 --- a/app/routes/issues.py +++ b/app/routes/issues.py @@ -3,7 +3,7 @@ from flask import (Blueprint, render_template, redirect, url_for, flash, request, current_app) from flask_login import login_required, current_user from app import db -from app.models.issue import Issue +from app.models.issue import Issue, IssueComment from app.models.facility import Facility, Area from app.models.user import User from app.utils.forms import IssueForm, IssueUpdateForm @@ -84,15 +84,27 @@ def view(issue_id): existing = issue.result_photos or [] issue.result_photos = existing + new_photos + # Persist a comment entry if the user wrote update notes + comment_body = form.comments.data.strip() if form.comments.data else '' + if comment_body: + comment = IssueComment( + issue_id = issue.id, + user_id = current_user.id, + status_at_time = issue.status, + body = comment_body, + ) + db.session.add(comment) + db.session.commit() current_app.logger.info( - 'ISSUE UPDATED | id=%s | status=%s | result_photos_added=%s | updated_by=%s', - issue.id, issue.status, len(new_photos), current_user.username + 'ISSUE UPDATED | id=%s | status=%s | result_photos_added=%s | comment=%s | updated_by=%s', + issue.id, issue.status, len(new_photos), bool(comment_body), current_user.username ) flash('Issue updated.', 'success') return redirect(url_for('issues.view', issue_id=issue_id)) - return render_template('issues/view.html', issue=issue, form=form) + comments = issue.comments.order_by(IssueComment.created_at.asc()).all() + return render_template('issues/view.html', issue=issue, form=form, comments=comments) # ── Standalone create (not from an inspection) ──────────────────────────────── diff --git a/app/routes/reports.py b/app/routes/reports.py index 38e9fa4..94c0f92 100644 --- a/app/routes/reports.py +++ b/app/routes/reports.py @@ -46,7 +46,13 @@ def index(): total_inspections = base.count() completed = base.filter(Inspection.status == 'completed').count() - flagged = base.filter(Inspection.status == 'flagged').count() + # "Flagged" = open or in-progress issues logged within the date range, + # not inspections with status='flagged' (those get completed on submit). + flagged = Issue.query.filter( + Issue.reported_at >= start, + Issue.reported_at <= end, + Issue.status != 'resolved', + ).count() avg_score = db.session.query(func.avg(Inspection.overall_score)).filter( Inspection.inspection_date >= start, Inspection.inspection_date <= end, diff --git a/app/templates/issues/view.html b/app/templates/issues/view.html index d829284..6d23e80 100644 --- a/app/templates/issues/view.html +++ b/app/templates/issues/view.html @@ -69,6 +69,34 @@ {% endif %} + + {# ── Update History ─────────────────────────────────────────────────── #} + {% if comments %} +
+
+
Update History
+
+
    + {% for c in comments %} +
  • +
    + + {{ c.author.username }} + + + + {{ c.status_at_time|replace('_',' ')|title }} + + {{ c.created_at.strftime('%Y-%m-%d %H:%M') }} + +
    +

    {{ c.body }}

    +
  • + {% endfor %} +
+
+ {% endif %} +
diff --git a/app/templates/reports/index.html b/app/templates/reports/index.html index 77e4057..e460cd8 100644 --- a/app/templates/reports/index.html +++ b/app/templates/reports/index.html @@ -52,7 +52,7 @@ {% for label, value, color, icon in [ ('Total Inspections', total_inspections, 'primary', 'bi-clipboard-data'), ('Completed', completed, 'success', 'bi-check-circle'), - ('Flagged', flagged, 'danger', 'bi-flag'), + ('Open Issues', flagged, 'danger', 'bi-flag'), ('Avg Score', (avg_score|string + '%') if avg_score else '—', 'info', 'bi-graph-up'), ] %}