249 lines
7.6 KiB
Python
249 lines
7.6 KiB
Python
"""
|
|
Celery tasks for psychology app.
|
|
Handles automated workflows, notifications, and scheduled tasks.
|
|
"""
|
|
|
|
from celery import shared_task
|
|
from django.utils import timezone
|
|
from django.db.models import Q
|
|
from datetime import timedelta
|
|
|
|
from .models import (
|
|
PsychologyConsultation,
|
|
PsychologySession,
|
|
PsychologyGoal,
|
|
)
|
|
from .services import (
|
|
PsychologyRiskAssessmentService,
|
|
PsychologyGoalTrackingService,
|
|
PsychologySessionManagementService,
|
|
PsychologyNotificationService,
|
|
)
|
|
from core.models import User
|
|
from notifications.models import Notification
|
|
|
|
|
|
@shared_task
|
|
def check_high_risk_patients():
|
|
"""
|
|
Daily task to check for high-risk patients and send alerts.
|
|
Runs every day at 8:00 AM.
|
|
"""
|
|
from core.models import Tenant
|
|
|
|
total_alerts = 0
|
|
|
|
for tenant in Tenant.objects.filter(is_active=True):
|
|
high_risk_patients = PsychologyRiskAssessmentService.get_high_risk_patients(str(tenant.id))
|
|
|
|
if high_risk_patients:
|
|
# Get clinical coordinator for this tenant
|
|
coordinators = User.objects.filter(
|
|
tenant=tenant,
|
|
role='CLINICAL_COORDINATOR',
|
|
is_active=True
|
|
)
|
|
|
|
for coordinator in coordinators:
|
|
Notification.objects.create(
|
|
user=coordinator,
|
|
notification_type='DAILY_SUMMARY',
|
|
title=f"High Risk Patients - Psychology",
|
|
message=f"{len(high_risk_patients)} patients with high risk assessments require monitoring.",
|
|
)
|
|
total_alerts += 1
|
|
|
|
return {
|
|
'task': 'check_high_risk_patients',
|
|
'alerts_sent': total_alerts,
|
|
'timestamp': timezone.now().isoformat(),
|
|
}
|
|
|
|
|
|
@shared_task
|
|
def send_unsigned_session_reminders():
|
|
"""
|
|
Daily task to remind psychologists about unsigned sessions.
|
|
Runs every day at 5:00 PM.
|
|
"""
|
|
psychologists = User.objects.filter(
|
|
role__in=['THERAPIST_SENIOR', 'THERAPIST_JUNIOR', 'THERAPIST_ASSISTANT'],
|
|
is_active=True
|
|
)
|
|
|
|
total_reminders = 0
|
|
|
|
for psychologist in psychologists:
|
|
# Check if they have psychology sessions
|
|
has_psych_sessions = PsychologySession.objects.filter(
|
|
provider=psychologist
|
|
).exists()
|
|
|
|
if has_psych_sessions:
|
|
count = PsychologyNotificationService.notify_unsigned_sessions(psychologist)
|
|
if count > 0:
|
|
total_reminders += 1
|
|
|
|
return {
|
|
'task': 'send_unsigned_session_reminders',
|
|
'reminders_sent': total_reminders,
|
|
'timestamp': timezone.now().isoformat(),
|
|
}
|
|
|
|
|
|
@shared_task
|
|
def send_overdue_goal_reminders():
|
|
"""
|
|
Weekly task to remind psychologists about overdue treatment goals.
|
|
Runs every Monday at 9:00 AM.
|
|
"""
|
|
psychologists = User.objects.filter(
|
|
role__in=['THERAPIST_SENIOR', 'THERAPIST_JUNIOR', 'THERAPIST_ASSISTANT'],
|
|
is_active=True
|
|
)
|
|
|
|
total_reminders = 0
|
|
|
|
for psychologist in psychologists:
|
|
# Check if they have psychology consultations
|
|
has_psych_consultations = PsychologyConsultation.objects.filter(
|
|
provider=psychologist
|
|
).exists()
|
|
|
|
if has_psych_consultations:
|
|
count = PsychologyNotificationService.notify_overdue_goals(psychologist)
|
|
if count > 0:
|
|
total_reminders += 1
|
|
|
|
return {
|
|
'task': 'send_overdue_goal_reminders',
|
|
'reminders_sent': total_reminders,
|
|
'timestamp': timezone.now().isoformat(),
|
|
}
|
|
|
|
|
|
@shared_task
|
|
def generate_weekly_psychology_summary():
|
|
"""
|
|
Weekly task to generate psychology statistics summary.
|
|
Runs every Monday at 8:00 AM.
|
|
"""
|
|
from .services import PsychologyStatisticsService
|
|
from core.models import Tenant
|
|
|
|
summaries_generated = 0
|
|
|
|
for tenant in Tenant.objects.filter(is_active=True):
|
|
# Get statistics for the past week
|
|
stats = PsychologyStatisticsService.get_tenant_statistics(
|
|
str(tenant.id),
|
|
start_date=timezone.now().date() - timedelta(days=7)
|
|
)
|
|
|
|
# Send to clinical coordinator
|
|
coordinators = User.objects.filter(
|
|
tenant=tenant,
|
|
role='CLINICAL_COORDINATOR',
|
|
is_active=True
|
|
)
|
|
|
|
for coordinator in coordinators:
|
|
message = f"""
|
|
Weekly Psychology Summary:
|
|
- Consultations: {stats['total_consultations']}
|
|
- Sessions: {stats['total_sessions']}
|
|
- Active Patients: {stats['total_active_patients']}
|
|
- High Risk Patients: {stats['high_risk_patients']}
|
|
- Goals Achieved: {stats['goals_achieved']}
|
|
- Average Goal Progress: {stats['average_goal_progress']:.1f}%
|
|
""".strip()
|
|
|
|
Notification.objects.create(
|
|
user=coordinator,
|
|
notification_type='WEEKLY_SUMMARY',
|
|
title=f"Weekly Psychology Summary",
|
|
message=message,
|
|
)
|
|
summaries_generated += 1
|
|
|
|
return {
|
|
'task': 'generate_weekly_psychology_summary',
|
|
'summaries_generated': summaries_generated,
|
|
'timestamp': timezone.now().isoformat(),
|
|
}
|
|
|
|
|
|
@shared_task
|
|
def auto_update_goal_status():
|
|
"""
|
|
Daily task to auto-update goal status based on progress percentage.
|
|
Runs every day at 6:00 AM.
|
|
"""
|
|
goals_updated = 0
|
|
|
|
# Get all active goals
|
|
goals = PsychologyGoal.objects.filter(
|
|
status__in=['NOT_STARTED', 'IN_PROGRESS']
|
|
)
|
|
|
|
for goal in goals:
|
|
old_status = goal.status
|
|
|
|
# Update status based on progress
|
|
if goal.progress_percentage == 0:
|
|
goal.status = 'NOT_STARTED'
|
|
elif goal.progress_percentage == 100:
|
|
goal.status = 'ACHIEVED'
|
|
if not goal.achieved_date:
|
|
goal.achieved_date = timezone.now().date()
|
|
elif goal.progress_percentage > 0:
|
|
goal.status = 'IN_PROGRESS'
|
|
|
|
# Save if status changed
|
|
if old_status != goal.status:
|
|
goal.save()
|
|
goals_updated += 1
|
|
|
|
return {
|
|
'task': 'auto_update_goal_status',
|
|
'goals_updated': goals_updated,
|
|
'timestamp': timezone.now().isoformat(),
|
|
}
|
|
|
|
|
|
@shared_task
|
|
def check_consultation_follow_ups():
|
|
"""
|
|
Weekly task to check if consultations need follow-up.
|
|
Runs every Friday at 10:00 AM.
|
|
"""
|
|
# Get consultations from 30-45 days ago that don't have follow-up sessions
|
|
start_date = timezone.now().date() - timedelta(days=45)
|
|
end_date = timezone.now().date() - timedelta(days=30)
|
|
|
|
consultations_needing_followup = PsychologyConsultation.objects.filter(
|
|
consultation_date__gte=start_date,
|
|
consultation_date__lte=end_date
|
|
).exclude(
|
|
patient__psychology_sessions__session_date__gte=end_date
|
|
).select_related('patient', 'provider')
|
|
|
|
notifications_sent = 0
|
|
|
|
for consultation in consultations_needing_followup:
|
|
if consultation.provider:
|
|
Notification.objects.create(
|
|
user=consultation.provider,
|
|
notification_type='REMINDER',
|
|
title=f"Follow-up Needed: {consultation.patient.get_full_name()}",
|
|
message=f"Consultation from {consultation.consultation_date} may need follow-up session.",
|
|
)
|
|
notifications_sent += 1
|
|
|
|
return {
|
|
'task': 'check_consultation_follow_ups',
|
|
'notifications_sent': notifications_sent,
|
|
'consultations_checked': consultations_needing_followup.count(),
|
|
'timestamp': timezone.now().isoformat(),
|
|
}
|