# ============================================================
# MODULE: Notificaties & Rapportages — FASE 5.2
# HSEQ Intelligence Dashboard
# In-app notificaties, wekelijks compliance rapport
# ============================================================
import sqlite3
from datetime import datetime, timedelta
from flask import jsonify, request, render_template_string
from indexer import DB_PATH
from module_auth import get_current_user, require_login
def init_db_notifications():
# Tables created in module_auth.init_db_auth() - notifications table
pass
def _unread_count(user_id):
conn = sqlite3.connect(DB_PATH)
cnt = conn.execute("SELECT COUNT(*) FROM notifications WHERE user_id=? AND read=0", (user_id,)).fetchone()[0]
conn.close()
return cnt
def create_notification(user_id, ntype, title, message="", company_id=None):
conn = sqlite3.connect(DB_PATH)
conn.execute("INSERT INTO notifications (user_id,company_id,type,title,message) VALUES (?,?,?,?,?)",
(user_id, company_id, ntype, title, message))
conn.commit()
conn.close()
# ─── Weekly Report HTML ──────────────────────────────────────────────────
WEEKLY_REPORT_HTML = """
📊 Wekelijks Compliance Rapport
Periode: {{week_start}} — {{week_end}}
{{stats.compliant}}
Compliant
{{stats.in_progress}}
In Uitvoering
{{stats.overdue}}
Verlopen
{{stats.total}}
Totaal Items
RAG Matrix Overzicht
Categorie
Compliant
In Uitvoering
Verlopen
Open
{% for cat in rag_rows %}
{{cat.name}}
{{cat.compliant}}
{{cat.in_progress}}
{{cat.overdue}}
{{cat.open}}
{% endfor %}
{% if actions %}
⚠️ Open Acties
Beschrijving
Prioriteit
Deadline
Status
{% for a in actions %}
{{a.description}}
{{a.priority}}
{{a.deadline or '-'}}
{{a.status}}
{% endfor %}
{% endif %}
"""
def _get_weekly_stats():
conn = sqlite3.connect(DB_PATH)
conn.row_factory = sqlite3.Row
stats = {'compliant': 0, 'in_progress': 0, 'overdue': 0, 'open': 0, 'total': 0, 'not_applicable': 0}
try:
rows = conn.execute("SELECT status, COUNT(*) as cnt FROM compliance_status GROUP BY status").fetchall()
for r in rows:
s = r['status'] or 'open'
if s in stats:
stats[s] = r['cnt']
stats['total'] += r['cnt']
except:
pass
rag_rows = []
try:
cats = conn.execute("SELECT DISTINCT category FROM compliance_status ORDER BY category").fetchall()
for c in cats:
cat_name = c['category']
row = {'name': cat_name, 'compliant': 0, 'in_progress': 0, 'overdue': 0, 'open': 0}
statuses = conn.execute("SELECT status, COUNT(*) as cnt FROM compliance_status WHERE category=? GROUP BY status", (cat_name,)).fetchall()
for s in statuses:
st = s['status'] or 'open'
if st in row:
row[st] = s['cnt']
rag_rows.append(row)
except:
pass
actions = []
try:
actions = conn.execute("SELECT * FROM compliance_status WHERE status IN ('overdue','in_progress','open') ORDER BY CASE priority WHEN 'critical' THEN 1 WHEN 'high' THEN 2 WHEN 'medium' THEN 3 ELSE 4 END LIMIT 20").fetchall()
except:
pass
conn.close()
return stats, rag_rows, actions
# ─── Register Routes ──────────────────────────────────────────────────────
def register_notification_routes(flask_app, page_func, BASE_PATH="/hseq-dashboard"):
app = flask_app
@app.route(BASE_PATH + '/api/notifications')
@require_login
def api_notifications():
user = get_current_user()
conn = sqlite3.connect(DB_PATH)
conn.row_factory = sqlite3.Row
notifs = conn.execute("SELECT * FROM notifications WHERE user_id=? ORDER BY created_at DESC LIMIT 50",
(user['id'],)).fetchall()
conn.close()
return jsonify([dict(n) for n in notifs])
@app.route(BASE_PATH + '/api/notifications//read', methods=['POST'])
@require_login
def api_notification_read(nid):
user = get_current_user()
conn = sqlite3.connect(DB_PATH)
conn.execute("UPDATE notifications SET read=1 WHERE id=? AND user_id=?", (nid, user['id']))
conn.commit()
conn.close()
return jsonify({"ok": True})
@app.route(BASE_PATH + '/api/notifications/count')
@require_login
def api_notification_count():
user = get_current_user()
return jsonify({"count": _unread_count(user['id'])})
@app.route(BASE_PATH + '/api/reports/weekly')
@require_login
def api_weekly_report():
stats, rag_rows, actions = _get_weekly_stats()
return jsonify({"stats": stats, "rag": rag_rows, "actions": [dict(a) for a in actions]})
@app.route(BASE_PATH + '/reports/weekly')
@require_login
def reports_weekly():
stats, rag_rows, actions = _get_weekly_stats()
now = datetime.now()
week_start = (now - timedelta(days=now.weekday())).strftime('%d-%m-%Y')
week_end = (now + timedelta(days=6-now.weekday())).strftime('%d-%m-%Y')
body = render_template_string(WEEKLY_REPORT_HTML, stats=stats, rag_rows=rag_rows,
actions=actions, week_start=week_start, week_end=week_end)
return page_func(body, active='reports-weekly', page_title='Wekelijks Rapport')