HH/apps/reports/tasks.py
2026-04-08 17:13:35 +03:00

120 lines
4.0 KiB
Python

import logging
from celery import shared_task
from django.utils import timezone
logger = logging.getLogger(__name__)
@shared_task
def process_scheduled_reports():
from apps.reports.models import ReportSchedule
now = timezone.now()
schedules = ReportSchedule.objects.filter(
is_active=True,
next_run_at__lte=now,
).select_related("report")
dispatched = 0
for schedule in schedules:
generate_and_deliver_report.delay(str(schedule.id))
dispatched += 1
logger.info(f"Dispatched {dispatched} scheduled reports")
return {"dispatched": dispatched}
@shared_task
def generate_and_deliver_report(schedule_id):
from apps.reports.models import ReportSchedule, GeneratedReport
from apps.reports.services import ReportBuilderService
from apps.notifications.services import NotificationService
try:
schedule = ReportSchedule.objects.select_related("report").get(id=schedule_id)
except ReportSchedule.DoesNotExist:
logger.error(f"ReportSchedule {schedule_id} not found")
return {"status": "error", "reason": "not_found"}
try:
report = schedule.report
report_data = ReportBuilderService.generate_report_data(
data_source=report.data_source,
filter_config=report.filter_config,
column_config=report.column_config,
grouping_config=report.grouping_config,
sort_config=report.sort_config,
)
summary = ReportBuilderService.generate_summary(
data_source=report.data_source,
filter_config=report.filter_config,
)
row_count = len(report_data.get("rows", []))
generated = GeneratedReport.objects.create(
saved_report=report,
name=report.name,
data_source=report.data_source,
filter_config=report.filter_config,
column_config=report.column_config,
grouping_config=report.grouping_config,
chart_config=report.chart_config,
data=report_data,
summary=summary,
chart_data={},
row_count=row_count,
hospital=report.hospital,
)
report.last_run_at = timezone.now()
report.last_run_count = row_count
report.save(update_fields=["last_run_at", "last_run_count"])
schedule.last_run_at = timezone.now()
schedule.last_error = ""
next_run = schedule.calculate_next_run()
if schedule.frequency == "once":
schedule.is_active = False
schedule.next_run_at = None
else:
schedule.next_run_at = next_run
schedule.save(update_fields=["last_run_at", "next_run_at", "is_active", "last_error"])
subject = f"Scheduled Report: {report.name}"
message = (
f"Report: {report.name}\n"
f"Data Source: {report.get_data_source_display()}\n"
f"Rows: {row_count}\n"
f"Generated: {timezone.now().strftime('%Y-%m-%d %H:%M')}\n\n"
f"View the full report in the PX360 dashboard."
)
for recipient in schedule.recipients:
try:
NotificationService.send_email(
email=recipient,
subject=subject,
message=message,
related_object=generated,
notification_type="report",
)
except Exception as email_err:
logger.error(f"Failed to send report email to {recipient}: {email_err}")
logger.info(f"Generated and delivered report for schedule {schedule_id}")
return {"status": "success", "generated_report_id": str(generated.id), "row_count": row_count}
except Exception as e:
error_msg = str(e)
logger.error(f"Error generating report for schedule {schedule_id}: {error_msg}", exc_info=True)
schedule.last_error = error_msg
schedule.save(update_fields=["last_error"])
return {"status": "error", "reason": error_msg}