agdar/mdt/tasks.py
Marwan Alwali 2f1681b18c update
2025-11-11 13:44:48 +03:00

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(),
}