diff --git a/app/routes/issues.py b/app/routes/issues.py index 641017b..db1ea20 100644 --- a/app/routes/issues.py +++ b/app/routes/issues.py @@ -70,12 +70,18 @@ class _SLAFilteredPage: @login_required def index(): page = request.args.get('page', 1, type=int) - q = Issue.query.order_by(Issue.reported_at.desc()) + # outerjoin Area once here so both the customer-scope filter and the + # facility_filter block can reference Area.facility_id without a cartesian + # product. Issues with no area_id get NULL for all Area columns (outer join). + q = ( + Issue.query + .outerjoin(Area, Issue.area_id == Area.id) + .order_by(Issue.reported_at.desc()) + ) if current_user.role == 'inspector': q = q.filter(Issue.assigned_to == current_user.id) elif current_user.role == 'customer': - from app.models.facility import Area customer_facility_ids = get_customer_scope(current_user) if not customer_facility_ids: q = q.filter(False) @@ -86,11 +92,10 @@ def index(): Issue.facility_id.in_(customer_facility_ids), db.and_( Issue.area_id.isnot(None), - Issue.area_id == Area.id, - Area.facility_id.in_(customer_facility_ids) + Area.facility_id.in_(customer_facility_ids), ) ) - ).outerjoin(Area, Issue.area_id == Area.id) + ) severity_filter = request.args.get('severity', '') status_filter = request.args.get('status', '') @@ -106,8 +111,7 @@ def index(): q = q.filter( db.or_( Issue.facility_id == fid, - db.and_(Issue.area_id.isnot(None), - Area.facility_id == fid) + Area.facility_id == fid, ) ) # SLA filter — SLA status is computed in Python (not a DB column). diff --git a/app/utils/audit.py b/app/utils/audit.py index 1bf0c49..4ed2453 100644 --- a/app/utils/audit.py +++ b/app/utils/audit.py @@ -44,6 +44,11 @@ def log_action(action: str, """ Write a single AuditLog row. Safe to call from any request context. + ⚠️ This function calls db.session.commit() internally. + Always call it AFTER the primary db.session.commit() for the business + transaction — never before. Calling it mid-transaction will commit any + dirty ORM state accumulated in the session up to that point. + Parameters ---------- action : One of the ACTION_* constants (or a custom string ≤ 50 chars). @@ -90,4 +95,4 @@ def log_action(action: str, try: db.session.rollback() except Exception: - pass + pass \ No newline at end of file