From 0675acb8ecfadfc9162a0aa515f30cec8a0d5ac1 Mon Sep 17 00:00:00 2001 From: Nguyen Ngo Date: Sat, 16 May 2026 13:47:39 -0400 Subject: [PATCH] 05/16 Fix bugs 1 --- app/api/inspections.py | 25 +++++++++++++++++++++---- app/models/notification.py | 4 ++++ 2 files changed, 25 insertions(+), 4 deletions(-) diff --git a/app/api/inspections.py b/app/api/inspections.py index 9d4f3b5..e9d0b1f 100644 --- a/app/api/inspections.py +++ b/app/api/inspections.py @@ -264,6 +264,12 @@ def create_inspection(): # follow_up_required on the parent automatically. This mirrors the web # list view's implicit logic (which hides the badge when follow_ups.any()) # and ensures the History API response reflects the resolved state. + # Capture parent label strings before commit while ORM objects are loaded. + # log_action() for the parent update must fire AFTER db.session.commit() to + # avoid audit.py's internal commit() persisting the parent flag change before + # the new inspection row is committed — a partial state that would be incorrect + # if the main commit subsequently failed. + _parent_log_args = None if parent_inspection_id and status == 'completed': parent_insp = db.session.get(Inspection, parent_inspection_id) if parent_insp and parent_insp.follow_up_required: @@ -273,10 +279,13 @@ def create_inspection(): 'by_inspection_id=%d | user=%s', parent_inspection_id, inspection.id, user.username, ) - log_action(ACTION_UPDATE, 'Inspection', parent_inspection_id, - f'{parent_insp.template.name} @ {parent_insp.facility.name}', - f'follow_up_required=False (cleared by re-inspection ' - f'#{inspection.id} via mobile API)') + # Snapshot label strings now — ORM objects may be expired after commit + _parent_log_args = ( + parent_inspection_id, + f'{parent_insp.template.name} @ {parent_insp.facility.name}', + f'follow_up_required=False (cleared by re-inspection ' + f'#{inspection.id} via mobile API)', + ) # ── Notifications ───────────────────────────────────────────────────── if status == 'completed': @@ -304,6 +313,14 @@ def create_inspection(): db.session.commit() + # ── Post-commit audit logging ────────────────────────────────────────── + # All log_action() calls must come AFTER db.session.commit() because + # audit.py calls db.session.commit() internally. Calling it before the + # main commit would persist the audit row (and any dirty ORM state) before + # the primary transaction completes. + if _parent_log_args: + log_action(ACTION_UPDATE, 'Inspection', *_parent_log_args) + log_action(ACTION_CREATE, 'Inspection', inspection.id, f'{template.name} @ {facility.name}', f'source=mobile; status={status}; score={overall_score}; ' diff --git a/app/models/notification.py b/app/models/notification.py index d94abef..9e0db1c 100644 --- a/app/models/notification.py +++ b/app/models/notification.py @@ -12,6 +12,9 @@ EVENT_ISSUE_COMMENT = 'issue_comment' EVENT_ISSUE_FOLLOW = 'issue_follow_update' EVENT_INSPECTION_DONE = 'inspection_completed' EVENT_SLA_ALERT = 'sla_alert' +# Fired when an issue is flagged during an inspection (web or mobile). +# Listed here so users can configure email preferences for this event. +EVENT_ISSUE_FLAGGED = 'issue_flagged' # ── Customer portal events ───────────────────────────────────────────────── # Fired when an inspection completes or an issue is created/updated at a @@ -25,6 +28,7 @@ ALL_EVENT_TYPES = { EVENT_ISSUE_STATUS: 'Issue status changed', EVENT_ISSUE_COMMENT: 'New comment on issue', EVENT_ISSUE_FOLLOW: 'Updates on followed issues', + EVENT_ISSUE_FLAGGED: 'Issue flagged (from inspection)', EVENT_INSPECTION_DONE: 'Inspection completed', EVENT_SLA_ALERT: 'SLA at-risk / breached alerts', # Customer-facing — only relevant for customer role accounts