diff --git a/SAS/TMSS/src/tmss/tmssapp/models/specification.py b/SAS/TMSS/src/tmss/tmssapp/models/specification.py index 4335bd06c161cecc4308e5d50c6be1ec57421ebb..56cc5c2d4a119809db76c0a27960be3613cc3650 100644 --- a/SAS/TMSS/src/tmss/tmssapp/models/specification.py +++ b/SAS/TMSS/src/tmss/tmssapp/models/specification.py @@ -12,6 +12,7 @@ from django.db.models.deletion import ProtectedError from lofar.sas.tmss.tmss.tmssapp.validation import validate_json_against_schema from django.core.exceptions import ValidationError from rest_framework import status +import datetime # # Common @@ -303,6 +304,38 @@ class SchedulingUnitDraft(NamedCommon): super().save(force_insert, force_update, using, update_fields) + @property + def duration(self) -> float or None: + '''return the overall duration in seconds of all tasks of this scheduling unit + ''' + if self.start_time is None or self.stop_time is None: + # todo: calculate? + return None + else: + return (self.stop_time - self.start_time).total_seconds() + + @property + def start_time(self) -> datetime or None: + '''return the earliest start time of all tasks of this scheduling unit + ''' + tasks_with_start_time = list(filter(lambda x: x.start_time is not None, self.task_drafts.all())) + if tasks_with_start_time: + return min(tasks_with_start_time, key=lambda x: x.start_time).start_time + else: + # todo: calculate? + return None + + @property + def stop_time(self) -> datetime or None: + '''return the latest end time of all tasks of this scheduling unit + ''' + tasks_with_stop_time = list(filter(lambda x: x.stop_time is not None, self.task_drafts.all())) + if tasks_with_stop_time: + return max(tasks_with_stop_time, key=lambda x: x.stop_time).stop_time + else: + # todo: calculate? + return None + class SchedulingUnitBlueprint(NamedCommon): requirements_doc = JSONField(help_text='Scheduling and/or quality requirements for this scheduling unit (IMMUTABLE).') @@ -316,6 +349,38 @@ class SchedulingUnitBlueprint(NamedCommon): super().save(force_insert, force_update, using, update_fields) + @property + def duration(self) -> float or None: + '''return the overall duration in seconds of all tasks of this scheduling unit + ''' + if self.start_time is None or self.stop_time is None: + # todo: calculate? + return None + else: + return (self.stop_time - self.start_time).total_seconds() + + @property + def start_time(self) -> datetime or None: + '''return the earliest start time of all tasks of this scheduling unit + ''' + tasks_with_start_time = list(filter(lambda x: x.start_time is not None, self.task_blueprints.all())) + if tasks_with_start_time: + return min(tasks_with_start_time, key=lambda x: x.start_time).start_time + else: + # todo: calculate? + return None + + @property + def stop_time(self) -> datetime or None: + '''return the latest end time of all tasks of this scheduling unit + ''' + tasks_with_stop_time = list(filter(lambda x: x.stop_time is not None, self.task_blueprints.all())) + if tasks_with_stop_time: + return max(tasks_with_stop_time, key=lambda x: x.stop_time).stop_time + else: + # todo: calculate? + return None + class TaskDraft(NamedCommon): specifications_doc = JSONField(help_text='Specifications for this task.') @@ -350,6 +415,41 @@ class TaskDraft(NamedCommon): "INNER JOIN tmssapp_taskrelationdraft as task_rel on task_rel.producer_id = successor_task.id\n" "WHERE task_rel.consumer_id = %s", params=[self.id])) + @property + def duration(self) -> float or None: + '''returns the overall duration in seconds of all blueprints of this draft + # todo: is this the wanted behavior? Do you want to consider all the blueprints created from your draft or do you want to preview a new blueprint? + ''' + if self.start_time is None or self.stop_time is None: + # todo: calculate? + return None + else: + return (self.stop_time - self.start_time).total_seconds() + + @property + def start_time(self) -> datetime or None: + '''return the earliest start time of all blueprints of this draft + # todo: is this the wanted behavior? Do you want to consider all the blueprints created from your draft or do you want to preview a new blueprint? + ''' + blueprints_with_start_time = list(filter(lambda x: x.start_time is not None, self.task_blueprints.all())) + if blueprints_with_start_time: + return min(blueprints_with_start_time, key=lambda x: x.start_time).start_time + else: + # todo: calculate? + return None + + @property + def stop_time(self) -> datetime or None: + '''return the latest end time of all blueprints of this draft + # todo: is this the wanted behavior? Do you want to consider all the blueprints created from your draft or do you want to preview a new blueprint? + ''' + blueprints_with_stop_time = list(filter(lambda x: x.stop_time is not None, self.task_blueprints.all())) + if blueprints_with_stop_time: + return max(blueprints_with_stop_time, key=lambda x: x.stop_time).stop_time + else: + # todo: calculate? + return None + class TaskBlueprint(NamedCommon): specifications_doc = JSONField(help_text='Schedulings for this task (IMMUTABLE).') @@ -384,6 +484,39 @@ class TaskBlueprint(NamedCommon): "INNER JOIN tmssapp_taskrelationblueprint as task_rel on task_rel.producer_id = predecessor_task.id\n" "WHERE task_rel.consumer_id = %s", params=[self.id])) + @property + def duration(self) -> float or None: + '''return the overall duration in seconds of all subtasks of this task + ''' + if self.start_time is None or self.stop_time is None: + # todo: calculate? + return None + else: + return (self.stop_time - self.start_time).total_seconds() + + @property + def start_time(self) -> datetime or None: + '''return the earliest start time of all subtasks of this draft + ''' + subtasks_with_start_time = list(filter(lambda x: x.start_time is not None, self.subtasks.all())) + if subtasks_with_start_time: + return min(subtasks_with_start_time, key=lambda x: x.start_time).start_time + else: + # todo: calculate? + return None + + + @property + def stop_time(self) -> datetime or None: + '''return the latest end time of all subtasks of this draft + ''' + subtasks_with_stop_time = list(filter(lambda x: x.stop_time is not None, self.subtasks.all())) + if subtasks_with_stop_time: + return max(subtasks_with_stop_time, key=lambda x: x.stop_time).stop_time + else: + # todo: calculate? + return None + class TaskRelationDraft(BasicCommon): selection_doc = JSONField(help_text='Filter for selecting dataproducts from the output role.') diff --git a/SAS/TMSS/src/tmss/tmssapp/serializers/specification.py b/SAS/TMSS/src/tmss/tmssapp/serializers/specification.py index 90152f462b3a860e144bb87a210f1c3a3c01bbdc..57279ca894684e98af64ad6a9c642c8a2f362de0 100644 --- a/SAS/TMSS/src/tmss/tmssapp/serializers/specification.py +++ b/SAS/TMSS/src/tmss/tmssapp/serializers/specification.py @@ -243,7 +243,7 @@ class SchedulingUnitDraftSerializer(RelationalHyperlinkedModelSerializer): class Meta: model = models.SchedulingUnitDraft fields = '__all__' - extra_fields = ['scheduling_unit_blueprints', 'task_drafts'] + extra_fields = ['scheduling_unit_blueprints', 'task_drafts', 'duration', 'start_time', 'stop_time'] class SchedulingUnitBlueprintSerializer(RelationalHyperlinkedModelSerializer): @@ -260,7 +260,7 @@ class SchedulingUnitBlueprintSerializer(RelationalHyperlinkedModelSerializer): class Meta: model = models.SchedulingUnitBlueprint fields = '__all__' - extra_fields = ['task_blueprints'] + extra_fields = ['task_blueprints', 'duration', 'start_time', 'stop_time'] class TaskDraftSerializer(RelationalHyperlinkedModelSerializer): @@ -277,7 +277,7 @@ class TaskDraftSerializer(RelationalHyperlinkedModelSerializer): class Meta: model = models.TaskDraft fields = '__all__' - extra_fields = ['task_blueprints', 'produced_by', 'consumed_by', 'first_to_connect', 'second_to_connect'] + extra_fields = ['task_blueprints', 'produced_by', 'consumed_by', 'first_to_connect', 'second_to_connect', 'duration', 'start_time', 'stop_time'] class TaskBlueprintSerializer(RelationalHyperlinkedModelSerializer): @@ -294,7 +294,7 @@ class TaskBlueprintSerializer(RelationalHyperlinkedModelSerializer): class Meta: model = models.TaskBlueprint fields = '__all__' - extra_fields = ['subtasks', 'produced_by', 'consumed_by', 'first_to_connect', 'second_to_connect'] + extra_fields = ['subtasks', 'produced_by', 'consumed_by', 'first_to_connect', 'second_to_connect', 'duration', 'start_time', 'stop_time'] class TaskRelationDraftSerializer(RelationalHyperlinkedModelSerializer):