diff --git a/app/utils/notifications.py b/app/utils/notifications.py index c5eff91..b23a856 100644 --- a/app/utils/notifications.py +++ b/app/utils/notifications.py @@ -219,20 +219,32 @@ def notify( ) # ── 2. Send immediate email if applicable ──────────────────────────────── - if send_email and not hold_for_digest: + if not send_email: + logger.info('EMAIL SKIP | user=%s | event=%s | reason=send_email_False', + recipient.username, event_type) + elif hold_for_digest: + logger.info('EMAIL SKIP | user=%s | event=%s | reason=digest_mode', + recipient.username, event_type) + else: if respect_preferences: - # Per-user opt-in/opt-out gate — used for direct notifications - # (issue assignment, SLA alerts, follower updates, etc.) - should_send = ( - event_type is None or _email_enabled_for(recipient, event_type) - ) + pref_enabled = _email_enabled_for(recipient, event_type) + should_send = (event_type is None or pref_enabled) + if not should_send: + logger.info('EMAIL SKIP | user=%s | event=%s | reason=user_pref_disabled', + recipient.username, event_type) else: - # Matrix-routed broadcast — the admin matrix is the authority. - # Individual preference rows must not override it, otherwise an - # admin or director who once clicked "Pause All" would silently - # stop receiving inspection completion and other broadcast events. should_send = True - if should_send and recipient.email and current_app.config.get('MAIL_SERVER'): + + mail_server = current_app.config.get('MAIL_SERVER') + if should_send and not recipient.email: + logger.warning('EMAIL SKIP | user=%s | event=%s | reason=no_email_address', + recipient.username, event_type) + elif should_send and not mail_server: + logger.warning('EMAIL SKIP | user=%s | event=%s | reason=MAIL_SERVER_not_configured', + recipient.username, event_type) + elif should_send: + logger.info('EMAIL SEND | user=%s | event=%s | to=%s', + recipient.username, event_type, recipient.email) _send_single_email(recipient, title, body, link) @@ -536,10 +548,15 @@ def notify_by_matrix( 'customer': 'customer', } + logger.info('MATRIX NOTIFY START | event=%s | exclude=%s', event_type, exclude) + for role_key, _ in MATRIX_ROLES: if role_key == 'custom': continue # handled separately below - if not is_enabled(event_type, role_key): + enabled = is_enabled(event_type, role_key) + logger.info('MATRIX NOTIFY | event=%s | role=%s | enabled=%s', + event_type, role_key, enabled) + if not enabled: continue db_role = role_to_db.get(role_key) @@ -547,6 +564,8 @@ def notify_by_matrix( continue users = User.query.filter_by(role=db_role, active=True).all() + logger.info('MATRIX NOTIFY | event=%s | role=%s | users_found=%s', + event_type, role_key, [u.username for u in users]) # Scope customer role to facility if provided if role_key == 'customer' and facility_id: