244 lines
6.9 KiB
Python
244 lines
6.9 KiB
Python
"""
|
|
Celery tasks for MDT 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 (
|
|
MDTNote,
|
|
MDTContribution,
|
|
MDTApproval,
|
|
MDTMention,
|
|
)
|
|
from .services import (
|
|
MDTWorkflowService,
|
|
MDTStatisticsService,
|
|
MDTNotificationService,
|
|
)
|
|
from core.models import User
|
|
from notifications.models import Notification
|
|
|
|
|
|
@shared_task
|
|
def check_stale_mdt_notes():
|
|
"""
|
|
Daily task to check for stale MDT notes (in draft for >30 days).
|
|
Runs every day at 9:00 AM.
|
|
"""
|
|
stale_notes = MDTWorkflowService.get_stale_notes(days=30)
|
|
|
|
notifications_sent = 0
|
|
|
|
for note in stale_notes:
|
|
if note.initiated_by:
|
|
Notification.objects.create(
|
|
user=note.initiated_by,
|
|
notification_type='MDT_REMINDER',
|
|
title=f"Stale MDT Note: {note.title}",
|
|
message=f"MDT note has been in draft for over 30 days. Please finalize or archive.",
|
|
)
|
|
notifications_sent += 1
|
|
|
|
return {
|
|
'task': 'check_stale_mdt_notes',
|
|
'stale_notes_found': len(stale_notes),
|
|
'notifications_sent': notifications_sent,
|
|
'timestamp': timezone.now().isoformat(),
|
|
}
|
|
|
|
|
|
@shared_task
|
|
def remind_pending_contributions():
|
|
"""
|
|
Daily task to remind contributors about pending contributions.
|
|
Runs every day at 10:00 AM.
|
|
"""
|
|
# Get notes in draft or pending approval with non-final contributions
|
|
notes_with_pending = MDTNote.objects.filter(
|
|
status__in=[MDTNote.Status.DRAFT, MDTNote.Status.PENDING_APPROVAL],
|
|
contributions__is_final=False
|
|
).distinct()
|
|
|
|
total_reminders = 0
|
|
|
|
for note in notes_with_pending:
|
|
reminders = MDTWorkflowService.remind_pending_contributors(note)
|
|
total_reminders += reminders
|
|
|
|
return {
|
|
'task': 'remind_pending_contributions',
|
|
'notes_checked': notes_with_pending.count(),
|
|
'reminders_sent': total_reminders,
|
|
'timestamp': timezone.now().isoformat(),
|
|
}
|
|
|
|
|
|
@shared_task
|
|
def remind_pending_approvals():
|
|
"""
|
|
Daily task to remind approvers about pending approvals.
|
|
Runs every day at 11:00 AM.
|
|
"""
|
|
# Get notes pending approval
|
|
notes_pending_approval = MDTNote.objects.filter(
|
|
status=MDTNote.Status.PENDING_APPROVAL
|
|
)
|
|
|
|
total_reminders = 0
|
|
|
|
for note in notes_pending_approval:
|
|
reminders = MDTWorkflowService.remind_pending_approvers(note)
|
|
total_reminders += reminders
|
|
|
|
return {
|
|
'task': 'remind_pending_approvals',
|
|
'notes_checked': notes_pending_approval.count(),
|
|
'reminders_sent': total_reminders,
|
|
'timestamp': timezone.now().isoformat(),
|
|
}
|
|
|
|
|
|
@shared_task
|
|
def auto_finalize_ready_notes():
|
|
"""
|
|
Hourly task to auto-finalize notes that meet requirements.
|
|
Runs every hour.
|
|
"""
|
|
# Get notes pending approval that might be ready
|
|
notes_pending = MDTNote.objects.filter(
|
|
status=MDTNote.Status.PENDING_APPROVAL
|
|
)
|
|
|
|
finalized_count = 0
|
|
|
|
for note in notes_pending:
|
|
if MDTWorkflowService.check_and_auto_finalize(note):
|
|
finalized_count += 1
|
|
|
|
return {
|
|
'task': 'auto_finalize_ready_notes',
|
|
'notes_checked': notes_pending.count(),
|
|
'notes_finalized': finalized_count,
|
|
'timestamp': timezone.now().isoformat(),
|
|
}
|
|
|
|
|
|
@shared_task
|
|
def generate_weekly_mdt_summary():
|
|
"""
|
|
Weekly task to generate MDT statistics summary.
|
|
Runs every Monday at 8:00 AM.
|
|
"""
|
|
from core.models import Tenant
|
|
|
|
summaries_generated = 0
|
|
|
|
for tenant in Tenant.objects.filter(is_active=True):
|
|
# Get statistics for the past week
|
|
stats = MDTStatisticsService.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 MDT Summary:
|
|
- Total Notes: {stats['total_notes']}
|
|
- Draft: {stats['draft_notes']}
|
|
- Pending Approval: {stats['pending_approval']}
|
|
- Finalized: {stats['finalized_notes']}
|
|
- Total Contributions: {stats['total_contributions']}
|
|
- Unique Contributors: {stats['unique_contributors']}
|
|
- Departments Involved: {stats['departments_involved']}
|
|
""".strip()
|
|
|
|
Notification.objects.create(
|
|
user=coordinator,
|
|
notification_type='WEEKLY_SUMMARY',
|
|
title=f"Weekly MDT Summary",
|
|
message=message,
|
|
)
|
|
summaries_generated += 1
|
|
|
|
return {
|
|
'task': 'generate_weekly_mdt_summary',
|
|
'summaries_generated': summaries_generated,
|
|
'timestamp': timezone.now().isoformat(),
|
|
}
|
|
|
|
|
|
@shared_task
|
|
def notify_unread_mentions():
|
|
"""
|
|
Daily task to remind users about unread mentions.
|
|
Runs every day at 4:00 PM.
|
|
"""
|
|
# Get unread mentions older than 24 hours
|
|
cutoff_time = timezone.now() - timedelta(hours=24)
|
|
|
|
unread_mentions = MDTMention.objects.filter(
|
|
viewed_at__isnull=True,
|
|
created_at__lt=cutoff_time
|
|
).select_related('mentioned_user', 'contribution__mdt_note')
|
|
|
|
# Group by user
|
|
users_with_unread = {}
|
|
for mention in unread_mentions:
|
|
user = mention.mentioned_user
|
|
if user not in users_with_unread:
|
|
users_with_unread[user] = []
|
|
users_with_unread[user].append(mention)
|
|
|
|
notifications_sent = 0
|
|
|
|
for user, mentions in users_with_unread.items():
|
|
Notification.objects.create(
|
|
user=user,
|
|
notification_type='MDT_REMINDER',
|
|
title=f"Unread MDT Mentions",
|
|
message=f"You have {len(mentions)} unread mentions in MDT notes",
|
|
)
|
|
notifications_sent += 1
|
|
|
|
return {
|
|
'task': 'notify_unread_mentions',
|
|
'unread_mentions': unread_mentions.count(),
|
|
'users_notified': notifications_sent,
|
|
'timestamp': timezone.now().isoformat(),
|
|
}
|
|
|
|
|
|
@shared_task
|
|
def archive_old_finalized_notes():
|
|
"""
|
|
Monthly task to archive old finalized notes.
|
|
Runs on the 1st of each month at 2:00 AM.
|
|
"""
|
|
# Archive notes finalized more than 6 months ago
|
|
cutoff_date = timezone.now() - timedelta(days=180)
|
|
|
|
old_notes = MDTNote.objects.filter(
|
|
status=MDTNote.Status.FINALIZED,
|
|
finalized_at__lt=cutoff_date
|
|
)
|
|
|
|
archived_count = old_notes.update(status=MDTNote.Status.ARCHIVED)
|
|
|
|
return {
|
|
'task': 'archive_old_finalized_notes',
|
|
'notes_archived': archived_count,
|
|
'cutoff_date': cutoff_date.isoformat(),
|
|
'timestamp': timezone.now().isoformat(),
|
|
}
|