diff --git a/SAS/TMSS/backend/src/tmss/tmssapp/adapters/reports.py b/SAS/TMSS/backend/src/tmss/tmssapp/adapters/reports.py index f4569ce40a22a15bef1212ae0b95b11c215136bd..3e4b6698a77f2c7a0abd49bf5504ad5a3643c87a 100644 --- a/SAS/TMSS/backend/src/tmss/tmssapp/adapters/reports.py +++ b/SAS/TMSS/backend/src/tmss/tmssapp/adapters/reports.py @@ -5,6 +5,7 @@ from lofar.sas.tmss.tmss.tmssapp import serializers from rest_framework.request import Request from datetime import timedelta +# Cycle Report def create_cycle_report(request: Request, cycle: models.Cycle) -> {}: """ @@ -26,32 +27,35 @@ def create_cycle_report(request: Request, cycle: models.Cycle) -> {}: def _get_telescope_time_distribution(cycle: models.Cycle): - # TODO: Check if these are the states we want to include. - categories = models.ProjectCategory.Choices + """ + Help function to retrieve telescope time distribution info. + """ result = {} # ProjectCategories - for c in categories: + for c in models.ProjectCategory.Choices: + total, succeeded, failed = 0, 0, 0 projects = models.Project.objects.filter(cycles=cycle, project_category=c.value) - succeeded, failed = 0, 0 for p in projects: - subs = models.SchedulingUnitBlueprint.objects.filter(draft__scheduling_set__project__pk=p.pk) - for sub in subs: - succeeded += sub.status if sub.status == 'finished' else 0 - failed += sub.status if sub.status == 'cancelled' else 0 - # TODO: Calculate idle. - result[c.name] = {'durations': {'succeeded': succeeded, 'failed': failed, 'idle': 0}} + # Get durations for single project and aggregate to get the totals + _, durations = _get_subs_and_durations_from_project(p) + total += durations['total'] + succeeded += durations['total_succeeded'] + failed += durations['total_failed'] + idle = total - succeeded - failed + result[c.name] = {'durations': {'total': total, 'succeeded': succeeded, 'failed': failed, 'idle': idle}} # Filler - succeeded, failed = 0, 0 + total, succeeded, failed = 0, 0, 0 projects = models.Project.objects.filter(cycles=cycle, filler=True) for p in projects: - subs = models.SchedulingUnitBlueprint.objects.filter(draft__scheduling_set__project__pk=p.pk) - for sub in subs: - succeeded += sub.status if sub.status == 'finished' else 0 - failed += sub.status if sub.status == 'cancelled' else 0 - # TODO: Calculate idle. - result['FILLER'] = {'durations': {'succeeded': succeeded, 'failed': failed, 'idle': 0}} + # Get durations for single project and aggregate to get the totals + _, durations = _get_subs_and_durations_from_project(p) + total += durations['total'] + succeeded += durations['total_succeeded'] + failed += durations['total_failed'] + idle = total - succeeded - failed + result['FILLER'] = {'durations': {'total': total, 'succeeded': succeeded, 'failed': failed, 'idle': idle}} return result @@ -65,32 +69,26 @@ def _get_completion_level(cycle: models.Cycle): def _get_observation_hours_per_category(cycle: models.Cycle): + """ + Help function to retrieve observation hours per category info. + """ # TODO: Better define system unavailability and idle values. - result = {} - result['total_duration_A'], result['total_duration_B'], result['total_duration_failed'], result['total_duration_idle'] \ - = timedelta(), timedelta(), timedelta(), timedelta() - - # Get SUBs within prio A - subs_A = models.SchedulingUnitBlueprint.objects.filter(draft__scheduling_set__project__cycles=cycle.pk).filter(priority_queue='A') - for sub in subs_A: - if sub.status == 'finished': - result['total_duration_A'] += sub.duration - if sub.status == 'cancelled': - result['total_duration_failed'] += sub.duration - result['total_duration_idle'] += sub.duration # TODO: Need to subtract other states. - # Get SUBs within prio B - subs_B = models.SchedulingUnitBlueprint.objects.filter(draft__scheduling_set__project__cycles=cycle.pk).filter(priority_queue='B') - for sub in subs_B: - if sub.status == 'finished': - result['total_duration_B'] += sub.duration - if sub.status == 'cancelled': - result['total_duration_failed'] += sub.duration - result['total_duration_idle'] += sub.duration # TODO: Need to subtract other states. - - result['total_duration_A'] = result['total_duration_A'].total_seconds() - result['total_duration_B'] = result['total_duration_B'].total_seconds() - result['total_duration_failed'] = result['total_duration_failed'].total_seconds() - result['total_duration_idle'] = result['total_duration_idle'].total_seconds() + result = {'total_duration_failed': 0, 'total_duration_idle': 0} + + # Filter durations for each prio. basing on SUBs states + for prio in models.PriorityQueueType.Choices: + result[f'total_duration_{prio.name}'] = 0 + subs = models.SchedulingUnitBlueprint.objects.filter(draft__scheduling_set__project__cycles=cycle.pk).filter(priority_queue=prio.value) + for sub in subs: + result['total_duration_idle'] += sub.duration.total_seconds() + if sub.status == 'finished': + result[f'total_duration_{prio.name}'] += sub.duration.total_seconds() + if sub.status == 'cancelled': + result['total_duration_failed'] += sub.duration.total_seconds() + # Subtract prio states from total to get partial idle + result['total_duration_idle'] -= result[f'total_duration_{prio.name}'] + # Subtract total failed to get total idle eventually + result['total_duration_idle'] -= result['total_duration_failed'] return result @@ -104,9 +102,9 @@ def _get_data_ingested_per_site_and_category(cycle: models.Cycle): def _get_projects_summary(request: Request, cycle: models.Cycle): - ''' + """ Help function to retrieve projects info. - ''' + """ projects_summary = [] # Get Projects related to the Cycle projects = models.Project.objects.filter(cycles=cycle) @@ -125,6 +123,8 @@ def _get_failures(cycle: models.Cycle): return 0 +#Project Report + def create_project_report(request: Request, project: models.Project) -> {}: """ Create a project report as a JSON object.