"""Idempotent in-app deadline checks through Hub's existing reminder scheduler.""" from app.core.database import atomic_transaction,execute_query_single,execute_query from .work import FINISHED def run_planning_checks(): ready=execute_query_single("""SELECT EXISTS(SELECT 1 FROM information_schema.columns WHERE table_name='planner_settings' AND column_name='deadline_warning_days') AS ready""") if not ready or not ready['ready']: return 0 config=execute_query_single('SELECT deadline_warning_days FROM planner_settings WHERE id=1') or {} days=int(config.get('deadline_warning_days',0)) if not days: return 0 from app.modules.sag.frontend.views import _fetch_closed_case_statuses closed=FINISHED|set(_fetch_closed_case_statuses()) with atomic_transaction(): rows=execute_query('''WITH candidates AS ( SELECT s.id,s.deadline,EXISTS(SELECT 1 FROM sag_case_assignees a JOIN users u ON u.user_id=a.user_id WHERE a.sag_id=s.id AND u.is_active) AS allocated, ARRAY(SELECT DISTINCT u.user_id FROM users u WHERE u.is_active AND (u.user_id=s.ansvarlig_bruger_id OR EXISTS(SELECT 1 FROM sag_case_assignees a WHERE a.sag_id=s.id AND a.user_id=u.user_id) OR (NOT EXISTS(SELECT 1 FROM sag_case_assignees a JOIN users au ON au.user_id=a.user_id WHERE a.sag_id=s.id AND au.is_active) AND (u.is_superadmin OR EXISTS(SELECT 1 FROM user_groups ug JOIN group_permissions gp ON gp.group_id=ug.group_id JOIN permissions p ON p.id=gp.permission_id WHERE ug.user_id=u.user_id AND p.code IN ('planner.admin','planner.allocate')))))) AS recipients FROM sag_sager s WHERE s.deleted_at IS NULL AND LOWER(s.status)<>ALL(%s) AND (s.deadline AT TIME ZONE 'UTC') BETWEEN NOW()-INTERVAL '1 day' AND NOW()+make_interval(days=>%s) ) INSERT INTO sag_reminders(sag_id,title,message,event_type,trigger_type,trigger_config, recipient_user_ids,notify_mattermost,notify_email,notify_frontend,override_user_preferences, recurrence_type,scheduled_at,next_check_at) SELECT id,CASE WHEN allocated THEN 'Deadline nærmer sig' ELSE 'Deadline: medarbejder mangler' END, 'Kontrollér deadline, kapacitet og arbejdsfordeling.','deadline','time_based', jsonb_build_object('planner_key','deadline:'||id::text||':'||deadline::text||':'||allocated::text||':'|| TO_CHAR(NOW() AT TIME ZONE 'Europe/Copenhagen','YYYY-MM-DD')), recipients,FALSE,FALSE,TRUE,TRUE,'once',NOW(),NOW() FROM candidates WHERE cardinality(recipients)>0 ORDER BY id ON CONFLICT DO NOTHING RETURNING id''',(list(closed),days)) or [] return len(rows)