diff --git a/SAS/TMSS/backend/services/scheduling/lib/constraints/__init__.py b/SAS/TMSS/backend/services/scheduling/lib/constraints/__init__.py
index 85e452ae48330a0ca82348f8dddf3805ce34ae2f..783dd86c11c1187042cc3fa490753338f77aff1a 100644
--- a/SAS/TMSS/backend/services/scheduling/lib/constraints/__init__.py
+++ b/SAS/TMSS/backend/services/scheduling/lib/constraints/__init__.py
@@ -68,7 +68,7 @@ def filter_scheduling_units_using_constraints(scheduling_units: [models.Scheduli
 
     for scheduling_unit in scheduling_units:
         try:
-            if scheduling_unit.draft is None or scheduling_unit.draft.scheduling_constraints_template is None:
+            if scheduling_unit.draft is None or scheduling_unit.scheduling_constraints_template is None:
                 logger.warning("cannot dynamically schedule scheduling_unit id=%s name='%s' because it has not constraints template", scheduling_unit.id, scheduling_unit.name)
                 continue
 
@@ -168,7 +168,7 @@ def sort_scheduling_units_scored_by_constraints(scheduling_units: [models.Schedu
 
 def can_run_within_timewindow(scheduling_unit: models.SchedulingUnitBlueprint, lower_bound: datetime, upper_bound: datetime) -> bool:
     '''Check if the given scheduling_unit can run somewhere within the given time window depending on the sub's constrains-template/doc.'''
-    constraints_template = scheduling_unit.draft.scheduling_constraints_template
+    constraints_template = scheduling_unit.scheduling_constraints_template
 
     # choose appropriate method based on template (strategy pattern), or raise
     if constraints_template.name == 'constraints' and constraints_template.version == 1:
@@ -184,7 +184,7 @@ def can_run_within_timewindow(scheduling_unit: models.SchedulingUnitBlueprint, l
 
 def can_run_after(scheduling_unit: models.SchedulingUnitBlueprint, lower_bound: datetime) -> bool:
     '''Check if the given scheduling_unit can run somewhere after the given lowerbound timestamp depending on the sub's constrains-template/doc.'''
-    constraints_template = scheduling_unit.draft.scheduling_constraints_template
+    constraints_template = scheduling_unit.scheduling_constraints_template
 
     # choose appropriate method based on template (strategy pattern), or raise
     if constraints_template.name == 'constraints' and constraints_template.version == 1:
@@ -201,7 +201,7 @@ def can_run_after(scheduling_unit: models.SchedulingUnitBlueprint, lower_bound:
 
 def compute_scores(scheduling_unit: models.SchedulingUnitBlueprint, lower_bound:datetime, upper_bound:datetime) -> ScoredSchedulingUnit:
     '''Compute the "fitness" scores per constraint for the given scheduling_unit at the given starttime depending on the sub's constrains-template/doc.'''
-    constraints_template = scheduling_unit.draft.scheduling_constraints_template
+    constraints_template = scheduling_unit.scheduling_constraints_template
 
     # choose appropriate method based on template (strategy pattern), or raise
     if constraints_template.name == 'constraints' and constraints_template.version == 1:
@@ -217,7 +217,7 @@ def compute_scores(scheduling_unit: models.SchedulingUnitBlueprint, lower_bound:
 
 def get_earliest_possible_start_time(scheduling_unit: models.SchedulingUnitBlueprint, lower_bound: datetime) -> datetime:
     '''determine the earliest possible start_time for the given scheduling unit, taking into account all its constraints'''
-    constraints_template = scheduling_unit.draft.scheduling_constraints_template
+    constraints_template = scheduling_unit.scheduling_constraints_template
 
     # choose appropriate method based on template (strategy pattern), or raise
     if constraints_template.name == 'constraints' and constraints_template.version == 1:
@@ -234,7 +234,7 @@ def get_earliest_possible_start_time(scheduling_unit: models.SchedulingUnitBluep
 def get_min_earliest_possible_start_time(scheduling_units: [models.SchedulingUnitBlueprint], lower_bound: datetime) -> datetime:
     '''deterimine the earliest possible starttime over all given scheduling units, taking into account all their constraints'''
     try:
-        return min(get_earliest_possible_start_time(scheduling_unit, lower_bound) for scheduling_unit in scheduling_units if scheduling_unit.draft.scheduling_constraints_template is not None)
+        return min(get_earliest_possible_start_time(scheduling_unit, lower_bound) for scheduling_unit in scheduling_units if scheduling_unit.scheduling_constraints_template is not None)
     except ValueError:
         return lower_bound
 
diff --git a/SAS/TMSS/backend/services/scheduling/lib/constraints/template_constraints_v1.py b/SAS/TMSS/backend/services/scheduling/lib/constraints/template_constraints_v1.py
index 594c088ecd651b9b9e7982df30a9e88b81526903..342b727554e0c3a5ca3212ab4008f8ecd116e752 100644
--- a/SAS/TMSS/backend/services/scheduling/lib/constraints/template_constraints_v1.py
+++ b/SAS/TMSS/backend/services/scheduling/lib/constraints/template_constraints_v1.py
@@ -33,7 +33,7 @@ from astropy.coordinates import Angle
 import astropy.units
 
 from lofar.sas.tmss.tmss.tmssapp import models
-from lofar.sas.tmss.tmss.tmssapp.conversions import create_astroplan_observer_for_station, Time, timestamps_and_stations_to_sun_rise_and_set, coordinates_and_timestamps_to_separation_from_bodies, coordinates_timestamps_and_stations_to_target_rise_and_set
+from lofar.sas.tmss.tmss.tmssapp.conversions import create_astroplan_observer_for_station, Time, timestamps_and_stations_to_sun_rise_and_set, coordinates_and_timestamps_to_separation_from_bodies, coordinates_timestamps_and_stations_to_target_rise_and_set, coordinates_timestamps_and_stations_to_target_transit, local_sidereal_time_for_utc_and_station
 from lofar.sas.tmss.tmss.exceptions import TMSSException
 
 from . import ScoredSchedulingUnit
@@ -61,7 +61,7 @@ def can_run_within_timewindow(scheduling_unit: models.SchedulingUnitBlueprint, l
 
 def can_run_after(scheduling_unit: models.SchedulingUnitBlueprint, lower_bound: datetime) -> bool:
     '''Check if the given scheduling_unit can run somewhere after the given lowerbound timestamp depending on the sub's constrains-template/doc.'''
-    constraints = scheduling_unit.draft.scheduling_constraints_doc
+    constraints = scheduling_unit.scheduling_constraints_doc
     if 'before' in constraints['time']:
         before = parser.parse(constraints['time']['before'], ignoretz=True)
         return before > lower_bound
@@ -74,7 +74,7 @@ __all__ = ['can_run_within_timewindow', 'can_run_after']
 
 def has_manual_scheduler_constraint(scheduling_unit: models.SchedulingUnitBlueprint) -> bool:
     '''evaluate the scheduler contraint. Should this unit be manually scheduled?'''
-    constraints = scheduling_unit.draft.scheduling_constraints_doc
+    constraints = scheduling_unit.scheduling_constraints_doc
     return constraints.get('scheduler', '') == 'manual'
 
 
@@ -101,7 +101,7 @@ def can_run_anywhere_within_timewindow_with_daily_constraints(scheduling_unit: m
     :return: True if all daily constraints are met over the entire time window, else False.
     """
     main_observation_task_name = get_target_observation_task_name_from_requirements_doc(scheduling_unit)
-    constraints = scheduling_unit.draft.scheduling_constraints_doc
+    constraints = scheduling_unit.scheduling_constraints_doc
     if constraints['daily']['require_day'] or constraints['daily']['require_night'] or constraints['daily']['avoid_twilight']:
 
         if (upper_bound - lower_bound).days >= 1:
@@ -158,7 +158,7 @@ def can_run_within_timewindow_with_time_constraints(scheduling_unit: models.Sche
              constraints are met over the runtime of the observation, else False.
     """
     main_observation_task_name = get_target_observation_task_name_from_requirements_doc(scheduling_unit)
-    constraints = scheduling_unit.draft.scheduling_constraints_doc
+    constraints = scheduling_unit.scheduling_constraints_doc
 
     # Check the 'at' constraint and then only check can_run_anywhere for the single possible time window
     if 'at' in constraints['time']:
@@ -189,7 +189,7 @@ def can_run_anywhere_within_timewindow_with_time_constraints(scheduling_unit: mo
     can_run_with_after = True
     can_run_between = True
     can_run_not_between = True
-    constraints = scheduling_unit.draft.scheduling_constraints_doc
+    constraints = scheduling_unit.scheduling_constraints_doc
 
     # given time window needs to end before constraint
     if 'before' in constraints['time']:
@@ -254,7 +254,7 @@ def can_run_anywhere_within_timewindow_with_sky_constraints(scheduling_unit: mod
     # TODO: remove this shortcut after demo
     return True
 
-    constraints = scheduling_unit.draft.scheduling_constraints_doc
+    constraints = scheduling_unit.scheduling_constraints_doc
     if not "sky" in constraints:
         return True
 
@@ -265,7 +265,6 @@ def can_run_anywhere_within_timewindow_with_sky_constraints(scheduling_unit: mod
                 angle1 = beam['angle1']
                 angle2 = beam['angle2']
                 direction_type = beam['direction_type']
-
                 if 'min_distance' in constraints['sky']:
                     # currently we only check at bounds, we probably want to add some more samples in between later on
                     distances = coordinates_and_timestamps_to_separation_from_bodies(angle1=angle1, angle2=angle2, direction_type=direction_type, timestamps=(lower_bound, upper_bound), bodies=tuple(constraints['sky']['min_distance'].keys()))
@@ -299,6 +298,81 @@ def can_run_anywhere_within_timewindow_with_sky_constraints(scheduling_unit: mod
                                 else:
                                     logger.info('min_target_elevation=%s constraint is not met at timestamp=%s' % (min_elevation.rad, timestamps[i]))
                                 return False
+                if 'transit_offset' in constraints['sky'] and 'from' in constraints['sky']['transit_offset'] and task['specifications_template'] == 'target observation':
+                    # Check constraint on tile beam for HBA only:
+                    if task['specifications_doc']['antenna_set'].startswith('HBA'):
+                        # since the constraint only applies to the middle of the obs, consider its duration
+                        if 'duration' in task['specifications_doc']:
+                            duration = timedelta(seconds=task['specifications_doc']['duration'])
+                            timestamps = (lower_bound + 0.5 * duration, upper_bound - 0.5 * duration)
+                        else:
+                            timestamps = (lower_bound, upper_bound)
+                        station_groups = task['specifications_doc']['station_groups']
+                        stations = list(set(sum([group['stations'] for group in station_groups], [])))  # flatten all station_groups to single list
+                        transit_times = coordinates_timestamps_and_stations_to_target_transit(angle1=angle1, angle2=angle2, direction_type=direction_type, timestamps=timestamps, stations=tuple(stations))
+                        for station, times in transit_times.items():
+                            for i in range(len(timestamps)):
+                                offset = (timestamps[i] - times[i]).total_seconds()
+                                offset_from = constraints['sky']['transit_offset']['from']
+                                offset_to = constraints['sky']['transit_offset']['to']
+                                # because the constraint allows specifying a window that reaches past 12h from transit,
+                                # the transit that it refers to may not be the nearest transit to the observation time.
+                                # Hence we also check if the constraint is met with 24h shift (which is approximately
+                                # equivalent to checking the constraint for the previous or next transit)
+                                if not ((offset_from < offset < offset_to) or
+                                        (offset_from+86400 < offset < offset_to+86400) or
+                                        (offset_from-86400 < offset < offset_to-86400)):
+                                    logger.info('transit_offset constraint from=%s to=%s is not met by offset=%s at timestamp=%s' % (offset_from, offset_to, offset, timestamps[i]))
+                                    return False
+
+            if 'SAPs' in task['specifications_doc']:
+                if 'transit_offset' in constraints['sky']  and 'from' in constraints['sky']['transit_offset'] and task['specifications_template'] == 'target observation':
+                    # Check constraint on SAPs for LBA only:
+                    if task['specifications_doc']['antenna_set'].startswith('LBA'):
+                        # since the constraint only applies to the middle of the obs, consider its duration
+                        if 'duration' in task['specifications_doc']:
+                            duration = timedelta(seconds=task['specifications_doc']['duration'])
+                            timestamps = (lower_bound + 0.5 * duration, upper_bound - 0.5 * duration)
+                        else:
+                            timestamps = (lower_bound, upper_bound)
+
+                        # for LBA get transit times for all SAPs...
+                        sap_transit_times = []
+                        station_groups = task['specifications_doc']['station_groups']
+                        stations = list(set(sum([group['stations'] for group in station_groups], [])))  # flatten all station_groups to single list
+                        for sap in task['specifications_doc']['SAPs']:
+                            angle1 = sap['digital_pointing']['angle1']
+                            angle2 = sap['digital_pointing']['angle2']
+                            direction_type = sap['digital_pointing']['direction_type']
+                            sap_transit_times.append(coordinates_timestamps_and_stations_to_target_transit(angle1=angle1, angle2=angle2, direction_type=direction_type, timestamps=timestamps, stations=tuple(stations)))
+
+                        # ...then for each station and timestamp, average the transit times we got for the different SAPs
+                        transit_times = {}
+                        _reference_date = datetime(1900, 1, 1)
+                        for station in stations:
+                            for j in range(len(timestamps)):
+                                sap_datetime_list = [sap_transit_times[i][station][j] for i in range(len(task['specifications_doc']['SAPs']))]
+                                average_transit_time = _reference_date + sum([date - _reference_date for date in sap_datetime_list], timedelta()) / len(sap_datetime_list)
+                                transit_times.get(station, []).append(average_transit_time)
+
+                        logger.warning('##### %s' % transit_times)
+
+                        for station, times in transit_times.items():
+                            for i in range(len(timestamps)):
+                                offset = (timestamps[i] - times[i]).total_seconds()
+                                offset_from = constraints['sky']['transit_offset']['from']
+                                offset_to = constraints['sky']['transit_offset']['to']
+                                # because the constraint allows specifying a window that reaches past 12h from transit,
+                                # the transit that it refers to may not be the nearest transit to the observation time.
+                                # Hence we also check if the constraint is met with 24h shift (which is approximately
+                                # equivalent to checking the constraint for the previous or next transit)
+                                if not ((offset_from < offset < offset_to) or
+                                        (offset_from+86400 < offset < offset_to+86400) or
+                                        (offset_from-86400 < offset < offset_to-86400)):
+                                    logger.info('transit_offset constraint from=%s to=%s is not met by offset=%s at timestamp=%s' % (offset_from, offset_to, offset, timestamps[i]))
+                                    return False
+
+
 
     return True
 
@@ -312,7 +386,7 @@ def get_target_observation_task_name_from_requirements_doc(scheduling_unit: mode
 
 
 def get_earliest_possible_start_time(scheduling_unit: models.SchedulingUnitBlueprint, lower_bound: datetime) -> datetime:
-    constraints = scheduling_unit.draft.scheduling_constraints_doc
+    constraints = scheduling_unit.scheduling_constraints_doc
 
     main_observation_task_name = get_target_observation_task_name_from_requirements_doc(scheduling_unit)
     duration = timedelta(seconds=scheduling_unit.requirements_doc['tasks'][main_observation_task_name]['specifications_doc']['duration'])
@@ -383,7 +457,7 @@ def get_earliest_possible_start_time(scheduling_unit: models.SchedulingUnitBluep
 
 def compute_scores(scheduling_unit: models.SchedulingUnitBlueprint, lower_bound:datetime, upper_bound:datetime) -> ScoredSchedulingUnit:
     '''Compute the "fitness" scores per constraint for the given scheduling_unit at the given starttime depending on the sub's constrains-template/doc.'''
-    constraints = scheduling_unit.draft.scheduling_constraints_doc
+    constraints = scheduling_unit.scheduling_constraints_doc
 
     # TODO: add compute_scores methods for each type of constraint
     # TODO: take start_time into account. For example, an LST constraint yields a better score when the starttime is such that the center of the obs is at LST.
diff --git a/SAS/TMSS/backend/services/scheduling/lib/dynamic_scheduling.py b/SAS/TMSS/backend/services/scheduling/lib/dynamic_scheduling.py
index 3b45ac16bd908ccd1a845b0b63876b4c2039b073..5ff4971b7f719615583eaf50ad3aaf5b86d27f92 100644
--- a/SAS/TMSS/backend/services/scheduling/lib/dynamic_scheduling.py
+++ b/SAS/TMSS/backend/services/scheduling/lib/dynamic_scheduling.py
@@ -298,8 +298,7 @@ def get_dynamically_schedulable_scheduling_units() -> [models.SchedulingUnitBlue
     defined_independend_subtasks = models.Subtask.independent_subtasks().filter(state__value='defined')
     defined_independend_subtask_ids = defined_independend_subtasks.values('task_blueprints__scheduling_unit_blueprint_id').distinct().all()
     scheduling_units = models.SchedulingUnitBlueprint.objects.filter(id__in=defined_independend_subtask_ids) \
-                                                             .filter(draft__scheduling_constraints_template__isnull=False) \
-                                                             .select_related('draft', 'draft__scheduling_constraints_template').all()
+                                                             .filter(scheduling_constraints_template__isnull=False).all()
     return [su for su in scheduling_units if su.status == 'schedulable']
 
 
diff --git a/SAS/TMSS/backend/services/scheduling/test/t_dynamic_scheduling.py b/SAS/TMSS/backend/services/scheduling/test/t_dynamic_scheduling.py
index 82bd9243e1897bd246367eb96ebb97f88dc927a5..59e644b4a882c4add00baa7b495fb95f41a524df 100755
--- a/SAS/TMSS/backend/services/scheduling/test/t_dynamic_scheduling.py
+++ b/SAS/TMSS/backend/services/scheduling/test/t_dynamic_scheduling.py
@@ -426,7 +426,7 @@ class TestDailyConstraints(TestCase):
     # require_day
 
     def test_get_earliest_possible_start_time_with_daytime_constraint_returns_day_start(self):
-        self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['daily']['require_day'] = True
+        self.scheduling_unit_blueprint.scheduling_constraints_doc['daily']['require_day'] = True
         self.scheduling_unit_blueprint.save()
         self.sunrise_mock.return_value = self.sunrise_data_early_night
         timestamp = datetime(2020, 1, 1, 4, 0, 0)
@@ -435,7 +435,7 @@ class TestDailyConstraints(TestCase):
 
     def test_get_earliest_possible_start_time_with_daytime_constraint_returns_day_start_of_latest_station(self):
         self.scheduling_unit_blueprint.requirements_doc['tasks']['Observation']['specifications_doc']['station_groups'] = [{'stations': ['CS001', 'DE601']}]
-        self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['daily']['require_day'] = True
+        self.scheduling_unit_blueprint.scheduling_constraints_doc['daily']['require_day'] = True
         self.scheduling_unit_blueprint.save()
         self.sunrise_mock.return_value = self.sunrise_data_early_night
         timestamp = datetime(2020, 1, 1, 4, 0, 0)
@@ -443,28 +443,28 @@ class TestDailyConstraints(TestCase):
         self.assertEqual(returned_time, self.sunrise_data['DE601']['day'][0]['start'])
 
     def test_get_earliest_possible_start_time_with_daytime_constraint_returns_timestamp(self):
-        self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['daily']['require_day'] = True
+        self.scheduling_unit_blueprint.scheduling_constraints_doc['daily']['require_day'] = True
         self.scheduling_unit_blueprint.save()
         timestamp = datetime(2020, 1, 1, 10, 0, 0)
         returned_time = get_earliest_possible_start_time(self.scheduling_unit_blueprint, timestamp)
         self.assertEqual(returned_time, timestamp)
 
     def test_get_earliest_possible_start_time_with_daytime_constraint_returns_next_day_start(self):
-        self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['daily']['require_day'] = True
+        self.scheduling_unit_blueprint.scheduling_constraints_doc['daily']['require_day'] = True
         self.scheduling_unit_blueprint.save()
         timestamp = datetime(2020, 1, 1, 20, 0, 0)
         returned_time = get_earliest_possible_start_time(self.scheduling_unit_blueprint, timestamp)
         self.assertEqual(returned_time, self.sunrise_data['CS001']['day'][1]['start'])
 
     def test_get_earliest_possible_start_time_with_daytime_constraint_returns_next_day_start_when_obs_does_not_fit(self):
-        self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['daily']['require_day'] = True
+        self.scheduling_unit_blueprint.scheduling_constraints_doc['daily']['require_day'] = True
         self.scheduling_unit_blueprint.save()
         timestamp = datetime(2020, 1, 1, 14, 0, 0)
         returned_time = get_earliest_possible_start_time(self.scheduling_unit_blueprint, timestamp)
         self.assertEqual(returned_time, self.sunrise_data['CS001']['day'][1]['start'])
 
     def test_can_run_anywhere_within_timewindow_with_daily_constraints_with_daytime_constraint_returns_true(self):
-        self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['daily']['require_day'] = True
+        self.scheduling_unit_blueprint.scheduling_constraints_doc['daily']['require_day'] = True
         self.scheduling_unit_blueprint.save()
 
         self.sunrise_mock.return_value = self.sunrise_data_late_night_late_night
@@ -473,7 +473,7 @@ class TestDailyConstraints(TestCase):
         self.assertTrue(tc1.can_run_anywhere_within_timewindow_with_daily_constraints(self.scheduling_unit_blueprint, lower_bound, upper_bound))
 
     def test_can_run_anywhere_within_timewindow_with_daily_constraints_with_daytime_constraint_returns_false_when_not_daytime(self):
-        self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['daily']['require_day'] = True
+        self.scheduling_unit_blueprint.scheduling_constraints_doc['daily']['require_day'] = True
         self.scheduling_unit_blueprint.save()
 
         self.sunrise_mock.return_value = self.sunrise_data_late_night_late_night
@@ -482,7 +482,7 @@ class TestDailyConstraints(TestCase):
         self.assertFalse(tc1.can_run_anywhere_within_timewindow_with_daily_constraints(self.scheduling_unit_blueprint, lower_bound, upper_bound))
 
     def test_can_run_anywhere_within_timewindow_with_daily_constraints_with_daytime_constraint_returns_false_when_partially_not_daytime(self):
-        self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['daily']['require_day'] = True
+        self.scheduling_unit_blueprint.scheduling_constraints_doc['daily']['require_day'] = True
         self.scheduling_unit_blueprint.save()
 
         self.sunrise_mock.return_value = self.sunrise_data_late_night_late_night
@@ -498,10 +498,10 @@ class TestDailyConstraints(TestCase):
     def test_can_run_within_timewindow_with_daytime_constraint_returns_correct_value(self):
         # todo: for time ranges across dates, consider removing the mock for this because the moving window cannot be easily mocked
         # remove other constraints:
-        self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['sky'] = {}
+        self.scheduling_unit_blueprint.scheduling_constraints_doc['sky'] = {}
 
         # set constraint to test
-        self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['daily']['require_day'] = True
+        self.scheduling_unit_blueprint.scheduling_constraints_doc['daily']['require_day'] = True
         self.scheduling_unit_blueprint.save()
 
         # can run in day
@@ -519,7 +519,7 @@ class TestDailyConstraints(TestCase):
     # require_night
 
     def test_get_earliest_possible_start_time_with_nighttime_constraint_returns_night_start(self):
-        self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['daily']['require_night'] = True
+        self.scheduling_unit_blueprint.scheduling_constraints_doc['daily']['require_night'] = True
         self.scheduling_unit_blueprint.save()
         timestamp = datetime(2020, 1, 1, 14, 0, 0)
         returned_time = get_earliest_possible_start_time(self.scheduling_unit_blueprint, timestamp)
@@ -527,14 +527,14 @@ class TestDailyConstraints(TestCase):
 
     def test_get_earliest_possible_start_time_with_nighttime_constraint_returns_night_start_of_latest_station(self):
         self.scheduling_unit_blueprint.requirements_doc['tasks']['Observation']['specifications_doc']['station_groups'] = [{'stations': ['CS001', 'DE601']}]
-        self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['daily']['require_night'] = True
+        self.scheduling_unit_blueprint.scheduling_constraints_doc['daily']['require_night'] = True
         self.scheduling_unit_blueprint.save()
         timestamp = datetime(2020, 1, 1, 14, 0, 0)
         returned_time = get_earliest_possible_start_time(self.scheduling_unit_blueprint, timestamp)
         self.assertEqual(returned_time, self.sunrise_data['DE601']['night'][0]['start'])
 
     def test_get_earliest_possible_start_time_with_nighttime_constraint_returns_timestamp(self):
-        self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['daily']['require_night'] = True
+        self.scheduling_unit_blueprint.scheduling_constraints_doc['daily']['require_night'] = True
         self.scheduling_unit_blueprint.save()
 
         # late night
@@ -549,7 +549,7 @@ class TestDailyConstraints(TestCase):
         self.assertEqual(returned_time, timestamp)
 
     def test_get_earliest_possible_start_time_with_nighttime_constraint_returns_next_night_start_when_obs_does_not_fit(self):
-        self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['daily']['require_night'] = True
+        self.scheduling_unit_blueprint.scheduling_constraints_doc['daily']['require_night'] = True
         self.scheduling_unit_blueprint.save()
 
         # early night
@@ -559,7 +559,7 @@ class TestDailyConstraints(TestCase):
         self.assertEqual(returned_time, self.sunrise_data_early_night['CS001']['night'][1]['start'])
 
     def test_can_run_anywhere_within_timewindow_with_daily_constraints_with_nighttime_constraint_returns_true(self):
-        self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['daily']['require_night'] = True
+        self.scheduling_unit_blueprint.scheduling_constraints_doc['daily']['require_night'] = True
         self.scheduling_unit_blueprint.save()
 
         # early night
@@ -581,7 +581,7 @@ class TestDailyConstraints(TestCase):
         self.assertTrue(tc1.can_run_anywhere_within_timewindow_with_daily_constraints(self.scheduling_unit_blueprint, lower_bound, upper_bound))
 
     def test_can_run_anywhere_within_timewindow_with_daily_constraints_with_nighttime_constraint_returns_false_when_not_nighttime(self):
-        self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['daily']['require_night'] = True
+        self.scheduling_unit_blueprint.scheduling_constraints_doc['daily']['require_night'] = True
         self.scheduling_unit_blueprint.save()
 
         self.sunrise_mock.return_value = self.sunrise_data_late_night_late_night
@@ -590,7 +590,7 @@ class TestDailyConstraints(TestCase):
         self.assertFalse(tc1.can_run_anywhere_within_timewindow_with_daily_constraints(self.scheduling_unit_blueprint, lower_bound, upper_bound))
 
     def test_can_run_anywhere_within_timewindow_with_daily_constraints_with_nighttime_constraint_returns_false_when_partially_not_nighttime(self):
-        self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['daily']['require_night'] = True
+        self.scheduling_unit_blueprint.scheduling_constraints_doc['daily']['require_night'] = True
         self.scheduling_unit_blueprint.save()
 
         # night-day next day
@@ -632,10 +632,10 @@ class TestDailyConstraints(TestCase):
     def test_can_run_within_timewindow_with_nighttime_constraint_returns_correct_value(self):
         # todo: for time ranges across dates, consider removing the mock for this because the moving window cannot be easily mocked
         # remove other constraints:
-        self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['sky'] = {}
+        self.scheduling_unit_blueprint.scheduling_constraints_doc['sky'] = {}
 
         # set constraint to test
-        self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['daily']['require_night'] = True
+        self.scheduling_unit_blueprint.scheduling_constraints_doc['daily']['require_night'] = True
         self.scheduling_unit_blueprint.save()
 
         # cannot run in day
@@ -654,7 +654,7 @@ class TestDailyConstraints(TestCase):
     # avoid_twilight
 
     def test_get_earliest_possible_start_time_with_twilight_constraint_returns_day_start(self):
-        self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['daily']['avoid_twilight'] = True
+        self.scheduling_unit_blueprint.scheduling_constraints_doc['daily']['avoid_twilight'] = True
         self.scheduling_unit_blueprint.save()
 
         self.sunrise_mock.return_value = self.sunrise_data_early_night
@@ -664,7 +664,7 @@ class TestDailyConstraints(TestCase):
 
     def test_get_earliest_possible_start_time_with_twilight_constraint_returns_day_start_of_latest_station(self):
         self.scheduling_unit_blueprint.requirements_doc['tasks']['Observation']['specifications_doc']['station_groups'] = [{'stations': ['CS001', 'DE601']}]
-        self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['daily']['avoid_twilight'] = True
+        self.scheduling_unit_blueprint.scheduling_constraints_doc['daily']['avoid_twilight'] = True
         self.scheduling_unit_blueprint.save()
 
         self.sunrise_mock.return_value = self.sunrise_data_early_night
@@ -673,7 +673,7 @@ class TestDailyConstraints(TestCase):
         self.assertEqual(returned_time, self.sunrise_data['DE601']['day'][0]['start'])
 
     def test_get_earliest_possible_start_time_with_twilight_constraint_returns_night_start(self):
-        self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['daily']['avoid_twilight'] = True
+        self.scheduling_unit_blueprint.scheduling_constraints_doc['daily']['avoid_twilight'] = True
         self.scheduling_unit_blueprint.save()
 
         self.sunrise_mock.return_value = self.sunrise_data
@@ -683,7 +683,7 @@ class TestDailyConstraints(TestCase):
 
     def test_get_earliest_possible_start_time_with_twilight_constraint_returns_night_start_of_latest_station(self):
         self.scheduling_unit_blueprint.requirements_doc['tasks']['Observation']['specifications_doc']['station_groups'] = [{'stations': ['CS001', 'DE601']}]
-        self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['daily']['avoid_twilight'] = True
+        self.scheduling_unit_blueprint.scheduling_constraints_doc['daily']['avoid_twilight'] = True
         self.scheduling_unit_blueprint.save()
 
         self.sunrise_mock.return_value = self.sunrise_data
@@ -692,7 +692,7 @@ class TestDailyConstraints(TestCase):
         self.assertEqual(returned_time, self.sunrise_data['DE601']['night'][0]['start'])
 
     def test_get_earliest_possible_start_time_with_twilight_constraint_returns_timestamp(self):
-        self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['daily']['avoid_twilight'] = True
+        self.scheduling_unit_blueprint.scheduling_constraints_doc['daily']['avoid_twilight'] = True
         self.scheduling_unit_blueprint.save()
 
         # daytime
@@ -712,7 +712,7 @@ class TestDailyConstraints(TestCase):
         self.assertEqual(returned_time, timestamp)
 
     def test_get_earliest_possible_start_time_with_twilight_constraint_returns_day_or_night_start_when_obs_does_not_fit(self):
-        self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['daily']['avoid_twilight'] = True
+        self.scheduling_unit_blueprint.scheduling_constraints_doc['daily']['avoid_twilight'] = True
         self.scheduling_unit_blueprint.save()
 
         timestamp = datetime(2020, 1, 1, 15, 0, 0)
@@ -725,7 +725,7 @@ class TestDailyConstraints(TestCase):
         self.assertEqual(returned_time, self.sunrise_data['CS001']['day'][0]['start'])
 
     def test_can_run_anywhere_within_timewindow_with_daily_constraints_with_twilight_constraint_returns_true(self):
-        self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['daily']['avoid_twilight'] = True
+        self.scheduling_unit_blueprint.scheduling_constraints_doc['daily']['avoid_twilight'] = True
         self.scheduling_unit_blueprint.save()
 
         self.sunrise_mock.return_value = self.sunrise_data_late_night_late_night
@@ -734,7 +734,7 @@ class TestDailyConstraints(TestCase):
         self.assertTrue(tc1.can_run_anywhere_within_timewindow_with_daily_constraints(self.scheduling_unit_blueprint, lower_bound, upper_bound))
 
     def test_can_run_anywhere_within_timewindow_with_daily_constraints_with_twilight_constraint_returns_false_when_in_twilight(self):
-        self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['daily']['avoid_twilight'] = True
+        self.scheduling_unit_blueprint.scheduling_constraints_doc['daily']['avoid_twilight'] = True
         self.scheduling_unit_blueprint.save()
 
         self.sunrise_mock.return_value = self.sunrise_data_late_night_late_night
@@ -748,7 +748,7 @@ class TestDailyConstraints(TestCase):
         self.assertFalse(tc1.can_run_anywhere_within_timewindow_with_daily_constraints(self.scheduling_unit_blueprint, lower_bound, upper_bound))
 
     def test_can_run_anywhere_within_timewindow_with_daily_constraints_with_twilight_constraint_returns_false_when_partially_in_twilight(self):
-        self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['daily']['avoid_twilight'] = True
+        self.scheduling_unit_blueprint.scheduling_constraints_doc['daily']['avoid_twilight'] = True
         self.scheduling_unit_blueprint.save()
 
         self.sunrise_mock.return_value = self.sunrise_data_late_night_late_night
@@ -764,10 +764,10 @@ class TestDailyConstraints(TestCase):
     def test_can_run_within_timewindow_with_twilight_constraint_returns_correct_value(self):
         # todo: for time ranges across dates, consider removing the mock for this because the moving window cannot be easily mocked
         # remove other constraints:
-        self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['sky'] = {}
+        self.scheduling_unit_blueprint.scheduling_constraints_doc['sky'] = {}
 
         # set constraint to test
-        self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['daily']['avoid_twilight'] = True
+        self.scheduling_unit_blueprint.scheduling_constraints_doc['daily']['avoid_twilight'] = True
         self.scheduling_unit_blueprint.save()
 
         # can run in day
@@ -812,23 +812,30 @@ class TestSkyConstraints(unittest.TestCase):
                                                    {"rise": datetime(2020, 1, 1, 8, 0, 0), "set": datetime(2020, 1, 1, 12, 30, 0), "always_above_horizon": False, "always_below_horizon": False}]}
         self.target_rise_and_set_data_always_above = {"CS002": [{"rise": None, "set": None, "always_above_horizon": True, "always_below_horizon": False}]}
         self.target_rise_and_set_data_always_below = {"CS002": [{"rise": None, "set": None, "always_above_horizon": False, "always_below_horizon": True}]}
-
         self.target_rise_and_set_patcher = mock.patch('lofar.sas.tmss.services.scheduling.constraints.template_constraints_v1.coordinates_timestamps_and_stations_to_target_rise_and_set')
         self.target_rise_and_set_mock = self.target_rise_and_set_patcher.start()
         self.target_rise_and_set_mock.return_value = self.target_rise_and_set_data
         self.addCleanup(self.target_rise_and_set_patcher.stop)
 
+        self.target_transit_data = {"CS002": [datetime(2020, 1, 1, 14, 0, 0), datetime(2020, 1, 1, 14, 0, 0)]}
+        self.target_transit_data_previous = {"CS002": [datetime(2019, 12, 31, 14, 0, 0), datetime(2020, 1, 1, 14, 0, 0)]}
+        self.target_transit_data_saps = [{"CS001": [datetime(2020, 1, 1, 14, 0, 0), datetime(2020, 1, 1, 14, 0, 0)]}, {"CS001": [datetime(2020, 1, 1, 16, 0, 0), datetime(2020, 1, 1, 16, 0, 0)]}]
+        self.target_transit_patcher = mock.patch('lofar.sas.tmss.services.scheduling.constraints.template_constraints_v1.coordinates_timestamps_and_stations_to_target_transit')
+        self.target_transit_mock = self.target_transit_patcher.start()
+        self.target_transit_mock.return_value = self.target_transit_data
+        self.addCleanup(self.target_transit_patcher.stop)
+
     # min_distance
 
     def test_can_run_anywhere_within_timewindow_with_sky_constraints_with_min_distance_constraint_returns_true_when_met(self):
-        self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['sky'] = {'min_distance': {'sun': 0.1, 'moon': 0.1, 'jupiter': 0.1}}
+        self.scheduling_unit_blueprint.scheduling_constraints_doc['sky'] = {'min_distance': {'sun': 0.1, 'moon': 0.1, 'jupiter': 0.1}}
         self.scheduling_unit_blueprint.save()
         timestamp = datetime(2020, 1, 1, 10, 0, 0)
         returned_value = tc1.can_run_anywhere_within_timewindow_with_sky_constraints(self.scheduling_unit_blueprint, timestamp, timestamp + timedelta(seconds=self.obs_duration))
         self.assertTrue(returned_value)
 
     def test_can_run_anywhere_within_timewindow_with_sky_constraints_with_min_distance_constraint_returns_false_when_not_met(self):
-        self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['sky'] = {'min_distance': {'sun': 0.2, 'moon': 0.2, 'jupiter': 0.2}}
+        self.scheduling_unit_blueprint.scheduling_constraints_doc['sky'] = {'min_distance': {'sun': 0.2, 'moon': 0.2, 'jupiter': 0.2}}
         self.scheduling_unit_blueprint.save()
         timestamp = datetime(2020, 1, 1, 10, 0, 0)
         returned_value = tc1.can_run_anywhere_within_timewindow_with_sky_constraints(self.scheduling_unit_blueprint, timestamp, timestamp + timedelta(seconds=self.obs_duration))
@@ -837,19 +844,83 @@ class TestSkyConstraints(unittest.TestCase):
     # min_target_elevation
 
     def test_can_run_anywhere_within_timewindow_with_sky_constraints_with_min_target_elevation_constraint_returns_true_when_met(self):
-        self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['sky'] = {'min_target_elevation': 0.1}
+        self.scheduling_unit_blueprint.scheduling_constraints_doc['sky'] = {'min_target_elevation': 0.1}
         self.scheduling_unit_blueprint.save()
         timestamp = datetime(2020, 1, 1, 10, 0, 0)
         returned_value = tc1.can_run_anywhere_within_timewindow_with_sky_constraints(self.scheduling_unit_blueprint, timestamp, timestamp + timedelta(seconds=self.obs_duration))
         self.assertTrue(returned_value)
 
     def test_can_run_anywhere_within_timewindow_with_sky_constraints_with_min_target_elevation_constraint_returns_false_when_not_met(self):
-        self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['sky'] = {'min_target_elevation': 0.2}
+        self.scheduling_unit_blueprint.scheduling_constraints_doc['sky'] = {'min_target_elevation': 0.2}
         self.scheduling_unit_blueprint.save()
         timestamp = datetime(2020, 1, 1, 11, 0, 0)
         returned_value = tc1.can_run_anywhere_within_timewindow_with_sky_constraints(self.scheduling_unit_blueprint, timestamp, timestamp + timedelta(seconds=self.obs_duration))
         self.assertFalse(returned_value)
 
+    # transit_offset
+
+    def test_can_run_anywhere_within_timewindow_with_sky_constraints_with_transit_offset_constraint_returns_true_when_met(self):
+        # case 1: transits at 14h, obs middle is at 13h, so we have an offset of -3600 seconds
+
+        # big window
+        self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['sky'] = {'transit_offset': {'from': -43200, 'to': 43200}}  # todo: use blueprint contraints after TMSS-697 was merged
+        self.scheduling_unit_blueprint.save()
+        timestamp = datetime(2020, 1, 1, 12, 0, 0)
+        returned_value = tc1.can_run_anywhere_within_timewindow_with_sky_constraints(self.scheduling_unit_blueprint, timestamp, timestamp + timedelta(seconds=self.obs_duration))
+        self.assertTrue(returned_value)
+
+        # narrow window
+        self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['sky'] = {'transit_offset': {'from': -3601, 'to': -3599}}  # todo: use blueprint contraints after TMSS-697 was merged
+        self.scheduling_unit_blueprint.save()
+        timestamp = datetime(2020, 1, 1, 12, 0, 0)
+        returned_value = tc1.can_run_anywhere_within_timewindow_with_sky_constraints(self.scheduling_unit_blueprint, timestamp, timestamp + timedelta(seconds=self.obs_duration))
+        self.assertTrue(returned_value)
+
+        # case 2: transits at 14h, obs middle is at 2h, so we have an offset of -43200 seconds
+
+        # window spans past 12h, so reference transit is not nearest transit to obs time
+        self.target_transit_mock.return_value = self.target_transit_data_previous
+        self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['sky'] = {'transit_offset': {'from': -43300, 'to': -43100}}  # todo: use blueprint contraints after TMSS-697 was merged
+        self.scheduling_unit_blueprint.save()
+        timestamp = datetime(2020, 1, 1, 1, 0, 0)
+        returned_value = tc1.can_run_anywhere_within_timewindow_with_sky_constraints(self.scheduling_unit_blueprint, timestamp, timestamp + timedelta(seconds=self.obs_duration))
+        self.assertTrue(returned_value)
+        self.target_transit_mock.return_value = self.target_transit_data
+
+    def test_can_run_anywhere_within_timewindow_with_sky_constraints_with_transit_offset_constraint_returns_false_when_not_met(self):
+        # transits at 14h, obs middle is at 13h, so we have an offset of -3600 seconds
+
+        # window after
+        self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['sky'] = {'transit_offset': {'from': -3599, 'to': 43200}}  # todo: use blueprint contraints after TMSS-697 was merged
+        self.scheduling_unit_blueprint.save()
+        timestamp = datetime(2020, 1, 1, 12, 0, 0)
+        returned_value = tc1.can_run_anywhere_within_timewindow_with_sky_constraints(self.scheduling_unit_blueprint, timestamp, timestamp + timedelta(seconds=self.obs_duration))
+        self.assertFalse(returned_value)
+
+        # window before
+        self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['sky'] = {'transit_offset': {'from': -43200, 'to': -3601}}  # todo: use blueprint contraints after TMSS-697 was merged
+        self.scheduling_unit_blueprint.save()
+        timestamp = datetime(2020, 1, 1, 12, 0, 0)
+        returned_value = tc1.can_run_anywhere_within_timewindow_with_sky_constraints(self.scheduling_unit_blueprint, timestamp, timestamp + timedelta(seconds=self.obs_duration))
+        self.assertFalse(returned_value)
+
+
+    def test_can_run_anywhere_within_timewindow_with_sky_constraints_with_transit_offset_constraint_averages_SAPs_for_LBA(self):
+        # sap1 transits at 14h, sap2 transits at 16h, so average transit is at 15h
+        # obs middle is 13h, so we have an offset of -7200 seconds
+
+        self.target_transit_mock.side_effect = self.target_transit_data_saps
+        self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['sky'] = {'transit_offset': {'from': -7201, 'to': -7199}}  # todo: use blueprint contraints after TMSS-697 was merged
+        self.scheduling_unit_blueprint.requirements_doc['tasks']['Observation']['specifications_doc']['antenna_set'] = 'LBA_INNER'
+        self.scheduling_unit_blueprint.requirements_doc['tasks']['Observation']['specifications_doc']['SAPs'] = \
+            [{'name': 'CygA', 'target': 'CygA', 'subbands': [0, 1], 'digital_pointing': {'angle1': 5.233660650313663, 'angle2': 0.7109404782526458, 'direction_type': 'J2000'}},
+             {'name': 'CasA', 'target': 'CasA', 'subbands': [2, 3], 'digital_pointing': {'angle1': 6.233660650313663, 'angle2': 0.6109404782526458, 'direction_type': 'J2000'}}]
+        self.scheduling_unit_blueprint.save()
+        timestamp = datetime(2020, 1, 1, 12, 0, 0)
+        returned_value = tc1.can_run_anywhere_within_timewindow_with_sky_constraints(self.scheduling_unit_blueprint, timestamp, timestamp + timedelta(seconds=self.obs_duration))
+        self.assertTrue(returned_value)
+        self.target_transit_mock.side_effect = None
+
 
 class TestTimeConstraints(TestCase):
     """
@@ -863,28 +934,28 @@ class TestTimeConstraints(TestCase):
     """
 
     def add_time_at_constraint(self, at_timestamp):
-        lst_at_constraint = self.scheduling_unit_blueprint.draft.scheduling_constraints_doc
+        lst_at_constraint = self.scheduling_unit_blueprint.scheduling_constraints_doc
         lst_at_constraint['time']['at'] = at_timestamp.isoformat()
         self.scheduling_unit_blueprint.save()
 
     def add_time_between_constraint(self, from_timestamp, to_timestamp):
-        lst_between_constraints = self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['time']["between"]
+        lst_between_constraints = self.scheduling_unit_blueprint.scheduling_constraints_doc['time']["between"]
         time_constraint_dict = {"from": from_timestamp.isoformat(), "to": to_timestamp.isoformat()}
         lst_between_constraints.append(time_constraint_dict)
         self.scheduling_unit_blueprint.save()
 
     def add_time_not_between_constraint(self, from_timestamp, to_timestamp):
-        lst_between_constraints = self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['time']["not_between"]
+        lst_between_constraints = self.scheduling_unit_blueprint.scheduling_constraints_doc['time']["not_between"]
         time_constraint_dict = {"from": from_timestamp.isoformat(), "to": to_timestamp.isoformat()}
         lst_between_constraints.append(time_constraint_dict)
         self.scheduling_unit_blueprint.save()
 
     def clear_time_constraints(self):
-        self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['time']["between"] = []
-        self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['time']["not_between"] = []
-        self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['time'].pop('at', None)
-        self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['time'].pop("before", None)
-        self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['time'].pop('after', None)
+        self.scheduling_unit_blueprint.scheduling_constraints_doc['time']["between"] = []
+        self.scheduling_unit_blueprint.scheduling_constraints_doc['time']["not_between"] = []
+        self.scheduling_unit_blueprint.scheduling_constraints_doc['time'].pop('at', None)
+        self.scheduling_unit_blueprint.scheduling_constraints_doc['time'].pop("before", None)
+        self.scheduling_unit_blueprint.scheduling_constraints_doc['time'].pop('after', None)
 
     def setUp(self) -> None:
         # scheduling unit
@@ -902,7 +973,7 @@ class TestTimeConstraints(TestCase):
 
         # Set datetime constraints before lower_bound
         self.clear_time_constraints()
-        self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['time']["after"] = datetime(2020, 1, 1, 11, 0, 0).isoformat()
+        self.scheduling_unit_blueprint.scheduling_constraints_doc['time']["after"] = datetime(2020, 1, 1, 11, 0, 0).isoformat()
         self.assertTrue(tc1.can_run_anywhere_within_timewindow_with_time_constraints(self.scheduling_unit_blueprint,
                                                                             datetime(2020, 1, 1, 12, 0, 0),
                                                                             datetime(2020, 1, 2, 12, 0, 0)))
@@ -911,28 +982,28 @@ class TestTimeConstraints(TestCase):
 
         # Set datetime constraints equal to lower_bound
         self.clear_time_constraints()
-        self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['time']["after"] = datetime(2020, 1, 1, 12, 0, 0).isoformat()
+        self.scheduling_unit_blueprint.scheduling_constraints_doc['time']["after"] = datetime(2020, 1, 1, 12, 0, 0).isoformat()
         self.assertFalse(tc1.can_run_anywhere_within_timewindow_with_time_constraints(self.scheduling_unit_blueprint,
                                                                             datetime(2020, 1, 1, 12, 0, 0),
                                                                             datetime(2020, 1, 2, 12, 0, 0)))
 
         # Set datetime constraints after lower_bound
         self.clear_time_constraints()
-        self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['time']["after"] = datetime(2020, 1, 1, 13, 0, 0).isoformat()
+        self.scheduling_unit_blueprint.scheduling_constraints_doc['time']["after"] = datetime(2020, 1, 1, 13, 0, 0).isoformat()
         self.assertFalse(tc1.can_run_anywhere_within_timewindow_with_time_constraints(self.scheduling_unit_blueprint,
                                                                              datetime(2020, 1, 1, 12, 0, 0),
                                                                              datetime(2020, 1, 2, 12, 0, 0)))
 
         # Set datetime constraints to upper_bound
         self.clear_time_constraints()
-        self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['time']["after"] = datetime(2020, 1, 2, 12, 0, 0).isoformat()
+        self.scheduling_unit_blueprint.scheduling_constraints_doc['time']["after"] = datetime(2020, 1, 2, 12, 0, 0).isoformat()
         self.assertFalse(tc1.can_run_anywhere_within_timewindow_with_time_constraints(self.scheduling_unit_blueprint,
                                                                              datetime(2020, 1, 1, 12, 0, 0),
                                                                              datetime(2020, 1, 2, 12, 0, 0)))
 
         # Set datetime constraints after upper_bound
         self.clear_time_constraints()
-        self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['time']["after"] = datetime(2020, 1, 2, 13, 0, 0).isoformat()
+        self.scheduling_unit_blueprint.scheduling_constraints_doc['time']["after"] = datetime(2020, 1, 2, 13, 0, 0).isoformat()
         self.assertFalse(tc1.can_run_anywhere_within_timewindow_with_time_constraints(self.scheduling_unit_blueprint,
                                                                              datetime(2020, 1, 1, 12, 0, 0),
                                                                              datetime(2020, 1, 2, 12, 0, 0)))
@@ -941,14 +1012,14 @@ class TestTimeConstraints(TestCase):
 
         # Set datetime constraints before lower bounds, but with too short window for obs duration
         self.clear_time_constraints()
-        self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['time']["after"] = datetime(2020, 1, 1, 11, 0, 0).isoformat()
+        self.scheduling_unit_blueprint.scheduling_constraints_doc['time']["after"] = datetime(2020, 1, 1, 11, 0, 0).isoformat()
         self.assertFalse(tc1.can_run_within_timewindow_with_time_constraints(self.scheduling_unit_blueprint,
                                                                             datetime(2020, 1, 1, 12, 0, 0),
                                                                             datetime(2020, 1, 1, 13, 0, 0)))
 
         # Set datetime constraints after lower bounds, and with too little space left in window for obs duration
         self.clear_time_constraints()
-        self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['time']["after"] = datetime(2020, 1, 1, 14, 0, 0).isoformat()
+        self.scheduling_unit_blueprint.scheduling_constraints_doc['time']["after"] = datetime(2020, 1, 1, 14, 0, 0).isoformat()
         self.assertFalse(tc1.can_run_within_timewindow_with_time_constraints(self.scheduling_unit_blueprint,
                                                                             datetime(2020, 1, 1, 12, 0, 0),
                                                                             datetime(2020, 1, 1, 15, 0, 0)))
@@ -957,14 +1028,14 @@ class TestTimeConstraints(TestCase):
 
         # Set datetime constraints before lower bounds, and with sufficient window for obs duration
         self.clear_time_constraints()
-        self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['time']["after"] = datetime(2020, 1, 1, 11, 0, 0).isoformat()
+        self.scheduling_unit_blueprint.scheduling_constraints_doc['time']["after"] = datetime(2020, 1, 1, 11, 0, 0).isoformat()
         self.assertTrue(tc1.can_run_within_timewindow_with_time_constraints(self.scheduling_unit_blueprint,
                                                                             datetime(2020, 1, 1, 12, 0, 0),
                                                                             datetime(2020, 1, 1, 14, 0, 0)))
 
         # Set datetime constraints after lower bounds, but with sufficient space left in window for obs duration
         self.clear_time_constraints()
-        self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['time']["after"] = datetime(2020, 1, 1, 13, 0, 0).isoformat()
+        self.scheduling_unit_blueprint.scheduling_constraints_doc['time']["after"] = datetime(2020, 1, 1, 13, 0, 0).isoformat()
         self.assertTrue(tc1.can_run_within_timewindow_with_time_constraints(self.scheduling_unit_blueprint,
                                                                             datetime(2020, 1, 1, 12, 0, 0),
                                                                             datetime(2020, 1, 1, 16, 0, 0)))
@@ -975,27 +1046,27 @@ class TestTimeConstraints(TestCase):
 
         # Set datetime constraints before lower_bound
         self.clear_time_constraints()
-        self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['time']["before"] = datetime(2020, 1, 1, 11, 0, 0).isoformat()
+        self.scheduling_unit_blueprint.scheduling_constraints_doc['time']["before"] = datetime(2020, 1, 1, 11, 0, 0).isoformat()
         self.assertFalse(tc1.can_run_anywhere_within_timewindow_with_time_constraints(self.scheduling_unit_blueprint,
                                                                             datetime(2020, 1, 1, 12, 0, 0),
                                                                             datetime(2020, 1, 2, 12, 0, 0)))
 
         # Set datetime constraints equal to lower_bound
         self.clear_time_constraints()
-        self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['time']["before"] = datetime(2020, 1, 1, 12, 0, 0).isoformat()
+        self.scheduling_unit_blueprint.scheduling_constraints_doc['time']["before"] = datetime(2020, 1, 1, 12, 0, 0).isoformat()
         self.assertFalse(tc1.can_run_anywhere_within_timewindow_with_time_constraints(self.scheduling_unit_blueprint,
                                                                             datetime(2020, 1, 1, 12, 0, 0),
                                                                             datetime(2020, 1, 2, 12, 0, 0)))
 
         # Set datetime constraints after lower_bound
         self.clear_time_constraints()
-        self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['time']["before"] = datetime(2020, 1, 1, 13, 0, 0).isoformat()
+        self.scheduling_unit_blueprint.scheduling_constraints_doc['time']["before"] = datetime(2020, 1, 1, 13, 0, 0).isoformat()
         self.assertFalse(tc1.can_run_anywhere_within_timewindow_with_time_constraints(self.scheduling_unit_blueprint,
                                                                              datetime(2020, 1, 1, 12, 0, 0),
                                                                              datetime(2020, 1, 2, 12, 0, 0)))
         # Set datetime constraints equal to upper_bound
         self.clear_time_constraints()
-        self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['time']["before"] = datetime(2020, 1, 2, 12, 0, 0).isoformat()
+        self.scheduling_unit_blueprint.scheduling_constraints_doc['time']["before"] = datetime(2020, 1, 2, 12, 0, 0).isoformat()
         self.assertFalse(tc1.can_run_anywhere_within_timewindow_with_time_constraints(self.scheduling_unit_blueprint,
                                                                              datetime(2020, 1, 1, 12, 0, 0),
                                                                              datetime(2020, 1, 2, 12, 0, 0)))
@@ -1005,7 +1076,7 @@ class TestTimeConstraints(TestCase):
 
         # Set datetime constraints after upper_bound
         self.clear_time_constraints()
-        self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['time']["before"] = datetime(2020, 1, 2, 13, 0, 0).isoformat()
+        self.scheduling_unit_blueprint.scheduling_constraints_doc['time']["before"] = datetime(2020, 1, 2, 13, 0, 0).isoformat()
         self.assertTrue(tc1.can_run_anywhere_within_timewindow_with_time_constraints(self.scheduling_unit_blueprint,
                                                                             datetime(2020, 1, 1, 12, 0, 0),
                                                                             datetime(2020, 1, 2, 12, 0, 0)))
@@ -1014,14 +1085,14 @@ class TestTimeConstraints(TestCase):
 
         # Set datetime constraints after upper bound, but with too short window for obs duration
         self.clear_time_constraints()
-        self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['time']["before"] = datetime(2020, 1, 2, 13, 0, 0).isoformat()
+        self.scheduling_unit_blueprint.scheduling_constraints_doc['time']["before"] = datetime(2020, 1, 2, 13, 0, 0).isoformat()
         self.assertFalse(tc1.can_run_within_timewindow_with_time_constraints(self.scheduling_unit_blueprint,
                                                                             datetime(2020, 1, 2, 11, 0, 0),
                                                                             datetime(2020, 1, 2, 12, 0, 0)))
 
         # Set datetime constraints after lower bound, and with too little space left in window for obs duration
         self.clear_time_constraints()
-        self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['time']["before"] = datetime(2020, 1, 1, 13, 0, 0).isoformat()
+        self.scheduling_unit_blueprint.scheduling_constraints_doc['time']["before"] = datetime(2020, 1, 1, 13, 0, 0).isoformat()
         self.assertFalse(tc1.can_run_within_timewindow_with_time_constraints(self.scheduling_unit_blueprint,
                                                                             datetime(2020, 1, 1, 12, 0, 0),
                                                                             datetime(2020, 1, 2, 12, 0, 0)))
@@ -1030,14 +1101,14 @@ class TestTimeConstraints(TestCase):
 
         # Set datetime constraints after upper bounds, and with sufficient window for obs duration
         self.clear_time_constraints()
-        self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['time']["before"] = datetime(2020, 1, 2, 13, 0, 0).isoformat()
+        self.scheduling_unit_blueprint.scheduling_constraints_doc['time']["before"] = datetime(2020, 1, 2, 13, 0, 0).isoformat()
         self.assertTrue(tc1.can_run_within_timewindow_with_time_constraints(self.scheduling_unit_blueprint,
                                                                             datetime(2020, 1, 1, 12, 0, 0),
                                                                             datetime(2020, 1, 2, 12, 0, 0)))
 
         # Set datetime constraints after lower bounds, but with sufficient space left in window for obs duration
         self.clear_time_constraints()
-        self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['time']["before"] = datetime(2020, 1, 1, 15, 0, 0).isoformat()
+        self.scheduling_unit_blueprint.scheduling_constraints_doc['time']["before"] = datetime(2020, 1, 1, 15, 0, 0).isoformat()
         self.assertTrue(tc1.can_run_within_timewindow_with_time_constraints(self.scheduling_unit_blueprint,
                                                                             datetime(2020, 1, 1, 12, 0, 0),
                                                                             datetime(2020, 1, 2, 12, 0, 0)))
@@ -1318,22 +1389,22 @@ class TestTimeConstraints(TestCase):
 
         # Set before and after constraint with sufficient gap to fit observation, and assert True
         self.clear_time_constraints()
-        self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['time']["after"] = datetime(2020, 1, 1, 12, 59, 59).isoformat()
-        self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['time']["before"] = datetime(2020, 1, 1, 15, 0, 1).isoformat()
+        self.scheduling_unit_blueprint.scheduling_constraints_doc['time']["after"] = datetime(2020, 1, 1, 12, 59, 59).isoformat()
+        self.scheduling_unit_blueprint.scheduling_constraints_doc['time']["before"] = datetime(2020, 1, 1, 15, 0, 1).isoformat()
         self.assertTrue(self.execute_can_run_within_timewindow_with_time_constraints_of_24hour_boundary())
 
         # set before and after constraint with slightly smaller gap for observation, and assert False
         self.clear_time_constraints()
-        self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['time']["after"] = datetime(2020, 1, 1, 13, 0, 0).isoformat()
-        self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['time']["before"] = datetime(2020, 1, 1, 15, 0, 0).isoformat()
+        self.scheduling_unit_blueprint.scheduling_constraints_doc['time']["after"] = datetime(2020, 1, 1, 13, 0, 0).isoformat()
+        self.scheduling_unit_blueprint.scheduling_constraints_doc['time']["before"] = datetime(2020, 1, 1, 15, 0, 0).isoformat()
         self.assertFalse(self.execute_can_run_within_timewindow_with_time_constraints_of_24hour_boundary())
 
         # set before and after constraint with large gap
         # then and add additional between and not between constraints until window is blocked
         # can run 13-8h
         self.clear_time_constraints()
-        self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['time']["after"] = datetime(2020, 1, 1, 13, 0, 0).isoformat()
-        self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['time']["before"] = datetime(2020, 1, 2, 8, 0, 0).isoformat()
+        self.scheduling_unit_blueprint.scheduling_constraints_doc['time']["after"] = datetime(2020, 1, 1, 13, 0, 0).isoformat()
+        self.scheduling_unit_blueprint.scheduling_constraints_doc['time']["before"] = datetime(2020, 1, 2, 8, 0, 0).isoformat()
         self.assertTrue(self.execute_can_run_within_timewindow_with_time_constraints_of_24hour_boundary())
 
         # can run 13h-20h
@@ -1353,7 +1424,7 @@ class TestTimeConstraints(TestCase):
         self.assertTrue(self.execute_can_run_within_timewindow_with_time_constraints_of_24hour_boundary())
 
         # move before constraint, can not run anymore
-        self.scheduling_unit_blueprint.draft.scheduling_constraints_doc['time']["before"] = datetime(2020, 1, 2, 5, 0, 0).isoformat()
+        self.scheduling_unit_blueprint.scheduling_constraints_doc['time']["before"] = datetime(2020, 1, 2, 5, 0, 0).isoformat()
         self.assertFalse(self.execute_can_run_within_timewindow_with_time_constraints_of_24hour_boundary())
 
 
diff --git a/SAS/TMSS/backend/src/tmss/tmssapp/conversions.py b/SAS/TMSS/backend/src/tmss/tmssapp/conversions.py
index 14b0a38e566666fda10ba8292bb9d4f91525afef..642e7090c070be2033a4af4c8404c137bbe2b771 100644
--- a/SAS/TMSS/backend/src/tmss/tmssapp/conversions.py
+++ b/SAS/TMSS/backend/src/tmss/tmssapp/conversions.py
@@ -35,7 +35,6 @@ SUN_SET_RISE_ANGLE_TO_HORIZON = Angle(10, unit=astropy.units.deg)
 # TODO: To be considered, now we store the sunset/sunrise data in advanced, we can increase the number of points!!
 SUN_SET_RISE_PRECISION = 30
 
-
 def timestamps_and_stations_to_sun_rise_and_set(timestamps: tuple, stations: tuple, angle_to_horizon: Angle=SUN_SET_RISE_ANGLE_TO_HORIZON,
                                                 create_when_not_found=False) -> dict:
     """
@@ -268,6 +267,34 @@ def coordinates_timestamps_and_stations_to_target_rise_and_set(angle1: float, an
 
     return return_dict
 
+# default n_grid_points; higher is more precise but very costly; astropy defaults to 150, note that errors can be in the minutes with a lower values
+TARGET_TRANSIT_PRECISION = 150
+
+@lru_cache(maxsize=256, typed=False)  # does not like lists, so use tuples to allow caching
+def coordinates_timestamps_and_stations_to_target_transit(angle1: float, angle2: float, direction_type: str, timestamps: tuple, stations: tuple) -> dict:
+    """
+    Compute nearest meridian transit times of the given coordinates for each given station and timestamp.
+    :param angle1: first angle of celectial coordinates, e.g. RA
+    :param angle2: second angle of celectial coordinates, e.g. Dec
+    :param direction_type: direction_type of celectial coordinates, e.g. 'J2000'
+    :param timestamps: tuple of datetimes, e.g. (datetime(2020, 1, 1), datetime(2020, 1, 2))
+    :param stations: tuple of station names, e.g. ("CS002",)
+    :return A dict that maps station names to a list of transit times (nearest transit for each requested timestamp).
+        E.g.
+        {"CS002": [datetime(2020, 1, 1, 4, 0, 0), datetime(2020, 1, 2, 4, 0, 0)]}
+    """
+    if direction_type == "J2000":
+        coord = astropy.coordinates.SkyCoord(ra=angle1, dec=angle2, unit=astropy.units.rad)
+    else:
+        raise ValueError("Do not know how to convert direction_type=%s to SkyCoord" % direction_type)
+    return_dict = {}
+    for station in stations:
+        for timestamp in timestamps:
+            # todo: this can probably be made faster by moving the following logic to an own function with single station/timestamp as input and putting the lru_cache on there.
+            observer = create_astroplan_observer_for_station(station)
+            target_transit = observer.target_meridian_transit_time(target=coord, time=Time(timestamp), which='nearest', n_grid_points=TARGET_TRANSIT_PRECISION)
+            return_dict.setdefault(station, []).append(target_transit.to_datetime())
+    return return_dict
 
 
 def local_sidereal_time_for_utc_and_station(timestamp: datetime = None,
diff --git a/SAS/TMSS/backend/src/tmss/tmssapp/migrations/0001_initial.py b/SAS/TMSS/backend/src/tmss/tmssapp/migrations/0001_initial.py
index e2cb08e37434b494c8b502cde395f9ef10510dcb..0110ee6adaa831b503f1b8b42ea28f0ed7a6d0d2 100644
--- a/SAS/TMSS/backend/src/tmss/tmssapp/migrations/0001_initial.py
+++ b/SAS/TMSS/backend/src/tmss/tmssapp/migrations/0001_initial.py
@@ -1,4 +1,4 @@
-# Generated by Django 3.0.9 on 2021-04-08 14:57
+# Generated by Django 3.0.9 on 2021-04-28 21:14
 
 from django.conf import settings
 import django.contrib.postgres.fields
@@ -617,9 +617,10 @@ class Migration(migrations.Migration):
                 ('ingest_permission_granted_since', models.DateTimeField(help_text='The moment when ingest permission was granted.', null=True)),
                 ('output_pinned', models.BooleanField(default=False, help_text='boolean (default FALSE), which blocks deleting unpinned dataproducts. When toggled ON, backend must pick SUB up for deletion. It also must when dataproducts are unpinned.')),
                 ('results_accepted', models.BooleanField(default=False, help_text='boolean (default NULL), which records whether the results were accepted, allowing the higher-level accounting to be adjusted.')),
-                ('priority_rank', models.FloatField(default=0.0, help_text='Priority of this scheduling unit w.r.t. other scheduling units within the same queue and project.')),
                 ('piggyback_allowed_tbb', models.BooleanField(help_text='Piggyback key for TBB.', null=True)),
                 ('piggyback_allowed_aartfaac', models.BooleanField(help_text='Piggyback key for AARTFAAC.', null=True)),
+                ('priority_rank', models.FloatField(default=0.0, help_text='Priority of this scheduling unit w.r.t. other scheduling units within the same queue and project.')),
+                ('scheduling_constraints_doc', django.contrib.postgres.fields.jsonb.JSONField(help_text='Scheduling Constraints for this run.', null=True)),
             ],
             options={
                 'abstract': False,
@@ -639,9 +640,9 @@ class Migration(migrations.Migration):
                 ('generator_instance_doc', django.contrib.postgres.fields.jsonb.JSONField(help_text='Parameter value that generated this run draft (NULLable).', null=True)),
                 ('scheduling_constraints_doc', django.contrib.postgres.fields.jsonb.JSONField(help_text='Scheduling Constraints for this run.', null=True)),
                 ('ingest_permission_required', models.BooleanField(default=False, help_text='Explicit permission is needed before the task.')),
-                ('priority_rank', models.FloatField(default=0.0, help_text='Priority of this scheduling unit w.r.t. other scheduling units within the same queue and project.')),
                 ('piggyback_allowed_tbb', models.BooleanField(help_text='Piggyback key for TBB.', null=True)),
                 ('piggyback_allowed_aartfaac', models.BooleanField(help_text='Piggyback key for AARTFAAC.', null=True)),
+                ('priority_rank', models.FloatField(default=0.0, help_text='Priority of this scheduling unit w.r.t. other scheduling units within the same queue and project.')),
             ],
             options={
                 'abstract': False,
@@ -1251,6 +1252,11 @@ class Migration(migrations.Migration):
             name='requirements_template',
             field=models.ForeignKey(help_text='Schema used for requirements_doc (IMMUTABLE).', on_delete=django.db.models.deletion.CASCADE, to='tmssapp.SchedulingUnitTemplate'),
         ),
+        migrations.AddField(
+            model_name='schedulingunitblueprint',
+            name='scheduling_constraints_template',
+            field=models.ForeignKey(help_text='Schema used for scheduling_constraints_doc.', null=True, on_delete=django.db.models.deletion.CASCADE, to='tmssapp.SchedulingConstraintsTemplate'),
+        ),
         migrations.AddField(
             model_name='schedulingset',
             name='generator_source',
diff --git a/SAS/TMSS/backend/src/tmss/tmssapp/models/specification.py b/SAS/TMSS/backend/src/tmss/tmssapp/models/specification.py
index b927f609a143033d3169b34b1d4a30bcd7bb3360..ada071a865bdf4f336164fa504e62eb9f7083a87 100644
--- a/SAS/TMSS/backend/src/tmss/tmssapp/models/specification.py
+++ b/SAS/TMSS/backend/src/tmss/tmssapp/models/specification.py
@@ -17,7 +17,7 @@ from django.core.exceptions import ValidationError
 import datetime
 from collections import Counter
 from django.utils.functional import cached_property
-
+from lofar.sas.tmss.tmss.exceptions import TMSSException
 
 #
 # Mixins
@@ -480,6 +480,8 @@ class SchedulingUnitBlueprint(RefreshFromDbInvalidatesCachedPropertiesMixin, Tem
         SCHEDULED = "scheduled"
         SCHEDULABLE = "schedulable"
 
+    # todo: are many of these fields supposed to be immutable in the database?
+    #  Or are we fine to just not allow most users to change them?
     requirements_doc = JSONField(help_text='Scheduling and/or quality requirements for this scheduling unit (IMMUTABLE).')
     do_cancel = BooleanField()
     ingest_permission_required = BooleanField(default=False, help_text='Explicit permission is needed before the task.')
@@ -492,19 +494,40 @@ class SchedulingUnitBlueprint(RefreshFromDbInvalidatesCachedPropertiesMixin, Tem
     piggyback_allowed_aartfaac = BooleanField(help_text='Piggyback key for AARTFAAC.', null=True)
     priority_rank = FloatField(null=False, default=0.0, help_text='Priority of this scheduling unit w.r.t. other scheduling units within the same queue and project.')
     priority_queue = ForeignKey('PriorityQueueType', null=False, on_delete=PROTECT, default="A", help_text='Priority queue of this scheduling unit. Queues provide a strict ordering between scheduling units.')
+    scheduling_constraints_doc = JSONField(help_text='Scheduling Constraints for this run.', null=True)
+    scheduling_constraints_template = ForeignKey('SchedulingConstraintsTemplate', on_delete=CASCADE, null=True, help_text='Schema used for scheduling_constraints_doc.')
+
+    def __init__(self, *args, **kwargs):
+        super().__init__(*args, **kwargs)
+
+        # keep original scheduling constraints to detect changes on save
+        # Note: we cannot use self.scheduling_constraints_doc here since that causes an infinite loop of update_from_db
+        if 'scheduling_constraints_doc' in kwargs.keys():
+            self.__original_scheduling_constraints_doc = kwargs['scheduling_constraints_doc']
+        else:
+            self.__original_scheduling_constraints_doc = None
+        self.__original_scheduling_constraints_template_id = self.scheduling_constraints_template_id
 
     def save(self, force_insert=False, force_update=False, using=None, update_fields=None):
         self.annotate_validate_add_defaults_to_doc_using_template('requirements_doc', 'requirements_template')
-       
-        # This code only happens if the objects is not in the database yet. self._state.adding is True creating
-        if self._state.adding and hasattr(self, 'draft'):
-            self.ingest_permission_required = self.draft.ingest_permission_required
-
-        # Propagate scheduling_unit_draft piggyback values as default for scheduling_unit_blueprint
-        if self._state.adding and self.piggyback_allowed_tbb is None and hasattr(self, 'draft'):
-            self.piggyback_allowed_tbb = self.draft.piggyback_allowed_tbb
-        if self._state.adding and self.piggyback_allowed_aartfaac is None and hasattr(self, 'draft'):
-            self.piggyback_allowed_aartfaac = self.draft.piggyback_allowed_aartfaac
+
+        if self._state.adding:
+            # On creation, propagate the following scheduling_unit_draft attributes as default for the new scheduling_unit_blueprint
+            for copy_field in ['ingest_permission_required', 'piggyback_allowed_tbb', 'piggyback_allowed_aartfaac',
+                               'scheduling_constraints_doc', 'scheduling_constraints_template']:
+                if hasattr(self, 'draft'):
+                    setattr(self, copy_field, getattr(self.draft, copy_field))
+        else:
+            # On updates, prevent changing the scheduling constraints doc or template if we are past schedulable state
+            # todo: This causes a ton of tests to fail, e.g. t_workflow_qaworkflow returns errors 422
+            if self.status not in [SchedulingUnitBlueprint.Status.DEFINED.value, SchedulingUnitBlueprint.Status.SCHEDULABLE.value] and \
+                    ((self.__original_scheduling_constraints_doc is not None and self.scheduling_constraints_doc != self.__original_scheduling_constraints_doc) or
+                     self.scheduling_constraints_template_id != self.__original_scheduling_constraints_template_id):
+                raise TMSSException('The scheduling constraints of SchedulingUnitBlueprint pk=%s status=%s cannot be updated since it is not in defined or schedulable state.' % (self.pk, self.status))
+
+        # update the original constraints value for comparison on next save
+        self.__original_scheduling_constraints_doc = self.scheduling_constraints_doc
+        self.__original_scheduling_constraints_template_id = self.scheduling_constraints_template_id
 
         super().save(force_insert, force_update, using, update_fields)
 
diff --git a/SAS/TMSS/backend/src/tmss/tmssapp/views.py b/SAS/TMSS/backend/src/tmss/tmssapp/views.py
index 85bdfe0de03a90428f85f01fb51264e4b4082b49..c043399964b788b809194e49c1c0b6872e57fdfe 100644
--- a/SAS/TMSS/backend/src/tmss/tmssapp/views.py
+++ b/SAS/TMSS/backend/src/tmss/tmssapp/views.py
@@ -18,7 +18,7 @@ from datetime import datetime
 import dateutil.parser
 from astropy.coordinates import Angle
 import astropy.units
-from lofar.sas.tmss.tmss.tmssapp.conversions import local_sidereal_time_for_utc_and_station, local_sidereal_time_for_utc_and_longitude, timestamps_and_stations_to_sun_rise_and_set, coordinates_and_timestamps_to_separation_from_bodies, coordinates_timestamps_and_stations_to_target_rise_and_set
+from lofar.sas.tmss.tmss.tmssapp.conversions import local_sidereal_time_for_utc_and_station, local_sidereal_time_for_utc_and_longitude, timestamps_and_stations_to_sun_rise_and_set, coordinates_and_timestamps_to_separation_from_bodies, coordinates_timestamps_and_stations_to_target_rise_and_set, coordinates_timestamps_and_stations_to_target_transit
 
 # Note: Decorate with @api_view to get this picked up by Swagger
 
@@ -278,3 +278,27 @@ def get_target_rise_and_set(request):
     rise_set_dict = coordinates_timestamps_and_stations_to_target_rise_and_set(angle1=angle1, angle2=angle2, direction_type=direction_type, angle_to_horizon=horizon, timestamps=timestamps, stations=stations)
     return JsonResponse(rise_set_dict)
 
+
+@api_view(['GET'])
+def get_target_transit(request):
+    '''
+    returns transit times of the given coordinates for each given station and timestamp.
+    '''
+    timestamps = request.GET.get('timestamps', None)
+    angle1 = request.GET.get('angle1')
+    angle2 = request.GET.get('angle2')
+    direction_type = request.GET.get("direction_type", "J2000")
+    stations = tuple(request.GET.get('stations', "CS002").split(','))
+
+    if angle1 is None or angle2 is None:
+        raise ValueError("Please provide celestial coordinates via 'angle1', 'angle2' (and optionally 'direction_type') properties.")
+
+    if timestamps is None:
+        timestamps = (datetime.utcnow(),)
+    else:
+        timestamps = timestamps.split(',')
+        timestamps = tuple([dateutil.parser.parse(timestamp, ignoretz=True) for timestamp in timestamps])  #  isot to datetime
+
+    # calculate
+    transit_dict = coordinates_timestamps_and_stations_to_target_transit(angle1=angle1, angle2=angle2, direction_type=direction_type, timestamps=timestamps, stations=stations)
+    return JsonResponse(transit_dict)
diff --git a/SAS/TMSS/backend/src/tmss/urls.py b/SAS/TMSS/backend/src/tmss/urls.py
index 5306787cb405fa524cbb475cc7d7e76d1fe3c561..c077e51431b29da1484c0653421d54c27a7a5f91 100644
--- a/SAS/TMSS/backend/src/tmss/urls.py
+++ b/SAS/TMSS/backend/src/tmss/urls.py
@@ -75,6 +75,7 @@ urlpatterns = [
     re_path('util/lst/?', views.lst, name="conversion-lst"),
     re_path('util/angular_separation/?', views.get_angular_separation, name='get_angular_separation'),
     re_path('util/target_rise_and_set/?', views.get_target_rise_and_set, name='get_target_rise_and_set'),
+    re_path('util/target_transit/?', views.get_target_transit, name='get_target_transit'),
 ]
 
 if os.environ.get('SHOW_DJANGO_DEBUG_TOOLBAR', False):
diff --git a/SAS/TMSS/backend/test/t_conversions.py b/SAS/TMSS/backend/test/t_conversions.py
index 6a07693cbced93562963ebd79790cf1716c58e0e..942fb172dd634dd99f95732459ac833b0e37a622 100755
--- a/SAS/TMSS/backend/test/t_conversions.py
+++ b/SAS/TMSS/backend/test/t_conversions.py
@@ -288,11 +288,12 @@ class UtilREST(unittest.TestCase):
         # defaults are CS002 and today
         self.assertIn('CS002', r_dict.keys())
 
-        # assert day of timestamp matches day of returned rise
-        expected_date = datetime.date.today()
+        # assert target sets within 24h after now and rises within 24h before it sets
+        expected_date = datetime.datetime.utcnow()
         target_rise = dateutil.parser.parse(r_dict['CS002'][0]['rise'])
         target_set = dateutil.parser.parse(r_dict['CS002'][0]['set'])
-        self.assertTrue(expected_date == target_rise.date() or expected_date == target_set.date())
+        self.assertTrue(0 < (target_set - expected_date).total_seconds() < 86400)
+        self.assertTrue(0 < (target_set - target_rise).total_seconds() < 86400)
 
     def test_util_target_rise_and_set_considers_stations(self):
         stations = ['CS005', 'RS305', 'DE609']
@@ -353,13 +354,13 @@ class UtilREST(unittest.TestCase):
 
     def test_util_target_rise_and_set_considers_horizon(self):
         test_horizons = [0.1, 0.2, 0.3]
+        rise_last = None
         for horizon in test_horizons:
             r = requests.get(BASE_URL + '/util/target_rise_and_set?angle1=0.5&angle2=0.5&horizon=%s' % horizon, auth=AUTH)
             self.assertEqual(r.status_code, 200)
             r_dict = json.loads(r.content.decode('utf-8'))
 
             # assert all requested horizons yield a response and times differ
-            rise_last = None
             rise = r_dict['CS002'][0]['rise']
             if rise_last:
                 self.assertNotEqual(rise, rise_last)
@@ -394,6 +395,76 @@ class UtilREST(unittest.TestCase):
         self.assertFalse(r_dict['CS002'][0]['always_above_horizon'])
         self.assertTrue(r_dict['CS002'][0]['always_below_horizon'])
 
+    # target transit
+
+    def test_util_target_transit_returns_json_structure_with_defaults(self):
+        r = requests.get(BASE_URL + '/util/target_transit?angle1=0.5&angle2=0.5', auth=AUTH)
+        self.assertEqual(r.status_code, 200)
+        r_dict = json.loads(r.content.decode('utf-8'))
+
+        # defaults are CS002 and today
+        self.assertIn('CS002', r_dict.keys())
+
+        # assert returned timestamp is no further than 12h away from now
+        expected_time = datetime.datetime.utcnow()
+        returned_time = dateutil.parser.parse(r_dict['CS002'][0])
+        time_diff = abs(expected_time - returned_time)
+        self.assertTrue(time_diff <= datetime.timedelta(days=0.5))
+
+    def test_util_target_transit_considers_stations(self):
+        stations = ['CS005', 'RS305', 'DE609']
+        r = requests.get(BASE_URL + '/util/target_transit?angle1=0.5&angle2=0.5&stations=%s' % ','.join(stations), auth=AUTH)
+        self.assertEqual(r.status_code, 200)
+        r_dict = json.loads(r.content.decode('utf-8'))
+
+        # assert station is included in response and timestamps differ
+        target_transit_last = None
+        for station in stations:
+            self.assertIn(station, r_dict.keys())
+            target_transit = dateutil.parser.parse(r_dict[station][0])
+            if target_transit_last:
+                self.assertNotEqual(target_transit, target_transit_last)
+            target_transit_last = target_transit
+
+    def test_util_target_transit_considers_timestamps(self):
+        timestamps = ['2020-01-01', '2020-02-22T16-00-00', '2020-3-11']
+        r = requests.get(BASE_URL + '/util/target_transit?angle1=0.5&angle2=0.5&timestamps=%s' % ','.join(timestamps), auth=AUTH)
+        self.assertEqual(r.status_code, 200)
+        r_dict = json.loads(r.content.decode('utf-8'))
+
+        # assert all requested timestamps yield a different response
+        transit_last = None
+        for i in range(len(timestamps)):
+            transit = r_dict['CS002'][i]
+            if transit_last:
+                self.assertNotEqual(transit, transit_last)
+            transit_last = transit
+
+    def test_util_target_transit_returns_correct_date_of_target_transit(self):
+        timestamps = ['2020-01-01T02-00-00']
+        r = requests.get(BASE_URL + '/util/target_transit?angle1=0.5&angle2=0.5&timestamps=%s' % ','.join(timestamps), auth=AUTH)
+        self.assertEqual(r.status_code, 200)
+        r_dict = json.loads(r.content.decode('utf-8'))
+
+        # assert transit time is no further than 12h from requested time
+        requested_time = dateutil.parser.parse(timestamps[0]).replace(tzinfo=None)
+        returned_time = dateutil.parser.parse(r_dict['CS002'][0])
+        time_diff = abs(requested_time - returned_time)
+        self.assertTrue(time_diff <= datetime.timedelta(days=0.5))
+
+    def test_util_target_transit_considers_coordinates(self):
+        test_coords = [(0.5, 0.5, "J2000"), (0.6, 0.5, "J2000"), (0.6, 0.6, "J2000")]
+        transit_last = None
+        for coords in test_coords:
+            r = requests.get(BASE_URL + '/util/target_transit?angle1=%s&angle2=%s&direction_type=%s' % coords, auth=AUTH)
+            self.assertEqual(r.status_code, 200)
+            r_dict = json.loads(r.content.decode('utf-8'))
+
+            # assert all requested coordinates yield a response and times differ
+            transit = r_dict['CS002'][0]
+            if transit_last:
+                self.assertNotEqual(transit, transit_last)
+            transit_last = transit
 
 if __name__ == "__main__":
     os.environ['TZ'] = 'UTC'
diff --git a/SAS/TMSS/backend/test/t_tmssapp_specification_django_API.py b/SAS/TMSS/backend/test/t_tmssapp_specification_django_API.py
index b8d82ead9e47fbab49e00befc8742bedc634eee3..f1218237f3ff7b8ee8a7d70e24c3486d081cf500 100755
--- a/SAS/TMSS/backend/test/t_tmssapp_specification_django_API.py
+++ b/SAS/TMSS/backend/test/t_tmssapp_specification_django_API.py
@@ -45,6 +45,7 @@ from django.db.utils import IntegrityError
 from django.core.exceptions import ValidationError
 from django.db.models.deletion import ProtectedError
 from lofar.sas.tmss.tmss.exceptions import SchemaValidationException
+from lofar.sas.tmss.tmss.exceptions import TMSSException
 
 class GeneratorTemplateTest(unittest.TestCase):
     def test_GeneratorTemplate_gets_created_with_correct_creation_timestamp(self):
@@ -471,7 +472,7 @@ class SchedulingUnitDraftTest(unittest.TestCase):
             models.SchedulingUnitDraft.objects.create(**test_data)
 
     def test_SchedulingUnitDraft_gets_created_with_correct_default_ingest_permission_required(self):
-        
+
         # setup
         entry = models.SchedulingUnitDraft.objects.create(**SchedulingUnitDraft_test_data())
         #check the auto_ingest on project
@@ -749,239 +750,339 @@ class SchedulingUnitBlueprintTest(unittest.TestCase):
         self.assertEqual(scheduling_unit_blueprint.piggyback_allowed_tbb, scheduling_unit_draft.piggyback_allowed_tbb)
         self.assertEqual(scheduling_unit_blueprint.piggyback_allowed_aartfaac, scheduling_unit_draft.piggyback_allowed_aartfaac)
 
-
-class TaskBlueprintTest(unittest.TestCase):
-    @classmethod
-    def setUpClass(cls) -> None:
-        cls.task_draft = models.TaskDraft.objects.create(**TaskDraft_test_data())
-        cls.scheduling_unit_blueprint = models.SchedulingUnitBlueprint.objects.create(**SchedulingUnitBlueprint_test_data())
-
-    def test_TaskBlueprint_gets_created_with_correct_creation_timestamp(self):
-
-        # setup
-        before = datetime.utcnow()
-        entry = models.TaskBlueprint.objects.create(**TaskBlueprint_test_data(task_draft=self.task_draft, scheduling_unit_blueprint=self.scheduling_unit_blueprint))
-
-        after = datetime.utcnow()
-
-        # assert
-        self.assertLess(before, entry.created_at)
-        self.assertGreater(after, entry.created_at)
-
-    def test_TaskBlueprint_update_timestamp_gets_changed_correctly(self):
+    def test_SchedulingUnitBlueprint_gets_created_with_correct_default_scheduling_constraints(self):
 
         # setup
-        entry = models.TaskBlueprint.objects.create(**TaskBlueprint_test_data(name=str(uuid.uuid4()), task_draft=self.task_draft, scheduling_unit_blueprint=self.scheduling_unit_blueprint))
-        before = datetime.utcnow()
-        entry.save()
-        after = datetime.utcnow()
-
-        # assert
-        self.assertLess(before, entry.updated_at)
-        self.assertGreater(after, entry.updated_at)
-
-    def test_TaskBlueprint_prevents_missing_template(self):
-
-        # setup
-        test_data = dict(TaskBlueprint_test_data(task_draft=self.task_draft, scheduling_unit_blueprint=self.scheduling_unit_blueprint))
-        test_data['specifications_template'] = None
-
-        # assert
-        with self.assertRaises(IntegrityError):
-            models.TaskBlueprint.objects.create(**test_data)
-
-    def test_TaskBlueprint_prevents_missing_draft(self):
+        constraints = models.SchedulingConstraintsTemplate.objects.create(**SchedulingConstraintsTemplate_test_data(name='constraints'))
+        scheduling_unit_draft = models.SchedulingUnitDraft.objects.create(**SchedulingUnitDraft_test_data(
+            scheduling_constraints_doc={'foo': 'baz'},
+            scheduling_constraints_template=constraints))
+        scheduling_unit_blueprint = models.SchedulingUnitBlueprint.objects.create(**SchedulingUnitBlueprint_test_data(draft=scheduling_unit_draft))
 
-        # setup
-        test_data = dict(TaskBlueprint_test_data(task_draft=self.task_draft, scheduling_unit_blueprint=self.scheduling_unit_blueprint))
-        test_data['draft'] = None
+        scheduling_unit_blueprint.refresh_from_db()
 
         # assert
-        with self.assertRaises(IntegrityError):
-            models.TaskBlueprint.objects.create(**test_data)
-
-    def test_TaskBlueprint_prevents_draft_deletion(self):
-        # setup
-        test_data = dict(TaskBlueprint_test_data())
-        blueprint = models.TaskBlueprint.objects.create(**test_data)
-        draft = blueprint.draft
-        with self.assertRaises(ProtectedError):
-            draft.delete()
+        self.assertEqual(scheduling_unit_blueprint.scheduling_constraints_doc, scheduling_unit_draft.scheduling_constraints_doc)
+        self.assertEqual(scheduling_unit_blueprint.scheduling_constraints_template, scheduling_unit_draft.scheduling_constraints_template)
 
-    def test_TaskBlueprint_prevents_missing_scheduling_unit_blueprint(self):
+    def test_SchedulingUnitBlueprint_prevents_updating_scheduling_constraints_template_if_not_in_correct_state(self):
 
         # setup
-        test_data = dict(TaskBlueprint_test_data(task_draft=self.task_draft, scheduling_unit_blueprint=self.scheduling_unit_blueprint))
-        test_data['scheduling_unit_blueprint'] = None
-
-        # assert
-        with self.assertRaises(IntegrityError):
-            models.TaskBlueprint.objects.create(**test_data)
-
-    def test_TaskBlueprint_predecessors_and_successors_none(self):
-        task_blueprint_1: models.TaskBlueprint = models.TaskBlueprint.objects.create(**TaskBlueprint_test_data(name=str(uuid.uuid4()), task_draft=self.task_draft, scheduling_unit_blueprint=self.scheduling_unit_blueprint))
-        task_blueprint_2: models.TaskBlueprint = models.TaskBlueprint.objects.create(**TaskBlueprint_test_data(name=str(uuid.uuid4()), task_draft=self.task_draft, scheduling_unit_blueprint=self.scheduling_unit_blueprint))
-
-        self.assertEqual(set(), set(task_blueprint_1.predecessors.all()))
-        self.assertEqual(set(), set(task_blueprint_2.predecessors.all()))
-        self.assertEqual(set(), set(task_blueprint_1.successors.all()))
-        self.assertEqual(set(), set(task_blueprint_2.successors.all()))
-
-    def test_TaskBlueprint_predecessors_and_successors_simple(self):
-        task_blueprint_1: models.TaskBlueprint = models.TaskBlueprint.objects.create(**TaskBlueprint_test_data(name=str(uuid.uuid4()), task_draft=self.task_draft, scheduling_unit_blueprint=self.scheduling_unit_blueprint))
-        task_blueprint_2: models.TaskBlueprint = models.TaskBlueprint.objects.create(**TaskBlueprint_test_data(name=str(uuid.uuid4()), task_draft=self.task_draft, scheduling_unit_blueprint=self.scheduling_unit_blueprint))
+        constraints_1 = models.SchedulingConstraintsTemplate.objects.create(**SchedulingConstraintsTemplate_test_data(name='constraints_1'))
+        constraints_2 = models.SchedulingConstraintsTemplate.objects.create(**SchedulingConstraintsTemplate_test_data(name='constraints_2'))
+        scheduling_unit_blueprint = models.SchedulingUnitBlueprint.objects.create(**SchedulingUnitBlueprint_test_data())
+        scheduling_unit_blueprint.scheduling_constraints_template = constraints_1
+        scheduling_unit_blueprint.save()
+
+        task_blueprint = models.TaskBlueprint.objects.create(**TaskBlueprint_test_data(scheduling_unit_blueprint=scheduling_unit_blueprint))
+        subtask = models.Subtask.objects.create(**Subtask_test_data())
+        subtask.task_blueprints.set([task_blueprint])
+        subtask.state = models.SubtaskState.objects.get(value='error')  # the derived SUB status is then also error
+        subtask.save()
 
-        models.TaskRelationBlueprint.objects.create(**TaskRelationBlueprint_test_data(producer=task_blueprint_1, consumer=task_blueprint_2))
-
-        self.assertEqual(task_blueprint_1, task_blueprint_2.predecessors.all()[0])
-        self.assertEqual(task_blueprint_2, task_blueprint_1.successors.all()[0])
-
-    def test_TaskBlueprint_predecessors_and_successors_complex(self):
-        task_blueprint_1: models.TaskBlueprint = models.TaskBlueprint.objects.create(**TaskBlueprint_test_data(name=str(uuid.uuid4())))
-        task_blueprint_2: models.TaskBlueprint = models.TaskBlueprint.objects.create(**TaskBlueprint_test_data(name=str(uuid.uuid4()), task_draft=task_blueprint_1.draft, scheduling_unit_blueprint=task_blueprint_1.scheduling_unit_blueprint))
-        task_blueprint_3: models.TaskBlueprint = models.TaskBlueprint.objects.create(**TaskBlueprint_test_data(name=str(uuid.uuid4()), task_draft=task_blueprint_1.draft, scheduling_unit_blueprint=task_blueprint_1.scheduling_unit_blueprint))
-        task_blueprint_4: models.TaskBlueprint = models.TaskBlueprint.objects.create(**TaskBlueprint_test_data(name=str(uuid.uuid4()), task_draft=task_blueprint_1.draft, scheduling_unit_blueprint=task_blueprint_1.scheduling_unit_blueprint))
-        task_blueprint_5: models.TaskBlueprint = models.TaskBlueprint.objects.create(**TaskBlueprint_test_data(name=str(uuid.uuid4()), task_draft=task_blueprint_1.draft, scheduling_unit_blueprint=task_blueprint_1.scheduling_unit_blueprint))
-        task_blueprint_6: models.TaskBlueprint = models.TaskBlueprint.objects.create(**TaskBlueprint_test_data(name=str(uuid.uuid4()), task_draft=task_blueprint_1.draft, scheduling_unit_blueprint=task_blueprint_1.scheduling_unit_blueprint))
-
-        # ST1 ---> ST3 ---> ST4
-        #      |        |
-        # ST2 -          -> ST5 ---> ST6
+        scheduling_unit_blueprint.refresh_from_db()
 
-        models.TaskRelationBlueprint.objects.create(**TaskRelationBlueprint_test_data(producer=task_blueprint_1, consumer=task_blueprint_3))
-        trb1 = models.TaskRelationBlueprint.objects.create(**TaskRelationBlueprint_test_data(producer=task_blueprint_2, consumer=task_blueprint_3))
-        models.TaskRelationBlueprint.objects.create(**TaskRelationBlueprint_test_data(producer=task_blueprint_3, consumer=task_blueprint_4))
-        models.TaskRelationBlueprint.objects.create(**TaskRelationBlueprint_test_data(producer=task_blueprint_3, consumer=task_blueprint_5))
-        models.TaskRelationBlueprint.objects.create(**TaskRelationBlueprint_test_data(producer=task_blueprint_5, consumer=task_blueprint_6))
+        # we should be able to modify other fields
+        scheduling_unit_blueprint.results_accepted = not scheduling_unit_blueprint.results_accepted
+        scheduling_unit_blueprint.save()
 
-        self.assertEqual(set((task_blueprint_1, task_blueprint_2)), set(task_blueprint_3.predecessors.all()))
-        self.assertEqual(set((task_blueprint_4, task_blueprint_5)), set(task_blueprint_3.successors.all()))
-        self.assertEqual(set((task_blueprint_3,)), set(task_blueprint_4.predecessors.all()))
-        self.assertEqual(set((task_blueprint_3,)), set(task_blueprint_5.predecessors.all()))
-        self.assertEqual(set((task_blueprint_3,)), set(task_blueprint_1.successors.all()))
-        self.assertEqual(set((task_blueprint_3,)), set(task_blueprint_2.successors.all()))
-        self.assertEqual(set(), set(task_blueprint_1.predecessors.all()))
-        self.assertEqual(set(), set(task_blueprint_2.predecessors.all()))
-        self.assertEqual(set(), set(task_blueprint_4.successors.all()))
-        self.assertEqual(set((task_blueprint_6,)), set(task_blueprint_5.successors.all()))
+        # but scheduling constraints should be immutable
+        with self.assertRaises(TMSSException) as context:
+            scheduling_unit_blueprint.scheduling_constraints_template = constraints_2
+            scheduling_unit_blueprint.save()
 
+        self.assertIn('schedulable state', str(context.exception))
 
-class TaskRelationBlueprintTest(unittest.TestCase):
-    @classmethod
-    def setUpClass(cls) -> None:
-        cls.producer = models.TaskBlueprint.objects.create(**TaskBlueprint_test_data())
-        cls.consumer = models.TaskBlueprint.objects.create(**TaskBlueprint_test_data())
+    def test_SchedulingUnitBlueprint_allows_updating_scheduling_constraints_template_if_in_correct_state(self):
 
-    def test_TaskRelationBlueprint_gets_created_with_correct_creation_timestamp(self):
         # setup
-        before = datetime.utcnow()
-        entry = models.TaskRelationBlueprint.objects.create(**TaskRelationBlueprint_test_data(producer=self.producer, consumer=self.consumer))
+        constraints_3 = models.SchedulingConstraintsTemplate.objects.create(**SchedulingConstraintsTemplate_test_data(name='constraints_3'))
+        constraints_4 = models.SchedulingConstraintsTemplate.objects.create(**SchedulingConstraintsTemplate_test_data(name='constraints_4'))
+        scheduling_unit_blueprint = models.SchedulingUnitBlueprint.objects.create(**SchedulingUnitBlueprint_test_data())
+        scheduling_unit_blueprint.scheduling_constraints_template = constraints_3
+        scheduling_unit_blueprint.save()
 
-        after = datetime.utcnow()
+        task_blueprint = models.TaskBlueprint.objects.create(**TaskBlueprint_test_data(scheduling_unit_blueprint=scheduling_unit_blueprint))
+        subtask = models.Subtask.objects.create(**Subtask_test_data())
+        subtask.task_blueprints.set([task_blueprint])
+        subtask.save()
 
-        # assert
-        self.assertLess(before, entry.created_at)
-        self.assertGreater(after, entry.created_at)
+        scheduling_unit_blueprint.refresh_from_db()
 
-    def test_TaskRelationBlueprint_update_timestamp_gets_changed_correctly(self):
-        # setup
-        entry = models.TaskRelationBlueprint.objects.create(**TaskRelationBlueprint_test_data(producer=self.producer, consumer=self.consumer))
-        before = datetime.utcnow()
-        entry.save()
-        after = datetime.utcnow()
+        # we can still change the constraints
+        scheduling_unit_blueprint.scheduling_constraints_template = constraints_4
+        scheduling_unit_blueprint.save()
 
-        # assert
-        self.assertLess(before, entry.updated_at)
-        self.assertGreater(after, entry.updated_at)
+    def test_SchedulingUnitBlueprint_prevents_updating_scheduling_constraints_doc_if_not_in_correct_state(self):
 
-    def test_TaskRelationBlueprint_prevents_missing_selection_template(self):
         # setup
-        test_data = dict(TaskRelationBlueprint_test_data(producer=self.producer, consumer=self.consumer))
-        test_data['selection_template'] = None
+        scheduling_unit_blueprint = models.SchedulingUnitBlueprint.objects.create(**SchedulingUnitBlueprint_test_data())
+        task_blueprint = models.TaskBlueprint.objects.create(**TaskBlueprint_test_data(scheduling_unit_blueprint=scheduling_unit_blueprint))
+        subtask = models.Subtask.objects.create(**Subtask_test_data())
+        subtask.task_blueprints.set([task_blueprint])
+        subtask.state = models.SubtaskState.objects.get(value='error')  # the derived SUB status is then also error
+        subtask.save()
 
-        # assert
-        with self.assertRaises(IntegrityError):
-            models.TaskRelationBlueprint.objects.create(**test_data)
+        scheduling_unit_blueprint.refresh_from_db()
 
-    def test_TaskRelationBlueprint_prevents_missing_draft(self):
-        # setup
-        test_data = dict(TaskRelationBlueprint_test_data(producer=self.producer, consumer=self.consumer))
-        test_data['draft'] = None
+        # we should be able to modify other fields
+        scheduling_unit_blueprint.results_accepted = not scheduling_unit_blueprint.results_accepted
+        scheduling_unit_blueprint.save()
 
-        # assert
-        with self.assertRaises(IntegrityError):
-            models.TaskRelationBlueprint.objects.create(**test_data)
+        # but scheduling constraints should be immutable
+        with self.assertRaises(TMSSException) as context:
+            scheduling_unit_blueprint.scheduling_constraints_doc = {'foo': 'matic'}
+            scheduling_unit_blueprint.save()
 
-    def test_TaskRelationBlueprint_prevents_missing_producer(self):
-        # setup
-        test_data = dict(TaskRelationBlueprint_test_data(producer=self.producer, consumer=self.consumer))
-        test_data['producer'] = None
+        self.assertIn('schedulable state', str(context.exception))
 
-        # assert
-        with self.assertRaises(IntegrityError):
-            models.TaskRelationBlueprint.objects.create(**test_data)
+    def test_SchedulingUnitBlueprint_allows_updating_scheduling_constraints_doc_if_in_correct_state(self):
 
-    def test_TaskRelationBlueprint_prevents_missing_consumer(self):
         # setup
-        test_data = dict(TaskRelationBlueprint_test_data(producer=self.producer, consumer=self.consumer))
-        test_data['consumer'] = None
-
-        # assert
-        with self.assertRaises(IntegrityError):
-            models.TaskRelationBlueprint.objects.create(**test_data)
+        scheduling_unit_blueprint = models.SchedulingUnitBlueprint.objects.create(**SchedulingUnitBlueprint_test_data())
+        task_blueprint = models.TaskBlueprint.objects.create(**TaskBlueprint_test_data(scheduling_unit_blueprint=scheduling_unit_blueprint))
+        subtask = models.Subtask.objects.create(**Subtask_test_data())
+        subtask.task_blueprints.set([task_blueprint])
+        subtask.save()
 
-    def test_TaskRelationBlueprint_prevents_missing_input(self):
-        # setup
-        test_data = dict(TaskRelationBlueprint_test_data(producer=self.producer, consumer=self.consumer))
-        test_data['input_role'] = None
+        scheduling_unit_blueprint.refresh_from_db()
 
-        # assert
-        with self.assertRaises(IntegrityError):
-            models.TaskRelationBlueprint.objects.create(**test_data)
+        scheduling_unit_blueprint.scheduling_constraints_doc = {'foo': 'matic'}
+        scheduling_unit_blueprint.save()
 
-    def test_TaskRelationBlueprint_prevents_missing_output(self):
-        # setup
-        test_data = dict(TaskRelationBlueprint_test_data(producer=self.producer, consumer=self.consumer))
-        test_data['output_role'] = None
 
-        # assert
-        with self.assertRaises(IntegrityError):
-            models.TaskRelationBlueprint.objects.create(**test_data)
-
-
-
-
-class TestStationTimeLine(unittest.TestCase):
-    """
-    Actually this simple testcase should be in a separate module (t_tmssapp_calculations_django_API.py)
-    but I was just lazy and spare some overhead and I just 'piggyback' with this module
-    """
-
-    def test_StationTimeline_raises_Error_on_duplicate_station_timeline(self):
-        """
-        Test if adding a duplicate station-timestamp combination leads to an Error and so data is not inserted
-        """
-        import datetime
-
-        test_data = {"station_name": "CS001",
-                     "timestamp": datetime.date(2021, 4, 1),
-                     "sunrise_start": datetime.datetime(year=2021, month=4, day=1, hour=6, minute=1, second=0),
-                     "sunrise_end": datetime.datetime(year=2021, month=4, day=1, hour=7, minute=2, second=0),
-                     "sunset_start": datetime.datetime(year=2021, month=4, day=1, hour=20, minute=31, second=0),
-                     "sunset_end": datetime.datetime(year=2021, month=4, day=1, hour=21, minute=33, second=0) }
-
-        models.StationTimeline.objects.create(**test_data)
-        with self.assertRaises(IntegrityError) as context:
-            models.StationTimeline.objects.create(**test_data)
-            self.assertIn('unique_station_time_line', str(context.exception))
-
-        self.assertEqual(len(models.StationTimeline.objects.filter(timestamp=datetime.date(2021, 4, 1))), 1)
-        self.assertEqual(len(models.StationTimeline.objects.all()), 1)
-        # Add a non-duplicate
-        test_data["station_name"] = "CS002"
-        models.StationTimeline.objects.create(**test_data)
-        self.assertEqual(len(models.StationTimeline.objects.filter(timestamp=datetime.date(2021, 4, 1))), 2)
-        self.assertEqual(len(models.StationTimeline.objects.all()), 2)
+# class TaskBlueprintTest(unittest.TestCase):
+#     @classmethod
+#     def setUpClass(cls) -> None:
+#         cls.task_draft = models.TaskDraft.objects.create(**TaskDraft_test_data())
+#         cls.scheduling_unit_blueprint = models.SchedulingUnitBlueprint.objects.create(**SchedulingUnitBlueprint_test_data())
+#
+#     def test_TaskBlueprint_gets_created_with_correct_creation_timestamp(self):
+#
+#         # setup
+#         before = datetime.utcnow()
+#         entry = models.TaskBlueprint.objects.create(**TaskBlueprint_test_data(task_draft=self.task_draft, scheduling_unit_blueprint=self.scheduling_unit_blueprint))
+#
+#         after = datetime.utcnow()
+#
+#         # assert
+#         self.assertLess(before, entry.created_at)
+#         self.assertGreater(after, entry.created_at)
+#
+#     def test_TaskBlueprint_update_timestamp_gets_changed_correctly(self):
+#
+#         # setup
+#         entry = models.TaskBlueprint.objects.create(**TaskBlueprint_test_data(name=str(uuid.uuid4()), task_draft=self.task_draft, scheduling_unit_blueprint=self.scheduling_unit_blueprint))
+#         before = datetime.utcnow()
+#         entry.save()
+#         after = datetime.utcnow()
+#
+#         # assert
+#         self.assertLess(before, entry.updated_at)
+#         self.assertGreater(after, entry.updated_at)
+#
+#     def test_TaskBlueprint_prevents_missing_template(self):
+#
+#         # setup
+#         test_data = dict(TaskBlueprint_test_data(task_draft=self.task_draft, scheduling_unit_blueprint=self.scheduling_unit_blueprint))
+#         test_data['specifications_template'] = None
+#
+#         # assert
+#         with self.assertRaises(IntegrityError):
+#             models.TaskBlueprint.objects.create(**test_data)
+#
+#     def test_TaskBlueprint_prevents_missing_draft(self):
+#
+#         # setup
+#         test_data = dict(TaskBlueprint_test_data(task_draft=self.task_draft, scheduling_unit_blueprint=self.scheduling_unit_blueprint))
+#         test_data['draft'] = None
+#
+#         # assert
+#         with self.assertRaises(IntegrityError):
+#             models.TaskBlueprint.objects.create(**test_data)
+#
+#     def test_TaskBlueprint_prevents_draft_deletion(self):
+#         # setup
+#         test_data = dict(TaskBlueprint_test_data())
+#         blueprint = models.TaskBlueprint.objects.create(**test_data)
+#         draft = blueprint.draft
+#         with self.assertRaises(ProtectedError):
+#             draft.delete()
+#
+#     def test_TaskBlueprint_prevents_missing_scheduling_unit_blueprint(self):
+#
+#         # setup
+#         test_data = dict(TaskBlueprint_test_data(task_draft=self.task_draft, scheduling_unit_blueprint=self.scheduling_unit_blueprint))
+#         test_data['scheduling_unit_blueprint'] = None
+#
+#         # assert
+#         with self.assertRaises(IntegrityError):
+#             models.TaskBlueprint.objects.create(**test_data)
+#
+#     def test_TaskBlueprint_predecessors_and_successors_none(self):
+#         task_blueprint_1: models.TaskBlueprint = models.TaskBlueprint.objects.create(**TaskBlueprint_test_data(name=str(uuid.uuid4()), task_draft=self.task_draft, scheduling_unit_blueprint=self.scheduling_unit_blueprint))
+#         task_blueprint_2: models.TaskBlueprint = models.TaskBlueprint.objects.create(**TaskBlueprint_test_data(name=str(uuid.uuid4()), task_draft=self.task_draft, scheduling_unit_blueprint=self.scheduling_unit_blueprint))
+#
+#         self.assertEqual(set(), set(task_blueprint_1.predecessors.all()))
+#         self.assertEqual(set(), set(task_blueprint_2.predecessors.all()))
+#         self.assertEqual(set(), set(task_blueprint_1.successors.all()))
+#         self.assertEqual(set(), set(task_blueprint_2.successors.all()))
+#
+#     def test_TaskBlueprint_predecessors_and_successors_simple(self):
+#         task_blueprint_1: models.TaskBlueprint = models.TaskBlueprint.objects.create(**TaskBlueprint_test_data(name=str(uuid.uuid4()), task_draft=self.task_draft, scheduling_unit_blueprint=self.scheduling_unit_blueprint))
+#         task_blueprint_2: models.TaskBlueprint = models.TaskBlueprint.objects.create(**TaskBlueprint_test_data(name=str(uuid.uuid4()), task_draft=self.task_draft, scheduling_unit_blueprint=self.scheduling_unit_blueprint))
+#
+#         models.TaskRelationBlueprint.objects.create(**TaskRelationBlueprint_test_data(producer=task_blueprint_1, consumer=task_blueprint_2))
+#
+#         self.assertEqual(task_blueprint_1, task_blueprint_2.predecessors.all()[0])
+#         self.assertEqual(task_blueprint_2, task_blueprint_1.successors.all()[0])
+#
+#     def test_TaskBlueprint_predecessors_and_successors_complex(self):
+#         task_blueprint_1: models.TaskBlueprint = models.TaskBlueprint.objects.create(**TaskBlueprint_test_data(name=str(uuid.uuid4())))
+#         task_blueprint_2: models.TaskBlueprint = models.TaskBlueprint.objects.create(**TaskBlueprint_test_data(name=str(uuid.uuid4()), task_draft=task_blueprint_1.draft, scheduling_unit_blueprint=task_blueprint_1.scheduling_unit_blueprint))
+#         task_blueprint_3: models.TaskBlueprint = models.TaskBlueprint.objects.create(**TaskBlueprint_test_data(name=str(uuid.uuid4()), task_draft=task_blueprint_1.draft, scheduling_unit_blueprint=task_blueprint_1.scheduling_unit_blueprint))
+#         task_blueprint_4: models.TaskBlueprint = models.TaskBlueprint.objects.create(**TaskBlueprint_test_data(name=str(uuid.uuid4()), task_draft=task_blueprint_1.draft, scheduling_unit_blueprint=task_blueprint_1.scheduling_unit_blueprint))
+#         task_blueprint_5: models.TaskBlueprint = models.TaskBlueprint.objects.create(**TaskBlueprint_test_data(name=str(uuid.uuid4()), task_draft=task_blueprint_1.draft, scheduling_unit_blueprint=task_blueprint_1.scheduling_unit_blueprint))
+#         task_blueprint_6: models.TaskBlueprint = models.TaskBlueprint.objects.create(**TaskBlueprint_test_data(name=str(uuid.uuid4()), task_draft=task_blueprint_1.draft, scheduling_unit_blueprint=task_blueprint_1.scheduling_unit_blueprint))
+#
+#         # ST1 ---> ST3 ---> ST4
+#         #      |        |
+#         # ST2 -          -> ST5 ---> ST6
+#
+#         models.TaskRelationBlueprint.objects.create(**TaskRelationBlueprint_test_data(producer=task_blueprint_1, consumer=task_blueprint_3))
+#         trb1 = models.TaskRelationBlueprint.objects.create(**TaskRelationBlueprint_test_data(producer=task_blueprint_2, consumer=task_blueprint_3))
+#         models.TaskRelationBlueprint.objects.create(**TaskRelationBlueprint_test_data(producer=task_blueprint_3, consumer=task_blueprint_4))
+#         models.TaskRelationBlueprint.objects.create(**TaskRelationBlueprint_test_data(producer=task_blueprint_3, consumer=task_blueprint_5))
+#         models.TaskRelationBlueprint.objects.create(**TaskRelationBlueprint_test_data(producer=task_blueprint_5, consumer=task_blueprint_6))
+#
+#         self.assertEqual(set((task_blueprint_1, task_blueprint_2)), set(task_blueprint_3.predecessors.all()))
+#         self.assertEqual(set((task_blueprint_4, task_blueprint_5)), set(task_blueprint_3.successors.all()))
+#         self.assertEqual(set((task_blueprint_3,)), set(task_blueprint_4.predecessors.all()))
+#         self.assertEqual(set((task_blueprint_3,)), set(task_blueprint_5.predecessors.all()))
+#         self.assertEqual(set((task_blueprint_3,)), set(task_blueprint_1.successors.all()))
+#         self.assertEqual(set((task_blueprint_3,)), set(task_blueprint_2.successors.all()))
+#         self.assertEqual(set(), set(task_blueprint_1.predecessors.all()))
+#         self.assertEqual(set(), set(task_blueprint_2.predecessors.all()))
+#         self.assertEqual(set(), set(task_blueprint_4.successors.all()))
+#         self.assertEqual(set((task_blueprint_6,)), set(task_blueprint_5.successors.all()))
+#
+#
+# class TaskRelationBlueprintTest(unittest.TestCase):
+#     @classmethod
+#     def setUpClass(cls) -> None:
+#         cls.producer = models.TaskBlueprint.objects.create(**TaskBlueprint_test_data())
+#         cls.consumer = models.TaskBlueprint.objects.create(**TaskBlueprint_test_data())
+#
+#     def test_TaskRelationBlueprint_gets_created_with_correct_creation_timestamp(self):
+#         # setup
+#         before = datetime.utcnow()
+#         entry = models.TaskRelationBlueprint.objects.create(**TaskRelationBlueprint_test_data(producer=self.producer, consumer=self.consumer))
+#
+#         after = datetime.utcnow()
+#
+#         # assert
+#         self.assertLess(before, entry.created_at)
+#         self.assertGreater(after, entry.created_at)
+#
+#     def test_TaskRelationBlueprint_update_timestamp_gets_changed_correctly(self):
+#         # setup
+#         entry = models.TaskRelationBlueprint.objects.create(**TaskRelationBlueprint_test_data(producer=self.producer, consumer=self.consumer))
+#         before = datetime.utcnow()
+#         entry.save()
+#         after = datetime.utcnow()
+#
+#         # assert
+#         self.assertLess(before, entry.updated_at)
+#         self.assertGreater(after, entry.updated_at)
+#
+#     def test_TaskRelationBlueprint_prevents_missing_selection_template(self):
+#         # setup
+#         test_data = dict(TaskRelationBlueprint_test_data(producer=self.producer, consumer=self.consumer))
+#         test_data['selection_template'] = None
+#
+#         # assert
+#         with self.assertRaises(IntegrityError):
+#             models.TaskRelationBlueprint.objects.create(**test_data)
+#
+#     def test_TaskRelationBlueprint_prevents_missing_draft(self):
+#         # setup
+#         test_data = dict(TaskRelationBlueprint_test_data(producer=self.producer, consumer=self.consumer))
+#         test_data['draft'] = None
+#
+#         # assert
+#         with self.assertRaises(IntegrityError):
+#             models.TaskRelationBlueprint.objects.create(**test_data)
+#
+#     def test_TaskRelationBlueprint_prevents_missing_producer(self):
+#         # setup
+#         test_data = dict(TaskRelationBlueprint_test_data(producer=self.producer, consumer=self.consumer))
+#         test_data['producer'] = None
+#
+#         # assert
+#         with self.assertRaises(IntegrityError):
+#             models.TaskRelationBlueprint.objects.create(**test_data)
+#
+#     def test_TaskRelationBlueprint_prevents_missing_consumer(self):
+#         # setup
+#         test_data = dict(TaskRelationBlueprint_test_data(producer=self.producer, consumer=self.consumer))
+#         test_data['consumer'] = None
+#
+#         # assert
+#         with self.assertRaises(IntegrityError):
+#             models.TaskRelationBlueprint.objects.create(**test_data)
+#
+#     def test_TaskRelationBlueprint_prevents_missing_input(self):
+#         # setup
+#         test_data = dict(TaskRelationBlueprint_test_data(producer=self.producer, consumer=self.consumer))
+#         test_data['input_role'] = None
+#
+#         # assert
+#         with self.assertRaises(IntegrityError):
+#             models.TaskRelationBlueprint.objects.create(**test_data)
+#
+#     def test_TaskRelationBlueprint_prevents_missing_output(self):
+#         # setup
+#         test_data = dict(TaskRelationBlueprint_test_data(producer=self.producer, consumer=self.consumer))
+#         test_data['output_role'] = None
+#
+#         # assert
+#         with self.assertRaises(IntegrityError):
+#             models.TaskRelationBlueprint.objects.create(**test_data)
+#
+#
+#
+#
+# class TestStationTimeLine(unittest.TestCase):
+#     """
+#     Actually this simple testcase should be in a separate module (t_tmssapp_calculations_django_API.py)
+#     but I was just lazy and spare some overhead and I just 'piggyback' with this module
+#     """
+#
+#     def test_StationTimeline_raises_Error_on_duplicate_station_timeline(self):
+#         """
+#         Test if adding a duplicate station-timestamp combination leads to an Error and so data is not inserted
+#         """
+#         import datetime
+#
+#         test_data = {"station_name": "CS001",
+#                      "timestamp": datetime.date(2021, 4, 1),
+#                      "sunrise_start": datetime.datetime(year=2021, month=4, day=1, hour=6, minute=1, second=0),
+#                      "sunrise_end": datetime.datetime(year=2021, month=4, day=1, hour=7, minute=2, second=0),
+#                      "sunset_start": datetime.datetime(year=2021, month=4, day=1, hour=20, minute=31, second=0),
+#                      "sunset_end": datetime.datetime(year=2021, month=4, day=1, hour=21, minute=33, second=0) }
+#
+#         models.StationTimeline.objects.create(**test_data)
+#         with self.assertRaises(IntegrityError) as context:
+#             models.StationTimeline.objects.create(**test_data)
+#             self.assertIn('unique_station_time_line', str(context.exception))
+#
+#         self.assertEqual(len(models.StationTimeline.objects.filter(timestamp=datetime.date(2021, 4, 1))), 1)
+#         self.assertEqual(len(models.StationTimeline.objects.all()), 1)
+#         # Add a non-duplicate
+#         test_data["station_name"] = "CS002"
+#         models.StationTimeline.objects.create(**test_data)
+#         self.assertEqual(len(models.StationTimeline.objects.filter(timestamp=datetime.date(2021, 4, 1))), 2)
+#         self.assertEqual(len(models.StationTimeline.objects.all()), 2)
 
 
 if __name__ == "__main__":
diff --git a/SAS/TMSS/backend/test/tmss_test_data_django_models.py b/SAS/TMSS/backend/test/tmss_test_data_django_models.py
index 9b7024f59cb7d6f0f06e429dc72ffb08fd231ef2..538d5d7480920cc1ca4c924914f675e91e4c8892 100644
--- a/SAS/TMSS/backend/test/tmss_test_data_django_models.py
+++ b/SAS/TMSS/backend/test/tmss_test_data_django_models.py
@@ -191,7 +191,9 @@ def SchedulingSet_test_data(name="my_scheduling_set", project: models.Project=No
 
 def SchedulingUnitDraft_test_data(name="my_scheduling_unit_draft", scheduling_set: models.SchedulingSet=None,
                                   template: models.SchedulingUnitTemplate=None, requirements_doc: dict=None,
-                                  observation_strategy_template: models.SchedulingUnitObservingStrategyTemplate=None) -> dict:
+                                  observation_strategy_template: models.SchedulingUnitObservingStrategyTemplate=None,
+                                  scheduling_constraints_doc: dict=None,
+                                  scheduling_constraints_template: models.SchedulingConstraintsTemplate=None) -> dict:
     if scheduling_set is None:
         scheduling_set = models.SchedulingSet.objects.create(**SchedulingSet_test_data())
 
@@ -201,6 +203,12 @@ def SchedulingUnitDraft_test_data(name="my_scheduling_unit_draft", scheduling_se
     if requirements_doc is None:
         requirements_doc = get_default_json_object_for_schema(template.schema)
 
+    if scheduling_constraints_template is None:
+        scheduling_constraints_template = models.SchedulingConstraintsTemplate.objects.create(**SchedulingConstraintsTemplate_test_data())
+
+    if scheduling_constraints_doc is None:
+        scheduling_constraints_doc = get_default_json_object_for_schema(scheduling_constraints_template.schema)
+
     return {"name": name,
             "description": "",
             "tags": [],
@@ -210,7 +218,9 @@ def SchedulingUnitDraft_test_data(name="my_scheduling_unit_draft", scheduling_se
             "copies": None,
             "scheduling_set": scheduling_set,
             "requirements_template": template,
-            "observation_strategy_template": observation_strategy_template }
+            "observation_strategy_template": observation_strategy_template,
+            "scheduling_constraints_template": scheduling_constraints_template,
+            "scheduling_constraints_doc": scheduling_constraints_doc}
 
 def TaskDraft_test_data(name: str=None, specifications_template: models.TaskTemplate=None, specifications_doc: dict=None, scheduling_unit_draft: models.SchedulingUnitDraft=None, output_pinned=False) -> dict:
     if name is None:
@@ -251,6 +261,7 @@ def TaskRelationDraft_test_data(producer: models.TaskDraft = None, consumer: mod
             "selection_template": models.TaskRelationSelectionTemplate.objects.create(**TaskRelationSelectionTemplate_test_data())}
 
 def SchedulingUnitBlueprint_test_data(name=None, requirements_template: models.SchedulingUnitTemplate=None, draft=None, output_pinned=None) -> dict:
+
     if name is None:
         name = 'my_scheduling_unit_blueprint_' + str(uuid.uuid4())
 
diff --git a/SAS/TMSS/backend/test/tmss_test_environment_unittest_setup.py b/SAS/TMSS/backend/test/tmss_test_environment_unittest_setup.py
index 55d8da30199a0d79ac0aa9c43a6d67e465835931..2c3dd34f8f81bd2a256eaa7ffe5164408eb8de34 100644
--- a/SAS/TMSS/backend/test/tmss_test_environment_unittest_setup.py
+++ b/SAS/TMSS/backend/test/tmss_test_environment_unittest_setup.py
@@ -86,11 +86,13 @@ def _call_API_and_assert_expected_response(test_instance, url, call, data, expec
         for key, value in expected_content.items():
             if key not in r_dict.keys():
                 logger.error('!!! Missing key: %s in %s', key, r_dict.keys())
-            test_instance.assertTrue(key in r_dict.keys())
+            test_instance.assertIn(key, r_dict.keys())
             if isinstance(value, models.Model):
                 value = str(value.pk)
                 value = value.replace(' ', '%20')
-                test_instance.assertTrue(str(value) in r_dict[key])
+                if str(value) not in r_dict[key]:
+                    logger.error('!!! Unexpected value of key=%s: expected=%s got=%s', key, value, r_dict[key])
+                test_instance.assertIn(str(value), r_dict[key])
             elif type(value) is list:
                 test_instance.assertEqual(sorted(value), sorted(r_dict[key]), msg="lists differ for key=%s"%key) # compare lists independent of ordering
             elif isinstance(value, datetime.datetime):
diff --git a/SAS/TMSS/frontend/tmss_webapp/src/App.js b/SAS/TMSS/frontend/tmss_webapp/src/App.js
index ca7fab811ebe467a571c35f7a475e4678d545c07..3d4e9e0ac8152ae0a427918bf569f5668d1e0142 100644
--- a/SAS/TMSS/frontend/tmss_webapp/src/App.js
+++ b/SAS/TMSS/frontend/tmss_webapp/src/App.js
@@ -196,13 +196,13 @@ class App extends Component {
         //window.removeEventListener('popstate', this.onBackButtonEvent);
     }
 
-    close = () => {
+    close = () => {     
         this.setState({showDirtyDialog: false});
     }
     /**
      * Cancel edit and redirect to Cycle View page
      */
-    cancelEdit = () => {
+    cancelEdit = () => {        
         this.setState({ isEditDirty: false, showDirtyDialog: false });
         this.state.toPathCallback();
     }
diff --git a/SAS/TMSS/frontend/tmss_webapp/src/layout/sass/reservation.scss b/SAS/TMSS/frontend/tmss_webapp/src/layout/sass/reservation.scss
index 7372a5dcf271f473bdeb19f7c7a9a96b6f115fa3..5442a492fbfe35e2c694632c1caaa6aa98b931b0 100644
--- a/SAS/TMSS/frontend/tmss_webapp/src/layout/sass/reservation.scss
+++ b/SAS/TMSS/frontend/tmss_webapp/src/layout/sass/reservation.scss
@@ -9,4 +9,9 @@
     position: relative;
     top: 2.2em;
     width: 40em;
+}
+
+.p-field.p-grid, .p-formgrid.p-grid {
+    margin-left: -2px;
+    margin-top: 0;
 }
\ No newline at end of file
diff --git a/SAS/TMSS/frontend/tmss_webapp/src/routes/Reservation/reservation.create.js b/SAS/TMSS/frontend/tmss_webapp/src/routes/Reservation/reservation.create.js
index 5ed4ceff11c1bb985567f5e2159c49213b16e065..2b657133c940fa7dc3fa80f3178685ff8dd0b9d7 100644
--- a/SAS/TMSS/frontend/tmss_webapp/src/routes/Reservation/reservation.create.js
+++ b/SAS/TMSS/frontend/tmss_webapp/src/routes/Reservation/reservation.create.js
@@ -5,7 +5,7 @@ import { publish } from '../../App';
 import moment from 'moment';
 import { Growl } from 'primereact/components/growl/Growl';
 import { Dropdown } from 'primereact/dropdown';
-import {InputText } from 'primereact/inputtext';
+import { InputText } from 'primereact/inputtext';
 import { InputTextarea } from 'primereact/inputtextarea';
 import { Button } from 'primereact/button';
 import { Dialog } from 'primereact/components/dialog/Dialog';
@@ -14,11 +14,13 @@ import AppLoader from '../../layout/components/AppLoader';
 import PageHeader from '../../layout/components/PageHeader';
 import UIConstants from '../../utils/ui.constants';
 import { CustomDialog } from '../../layout/components/CustomDialog';
+import { InputMask } from 'primereact/inputmask';
 
 import ProjectService from '../../services/project.service';
 import ReservationService from '../../services/reservation.service';
 import Jeditor from '../../components/JSONEditor/JEditor';
 import UtilService from '../../services/util.service';
+import UnitConverter from '../../utils/unit.converter';
 
 import "flatpickr/dist/flatpickr.css";
 
@@ -28,22 +30,23 @@ import "flatpickr/dist/flatpickr.css";
 export class ReservationCreate extends Component {
     constructor(props) {
         super(props);
-        this.state= {
+        this.state = {
             showDialog: false,
             isDirty: false,
             isLoading: true,
-            redirect: null, 
+            redirect: null,
             paramsSchema: null,                     // JSON Schema to be generated from strategy template to pass to JSON editor 
-            dialog: { header: '', detail: ''},      // Dialog properties
+            dialog: { header: '', detail: '' },      // Dialog properties
             touched: {
                 name: '',
             },
-            reservation: { 
+            reservation: {
                 name: '',
-                description: '', 
+                description: '',
                 start_time: null,
                 stop_time: null,
-                project: (props.match?props.match.params.project:null) || null,
+                duration: null,
+                project: (props.match ? props.match.params.project : null) || null,
             },
             reservationStrategy: {
                 id: null,
@@ -59,10 +62,10 @@ export class ReservationCreate extends Component {
 
         // Validateion Rules
         this.formRules = {
-            name: {required: true, message: "Name can not be empty"},
-            description: {required: true, message: "Description can not be empty"},
-           // project: {required: true, message: "Project can not be empty"},
-            start_time: {required: true, message: "Start Time can not be empty"},
+            name: { required: true, message: "Name can not be empty" },
+            description: { required: true, message: "Description can not be empty" },
+            // project: {required: true, message: "Project can not be empty"},
+            start_time: { required: true, message: "Start Time can not be empty" },
         };
         this.tooltipOptions = UIConstants.tooltipOptions;
         this.setEditorOutput = this.setEditorOutput.bind(this);
@@ -74,22 +77,23 @@ export class ReservationCreate extends Component {
         this.initReservation = this.initReservation.bind(this);
         this.changeStrategy = this.changeStrategy.bind(this);
         this.setEditorFunction = this.setEditorFunction.bind(this);
+        this.isValidDuration = this.isValidDuration.bind(this);
     }
 
     async componentDidMount() {
         await this.initReservation();
     }
-    
+
     /**
      * Initialize the reservation and relevant details
      */
     async initReservation() {
-        const promises = [  ProjectService.getProjectList(),
-                            ReservationService.getReservationTemplates(),
-                            UtilService.getUTC(),
-                            ReservationService.getReservationStrategyTemplates()
-                        ];
-        let emptyProjects = [{url: null, name: "Select Project"}];
+        const promises = [ProjectService.getProjectList(),
+        ReservationService.getReservationTemplates(),
+        UtilService.getUTC(),
+        ReservationService.getReservationStrategyTemplates()
+        ];
+        let emptyProjects = [{ url: null, name: "Select Project" }];
         Promise.all(promises).then(responses => {
             this.projects = emptyProjects.concat(responses[0]);
             this.reservationTemplates = responses[1];
@@ -99,7 +103,7 @@ export class ReservationCreate extends Component {
             let schema = {
                 properties: {}
             };
-            if(reservationTemplate) {
+            if (reservationTemplate) {
                 schema = reservationTemplate.schema;
             }
             this.setState({
@@ -108,30 +112,31 @@ export class ReservationCreate extends Component {
                 reservationTemplate: reservationTemplate,
                 systemTime: systemTime,
             });
-        });    
-        
+        });
+
     }
-    
+
     /**
      * 
      * @param {Id} strategyId - id value of reservation strategy template
      */
     async changeStrategy(strategyId) {
-        this.setState({isLoading: true});
-        const reservationStrategy = _.find(this.reservationStrategies, {'id': strategyId});
+        this.setState({ isLoading: true });
+        const reservationStrategy = _.find(this.reservationStrategies, { 'id': strategyId });
         let paramsOutput = {};
-        if(reservationStrategy.template.parameters) {
+        if (reservationStrategy.template.parameters) {
             //if reservation strategy has parameter then prepare output parameter
 
-        }   else {
+        } else {
             paramsOutput = _.cloneDeep(reservationStrategy.template);
             delete paramsOutput["$id"];
         }
-        this.setState({ 
-                isLoading: false,
-                reservationStrategy: reservationStrategy,
-                paramsOutput: paramsOutput,
-                isDirty: true});
+        this.setState({
+            isLoading: false,
+            reservationStrategy: reservationStrategy,
+            paramsOutput: paramsOutput,
+            isDirty: true
+        });
         this.initReservation();
     }
 
@@ -143,23 +148,27 @@ export class ReservationCreate extends Component {
     setReservationParams(key, value) {
         let reservation = _.cloneDeep(this.state.reservation);
         reservation[key] = value;
-        if  ( !this.state.isDirty && !_.isEqual(this.state.reservation, reservation) ) {
-            this.setState({reservation: reservation, validForm: this.validateForm(key), validEditor: this.validateEditor(), touched: { 
-                ...this.state.touched,
-                [key]: true
-            }, isDirty: true});
+        if (!this.state.isDirty && !_.isEqual(this.state.reservation, reservation)) {
+            this.setState({
+                reservation: reservation, validForm: this.validateForm(key), validEditor: this.validateEditor(), touched: {
+                    ...this.state.touched,
+                    [key]: true
+                }, isDirty: true
+            });
             publish('edit-dirty', true);
-        }   else {
-            this.setState({reservation: reservation, validForm: this.validateForm(key), validEditor: this.validateEditor(),touched: { 
-                ...this.state.touched,
-                [key]: true
-            }});
+        } else {
+            this.setState({
+                reservation: reservation, validForm: this.validateForm(key), validEditor: this.validateEditor(), touched: {
+                    ...this.state.touched,
+                    [key]: true
+                }
+            });
         }
-    }
+    }    
 
-     /**
-     * This function is mainly added for Unit Tests. If this function is removed Unit Tests will fail.
-     */
+    /**
+    * This function is mainly added for Unit Tests. If this function is removed Unit Tests will fail.
+    */
     validateEditor() {
         return this.validEditor;
     }
@@ -171,20 +180,23 @@ export class ReservationCreate extends Component {
      */
     setParams(key, value, type) {
         let reservation = this.state.reservation;
-        switch(type) {
+        switch (type) {
             case 'NUMBER': {
-                reservation[key] = value?parseInt(value):0;
+                reservation[key] = value ? parseInt(value) : 0;
                 break;
             }
             default: {
-                reservation[key] = value;                
+                reservation[key] = value;
                 break;
             }
         }
-        this.setState({reservation: reservation, validForm: this.validateForm(key), isDirty: true});
+        this.setState({ reservation: reservation, validForm: this.validateForm(key), isDirty: true },
+            () => {
+                this.setDurationOrEndValue(key);
+            });
         publish('edit-dirty', true);
     }
-     
+
     /**
      * Validation function to validate the form or field based on the form rules.
      * If no argument passed for fieldName, validates all fields in the form.
@@ -202,13 +214,13 @@ export class ReservationCreate extends Component {
                 const fieldValue = this.state.reservation[fieldName];
                 if (rule.required) {
                     if (!fieldValue) {
-                        errors[fieldName] = rule.message?rule.message:`${fieldName} is required`;
-                    }   else {
+                        errors[fieldName] = rule.message ? rule.message : `${fieldName} is required`;
+                    } else {
                         validFields[fieldName] = true;
                     }
                 }
-            }  
-        }  else {
+            }
+        } else {
             errors = {};
             validFields = {};
             for (const fieldName in this.formRules) {
@@ -216,14 +228,14 @@ export class ReservationCreate extends Component {
                 const fieldValue = this.state.reservation[fieldName];
                 if (rule.required) {
                     if (!fieldValue) {
-                        errors[fieldName] = rule.message?rule.message:`${fieldName} is required`;
-                    }   else {
+                        errors[fieldName] = rule.message ? rule.message : `${fieldName} is required`;
+                    } else {
                         validFields[fieldName] = true;
                     }
                 }
             }
         }
-        this.setState({errors: errors, validFields: validFields});
+        this.setState({ errors: errors, validFields: validFields });
         if (Object.keys(validFields).length === Object.keys(this.formRules).length) {
             validForm = true;
             delete errors['start_time'];
@@ -239,7 +251,20 @@ export class ReservationCreate extends Component {
                 errors['stop_time'] = "End Time cannot be same or before Start Time";
                 delete errors['start_time'];
             }
-            this.setState({errors: errors});
+            this.setState({ errors: errors });
+        }
+        if (fieldName === 'duration' && this.state.reservation.duration) {
+            var values = this.state.reservation.duration.split(' ');
+            var days = values[0];
+            var dValues = values[1].split(':');           
+            delete errors['duration'];
+            if ((days *1 )===0 && (dValues[0] * 1) === 0 && (dValues[1] * 1) === 0 && (dValues[2] * 1) === 0) {
+                validForm = false;
+                if (!fieldName || fieldName === 'duration') {
+                    errors['duration'] = "Duration cannot be zero";
+                }
+                this.setState({ errors: errors });
+            }
         }
         return validForm;
     }
@@ -260,31 +285,35 @@ export class ReservationCreate extends Component {
     setEditorOutput(jsonOutput, errors) {
         this.paramsOutput = jsonOutput;
         this.validEditor = errors.length === 0;
-        if  ( !this.state.isDirty && this.state.paramsOutput && !_.isEqual(this.state.paramsOutput, jsonOutput) ) {
-            this.setState({ paramsOutput: jsonOutput, 
+        if (!this.state.isDirty && this.state.paramsOutput && !_.isEqual(this.state.paramsOutput, jsonOutput)) {
+            this.setState({
+                paramsOutput: jsonOutput,
                 validEditor: errors.length === 0,
                 validForm: this.validateForm(),
-                isDirty: true});
-                publish('edit-dirty', true);
-        }   else {
-            this.setState({ paramsOutput: jsonOutput, 
+                isDirty: true
+            });
+            publish('edit-dirty', true);
+        } else {
+            this.setState({
+                paramsOutput: jsonOutput,
                 validEditor: errors.length === 0,
-                validForm: this.validateForm()});
+                validForm: this.validateForm()
+            });
         }
     }
 
-    async saveReservation(){
+    async saveReservation() {
         let reservation = this.state.reservation;
         let project = this.projects.find(project => project.name === reservation.project);
         reservation['start_time'] = moment(reservation['start_time']).format(UIConstants.CALENDAR_DATETIME_FORMAT);
-        reservation['stop_time'] = reservation['stop_time']?moment(reservation['stop_time']).format(UIConstants.CALENDAR_DATETIME_FORMAT):null;
-        reservation['project']=  project ? project.url: null;
-        reservation['specifications_template']= this.reservationTemplates[0].url;
-        reservation['specifications_doc']= this.paramsOutput;
-        reservation = await ReservationService.saveReservation(reservation); 
-        if (reservation && reservation.id){
-            const dialog = {header: 'Success', detail: 'Reservation is created successfully. Do you want to create another Reservation?'};
-            this.setState({ dialogVisible: true, dialog: dialog,  paramsOutput: {}, showDialog: false, isDirty: false})
+        reservation['stop_time'] = reservation['stop_time'] ? moment(reservation['stop_time']).format(UIConstants.CALENDAR_DATETIME_FORMAT) : null;
+        reservation['project'] = project ? project.url : null;
+        reservation['specifications_template'] = this.reservationTemplates[0].url;
+        reservation['specifications_doc'] = this.paramsOutput;
+        reservation = await ReservationService.saveReservation(reservation);
+        if (reservation && reservation.id) {
+            const dialog = { header: 'Success', detail: 'Reservation is created successfully. Do you want to create another Reservation?' };
+            this.setState({ dialogVisible: true, dialog: dialog, paramsOutput: {}, showDialog: false, isDirty: false })
             publish('edit-dirty', false);
         }/*  else {
             this.growl.show({severity: 'error', summary: 'Error Occured', detail: 'Unable to save Reservation', showDialog: false, isDirty: false});
@@ -295,40 +324,40 @@ export class ReservationCreate extends Component {
      * Reset function to be called when user wants to create new Reservation
      */
     reset() {
-        let tmpReservation= { 
+        let tmpReservation = {
             name: '',
-            description: '', 
+            description: '',
             start_time: '',
             stop_time: '',
             project: '',
         }
         this.setState({
             dialogVisible: false,
-            dialog: { header: '', detail: ''},      
+            dialog: { header: '', detail: '' },
             errors: [],
             reservation: tmpReservation,
             reservationStrategy: {
                 id: null,
             },
-            paramsSchema: null, 
+            paramsSchema: null,
             paramsOutput: null,
             validEditor: false,
             validFields: {},
-            touched:false,
+            touched: false,
             stationGroup: [],
-            showDialog: false, 
+            showDialog: false,
             isDirty: false
         });
         this.initReservation();
     }
 
-      /**
-     * Cancel Reservation creation and redirect
-     */
-    cancelCreate() {
+    /**
+   * Cancel Reservation creation and redirect
+   */
+    cancelCreate() {       
         publish('edit-dirty', false);
         this.props.history.goBack();
-        this.setState({showDialog: false});
+        this.setState({ showDialog: false });
         this.props.history.goBack();
     }
 
@@ -336,15 +365,15 @@ export class ReservationCreate extends Component {
      * warn before cancel the page if any changes detected 
      */
     checkIsDirty() {
-        if( this.state.isDirty ){
-            this.setState({showDialog: true});
+        if (this.state.isDirty) {
+            this.setState({ showDialog: true });
         } else {
             this.cancelCreate();
         }
     }
-    
+
     close() {
-        this.setState({showDialog: false});
+        this.setState({ showDialog: false });
     }
 
     /**
@@ -352,121 +381,130 @@ export class ReservationCreate extends Component {
      * @param {Function} editorFunction 
      */
     setEditorFunction(editorFunction) {
-        this.setState({editorFunction: editorFunction});
+        this.setState({ editorFunction: editorFunction });
     }
-    
+
+    /**
+     * Function to set the value for the dependant fields when value is set to one field.
+     * When start_time or stop_time is changed, duration will be updated accordingly.
+     * Similarly if duration is changed, stop_time is updated.
+     * @param {String} key - property name of the reservation
+     */
+    setDurationOrEndValue = (key) => {
+        let state = this.state;
+        if (key === 'start_time' || key === 'stop_time') {
+            if (this.state.reservation.start_time && this.state.reservation.stop_time) {              
+                var delta = Math.abs(this.state.reservation.start_time - this.state.reservation.stop_time) / 1000;
+                let tempDuration = UnitConverter.getSecsToDDHHmmss(delta);             
+                this.setDurationOrStopTime('duration', tempDuration);
+            }   else if (key === 'start_time' && this.state.reservation.start_time && this.state.reservation.duration) {
+                let stopDate = UnitConverter.getEndDateFromDuration(this.state.reservation.start_time, this.state.reservation.duration);               
+                this.setDurationOrStopTime('stop_time', stopDate);
+            }   else if (key === 'stop_time' && !this.state.reservation.stop_time) {
+                this.setDurationOrStopTime('duration', "");
+            }
+        }
+        else if (key === 'duration') {
+            if (this.state.reservation.start_time) {   
+                let stopDate = UnitConverter.getEndDateFromDuration(this.state.reservation.start_time, this.state.reservation.duration);               
+                this.setDurationOrStopTime('stop_time', stopDate);
+            }
+        }
+    }
+
+    /**
+     * Function to set calcualted value for either duration or stop_time
+     * @param {String} key - name of the field
+     * @param {*} value - value to set for the field
+     */
+    setDurationOrStopTime(key, value) {
+        let reservation = this.state.reservation;
+        reservation[key] = value;
+        this.setState({ reservation: reservation, validForm: this.validateForm(key), isDirty: true });
+    }
+
+    /**
+     * Function to validate the duration field.
+     * @param {String} value - Duration in format 'Days HH:mm:ss'
+     * @returns boolean
+     */
+    isValidDuration(value) {
+        let errors = this.state.errors;
+        let touched = this.state.touched;
+        let reservation = this.state.reservation;
+        let validForm = this.state.validForm;
+        if (value.length === 12 && (value === "000 00:00:00" ||
+            !value.match(/^([0-1]90 00:00:00)|([0-1][0-8][0-9] ([0-1]?\d|2[0-3]):([0-5]?\d):([0-5]?\d))$/))) {
+            errors.duration = "Not valid duration. Duration should be in Days Hours:minutes:seconds. Min - 000 00:00:01, Max - 190 00:00:00";
+            touched.duration = true;
+            validForm = false;
+        }   else {
+            delete errors["duration"];
+            delete touched["duration"];
+            validForm = this.validateForm();
+        }
+        reservation.duration = value;
+        this.setState({errors: errors, touched: touched, reservation: reservation, validForm: validForm});
+        return errors.duration?false:true;
+    }
+
     render() {
         if (this.state.redirect) {
-            return <Redirect to={ {pathname: this.state.redirect} }></Redirect>
+            return <Redirect to={{ pathname: this.state.redirect }}></Redirect>
         }
         const schema = this.state.paramsSchema;
-        
         let jeditor = null;
         if (schema) {
             if (this.state.reservation.specifications_doc) {
                 delete this.state.reservation.specifications_doc.$id;
                 delete this.state.reservation.specifications_doc.$schema;
             }
-		   jeditor = React.createElement(Jeditor, {title: "Reservation Parameters", 
-                                                        schema: schema,
-                                                        initValue: this.state.paramsOutput, 
-                                                        callback: this.setEditorOutput,
-                                                        parentFunction: this.setEditorFunction
-                                                    }); 
+            jeditor = React.createElement(Jeditor, {
+                title: "Reservation Parameters",
+                schema: schema,
+                initValue: this.state.paramsOutput,
+                callback: this.setEditorOutput,
+                parentFunction: this.setEditorFunction
+            });
         }
         return (
             <React.Fragment>
                 <Growl ref={(el) => this.growl = el} />
-                <PageHeader location={this.props.location} title={'Reservation - Add'} 
-                           actions={[{icon: 'fa-window-close' ,title:'Click to close Reservation creation', 
-                           type: 'button',  actOn: 'click', props:{ callback: this.checkIsDirty }}]}/>
+                <PageHeader location={this.props.location} title={'Reservation - Add'}
+                    actions={[{
+                        icon: 'fa-window-close', title: 'Click to close Reservation creation',
+                        type: 'button', actOn: 'click', props: { callback: this.checkIsDirty }
+                    }]} />
                 { this.state.isLoading ? <AppLoader /> :
-                <> 
-                    <div>
-                        <div className="p-fluid">
-                            <div className="p-field p-grid">
-                                <label htmlFor="reservationname" className="col-lg-2 col-md-2 col-sm-12">Name <span style={{color:'red'}}>*</span></label>
-                                <div className="col-lg-3 col-md-3 col-sm-12">
-                                    <InputText className={(this.state.errors.name && this.state.touched.name) ?'input-error':''} id="reservationname" data-testid="name" 
-                                                tooltip="Enter name of the Reservation Name" tooltipOptions={this.tooltipOptions} maxLength="128"
-                                                ref={input => {this.nameInput = input;}}
-                                                value={this.state.reservation.name} autoFocus
-                                                onChange={(e) => this.setReservationParams('name', e.target.value)}
-                                                onBlur={(e) => this.setReservationParams('name', e.target.value)}/>
-                                    <label className={(this.state.errors.name && this.state.touched.name)?"error":"info"}>
-                                        {this.state.errors.name && this.state.touched.name ? this.state.errors.name : "Max 128 characters"}
-                                    </label>
-                                </div>
-                                <div className="col-lg-1 col-md-1 col-sm-12"></div>
-                                <label htmlFor="description" className="col-lg-2 col-md-2 col-sm-12">Description <span style={{color:'red'}}>*</span></label>
-                                <div className="col-lg-3 col-md-3 col-sm-12">
-                                    <InputTextarea className={(this.state.errors.description && this.state.touched.description) ?'input-error':''} rows={3} cols={30} 
-                                                tooltip="Longer description of the Reservation" 
-                                                tooltipOptions={this.tooltipOptions}
-                                                maxLength="128"
-                                                data-testid="description" 
-                                                value={this.state.reservation.description} 
-                                                onChange={(e) => this.setReservationParams('description', e.target.value)}
-                                                onBlur={(e) => this.setReservationParams('description', e.target.value)}/>
-                                    <label className={(this.state.errors.description && this.state.touched.description) ?"error":"info"}>
-                                        {(this.state.errors.description && this.state.touched.description) ? this.state.errors.description : "Max 255 characters"}
-                                    </label>
-                                </div>
-                            </div>
-                            <div className="p-field p-grid">
-                                    <label className="col-lg-2 col-md-2 col-sm-12">Start Time <span style={{color:'red'}}>*</span></label>
+                    <>
+                        <div>
+                            <div className="p-fluid">
+                                <div className="p-field p-grid">
+                                    <label htmlFor="reservationname" className="col-lg-2 col-md-2 col-sm-12">Name <span style={{ color: 'red' }}>*</span></label>
                                     <div className="col-lg-3 col-md-3 col-sm-12">
-                                        <Flatpickr data-enable-time data-input options={{
-                                                    "inlineHideInput": true,
-                                                    "wrap": true,
-                                                    "enableSeconds": true,
-                                                    "time_24hr": true,
-                                                    "minuteIncrement": 1,
-                                                    "allowInput": true,
-                                                    "defaultDate": this.state.systemTime.format(UIConstants.CALENDAR_DEFAULTDATE_FORMAT),
-                                                    "defaultHour": this.state.systemTime.hours(),
-                                                    "defaultMinute": this.state.systemTime.minutes()
-                                                    }}
-                                                    title="Start of this reservation"
-                                                    value={this.state.reservation.start_time}
-                                                    onChange= {value => {this.setParams('start_time', value[0]?value[0]:this.state.reservation.start_time);
-                                                        this.setReservationParams('start_time', value[0]?value[0]:this.state.reservation.start_time)}} >
-                                            <input type="text" data-input className={`p-inputtext p-component ${this.state.errors.start_time && this.state.touched.start_time?'input-error':''}`} />
-                                            <i className="fa fa-calendar" data-toggle style={{position: "absolute", marginLeft: '-25px', marginTop:'5px', cursor: 'pointer'}} ></i>
-                                            <i className="fa fa-times" style={{position: "absolute", marginLeft: '-50px', marginTop:'5px', cursor: 'pointer'}} 
-                                                onClick={e => {this.setParams('start_time', ''); this.setReservationParams('start_time', '')}}></i>
-                                        </Flatpickr>
-                                        <label className={this.state.errors.start_time && this.state.touched.start_time?"error":"info"}>
-                                            {this.state.errors.start_time && this.state.touched.start_time ? this.state.errors.start_time : ""}
+                                        <InputText className={(this.state.errors.name && this.state.touched.name) ? 'input-error' : ''} id="reservationname" data-testid="name"
+                                            tooltip="Enter name of the Reservation Name" tooltipOptions={this.tooltipOptions} maxLength="128"
+                                            ref={input => { this.nameInput = input; }}
+                                            value={this.state.reservation.name} autoFocus
+                                            onChange={(e) => this.setReservationParams('name', e.target.value)}
+                                            onBlur={(e) => this.setReservationParams('name', e.target.value)} />
+                                        <label className={(this.state.errors.name && this.state.touched.name) ? "error" : "info"}>
+                                            {this.state.errors.name && this.state.touched.name ? this.state.errors.name : "Max 128 characters"}
                                         </label>
                                     </div>
                                     <div className="col-lg-1 col-md-1 col-sm-12"></div>
-                             
-                                    <label className="col-lg-2 col-md-2 col-sm-12">End Time</label>
+                                    <label htmlFor="description" className="col-lg-2 col-md-2 col-sm-12">Description <span style={{ color: 'red' }}>*</span></label>
                                     <div className="col-lg-3 col-md-3 col-sm-12">
-                                        <Flatpickr data-enable-time data-input options={{
-                                                    "inlineHideInput": true,
-                                                    "wrap": true,
-                                                    "enableSeconds": true,
-                                                    "time_24hr": true,
-                                                    "minuteIncrement": 1,
-                                                    "allowInput": true,
-                                                    "minDate": this.state.reservation.start_time?this.state.reservation.start_time.toDate:'',
-                                                    "defaultDate": this.state.systemTime.format(UIConstants.CALENDAR_DEFAULTDATE_FORMAT),
-                                                    "defaultHour": this.state.systemTime.hours(),
-                                                    "defaultMinute": this.state.systemTime.minutes()
-                                                    }}
-                                                    title="End of this reservation. If empty, then this reservation is indefinite."
-                                                    value={this.state.reservation.stop_time}
-                                                    onChange= {value => {this.setParams('stop_time', value[0]?value[0]:this.state.reservation.stop_time);
-                                                                            this.setReservationParams('stop_time', value[0]?value[0]:this.state.reservation.stop_time)}} >
-                                            <input type="text" data-input className={`p-inputtext p-component ${this.state.errors.stop_time && this.state.touched.stop_time?'input-error':''}`} />
-                                            <i className="fa fa-calendar" data-toggle style={{position: "absolute", marginLeft: '-25px', marginTop:'5px', cursor: 'pointer'}} ></i>
-                                            <i className="fa fa-times" style={{position: "absolute", marginLeft: '-50px', marginTop:'5px', cursor: 'pointer'}} 
-                                                onClick={e => {this.setParams('stop_time', ''); this.setReservationParams('stop_time', '')}}></i>
-                                        </Flatpickr>
-                                        <label className={this.state.errors.stop_time && this.state.touched.stop_time?"error":"info"}>
-                                            {this.state.errors.stop_time && this.state.touched.stop_time ? this.state.errors.stop_time : ""}
+                                        <InputTextarea className={(this.state.errors.description && this.state.touched.description) ? 'input-error' : ''} rows={3} cols={30}
+                                            tooltip="Longer description of the Reservation"
+                                            tooltipOptions={this.tooltipOptions}
+                                            maxLength="128"
+                                            data-testid="description"
+                                            value={this.state.reservation.description}
+                                            onChange={(e) => this.setReservationParams('description', e.target.value)}
+                                            onBlur={(e) => this.setReservationParams('description', e.target.value)} />
+                                        <label className={(this.state.errors.description && this.state.touched.description) ? "error" : "info"}>
+                                            {(this.state.errors.description && this.state.touched.description) ? this.state.errors.description : "Max 255 characters"}
                                         </label>
                                     </div>
                                 </div>
@@ -474,74 +512,160 @@ export class ReservationCreate extends Component {
                                 <div className="p-field p-grid">
                                     <label htmlFor="project" className="col-lg-2 col-md-2 col-sm-12">Project</label>
                                     <div className="col-lg-3 col-md-3 col-sm-12" data-testid="project" >
-                                        <Dropdown inputId="project" optionLabel="name" optionValue="name" 
-                                                tooltip="Project" tooltipOptions={this.tooltipOptions}
-                                                value={this.state.reservation.project}
-                                                options={this.projects} 
-                                                onChange={(e) => {this.setParams('project',e.value)}} 
-                                                placeholder="Select Project" />
-                                        <label className={(this.state.errors.project && this.state.touched.project) ?"error":"info"}>
+                                        <Dropdown inputId="project" optionLabel="name" optionValue="name"
+                                            tooltip="Project" tooltipOptions={this.tooltipOptions}
+                                            value={this.state.reservation.project}
+                                            options={this.projects}
+                                            onChange={(e) => { this.setParams('project', e.value) }}
+                                            placeholder="Select Project" />
+                                        <label className={(this.state.errors.project && this.state.touched.project) ? "error" : "info"}>
                                             {(this.state.errors.project && this.state.touched.project) ? this.state.errors.project : "Select Project"}
                                         </label>
                                     </div>
                                     <div className="col-lg-1 col-md-1 col-sm-12"></div>
                                     <label htmlFor="strategy" className="col-lg-2 col-md-2 col-sm-12">Reservation Strategy</label>
                                     <div className="col-lg-3 col-md-3 col-sm-12" data-testid="strategy" >
-                                        <Dropdown inputId="strategy" optionLabel="name" optionValue="id" 
-                                                tooltip="Choose Reservation Strategy Template to set default values for create Reservation" tooltipOptions={this.tooltipOptions}
-                                                value={this.state.reservationStrategy.id} 
-                                                options={this.reservationStrategies} 
-                                                onChange={(e) => {this.changeStrategy(e.value)}} 
-                                                placeholder="Select Strategy" />
-                                        <label className={(this.state.errors.reservationStrategy && this.state.touched.reservationStrategy) ?"error":"info"}>
+                                        <Dropdown inputId="strategy" optionLabel="name" optionValue="id"
+                                            tooltip="Choose Reservation Strategy Template to set default values for create Reservation" tooltipOptions={this.tooltipOptions}
+                                            value={this.state.reservationStrategy.id}
+                                            options={this.reservationStrategies}
+                                            onChange={(e) => { this.changeStrategy(e.value) }}
+                                            placeholder="Select Strategy" />
+                                        <label className={(this.state.errors.reservationStrategy && this.state.touched.reservationStrategy) ? "error" : "info"}>
                                             {(this.state.errors.reservationStrategy && this.state.touched.reservationStrategy) ? this.state.errors.reservationStrategy : "Select Reservation Strategy Template"}
                                         </label>
                                     </div>
+
+                                    <div className="p-field p-grid">
+                                        <label className="col-lg-2 col-md-2 col-sm-12">Start Time <span style={{ color: 'red' }}>*</span></label>
+                                        <div className="col-lg-3 col-md-3 col-sm-12">
+                                            <Flatpickr data-enable-time data-input options={{
+                                                "inlineHideInput": true,
+                                                "wrap": true,
+                                                "enableSeconds": true,
+                                                "time_24hr": true,
+                                                "minuteIncrement": 1,
+                                                "allowInput": true,
+                                                "defaultDate": this.state.systemTime.format(UIConstants.CALENDAR_DEFAULTDATE_FORMAT),
+                                                "defaultHour": this.state.systemTime.hours(),
+                                                "defaultMinute": this.state.systemTime.minutes()
+                                            }}
+                                                title="Start of this reservation"
+                                                value={this.state.reservation.start_time}
+                                                onChange={value => {
+                                                    this.setParams('start_time', value[0] ? value[0] : this.state.reservation.start_time);
+                                                    this.setReservationParams('start_time', value[0] ? value[0] : this.state.reservation.start_time)
+                                                }} >
+                                                <input type="text" data-input className={`p-inputtext p-component ${this.state.errors.start_time && this.state.touched.start_time ? 'input-error' : ''}`} />
+                                                <i className="fa fa-calendar" data-toggle style={{ position: "absolute", marginLeft: '-25px', marginTop: '5px', cursor: 'pointer' }} ></i>
+                                                <i className="fa fa-times" style={{ position: "absolute", marginLeft: '-50px', marginTop: '5px', cursor: 'pointer' }}
+                                                    onClick={e => { this.setParams('start_time', ''); this.setReservationParams('start_time', '') }}></i>
+                                            </Flatpickr>
+                                            <label className={this.state.errors.start_time && this.state.touched.start_time ? "error" : "info"}>
+                                                {this.state.errors.start_time && this.state.touched.start_time ? this.state.errors.start_time : ""}
+                                            </label>
+                                        </div>
+                                        <div className="col-lg-1 col-md-1 col-sm-12"></div>
+                                        <label className="col-lg-2 col-md-2 col-sm-12">End Time</label>
+                                        <div className="col-lg-3 col-md-3 col-sm-12">
+                                            <Flatpickr data-enable-time data-input options={{
+                                                "inlineHideInput": true,
+                                                "wrap": true,
+                                                "enableSeconds": true,
+                                                "time_24hr": true,
+                                                "minuteIncrement": 1,
+                                                "allowInput": true,
+                                                "minDate": this.state.reservation.start_time ? this.state.reservation.start_time.toDate : '',
+                                                "defaultDate": this.state.systemTime.format(UIConstants.CALENDAR_DEFAULTDATE_FORMAT),
+                                                "defaultHour": this.state.systemTime.hours(),
+                                                "defaultMinute": this.state.systemTime.minutes()
+                                            }}
+                                                title="End of this reservation. If empty, then this reservation is indefinite."
+                                                value={this.state.reservation.stop_time}
+                                                onChange={value => {
+                                                    this.setParams('stop_time', value[0] ? value[0] : this.state.reservation.stop_time);
+                                                    this.setReservationParams('stop_time', value[0] ? value[0] : this.state.reservation.stop_time)
+                                                }} >
+                                                <input type="text" data-input className={`p-inputtext p-component ${this.state.errors.stop_time && this.state.touched.stop_time ? 'input-error' : ''}`} />
+                                                <i className="fa fa-calendar" data-toggle style={{ position: "absolute", marginLeft: '-25px', marginTop: '5px', cursor: 'pointer' }} ></i>
+                                                <i className="fa fa-times" style={{ position: "absolute", marginLeft: '-50px', marginTop: '5px', cursor: 'pointer' }}
+                                                    onClick={e => { this.setParams('stop_time', ''); this.setReservationParams('stop_time', '') }}></i>
+                                            </Flatpickr>
+                                            <label className={this.state.errors.stop_time && this.state.touched.stop_time ? "error" : "info"}>
+                                                {this.state.errors.stop_time && this.state.touched.stop_time ? this.state.errors.stop_time : ""}
+                                            </label>
+                                        </div>
+                                    </div>
+
+                                    <div className="p-field p-grid">
+                                        <label className="col-lg-2 col-md-2 col-sm-12">Duration</label>
+                                        <div className="col-lg-3 col-md-3 col-sm-12">
+                                            <InputMask mask="999 99:99:99"
+                                                tooltip="Enter duration in (Days HH:mm:ss) format. Min-000 00:00:01 & Max-190 00:00:00."
+                                                tooltipOptions={this.tooltipOptions} 
+                                                value={this.state.reservation.duration}
+                                                placeholder="DDD HH:mm:ss"
+                                                onChange={(e) =>{if(!e.value) {this.setDurationOrEndValue("stop_time")}}}
+                                                onComplete={(e) => {
+                                                    if (this.isValidDuration(e.value)) {
+                                                        this.setReservationParams('duration', e.value);
+                                                        this.setParams('duration', e.value ? e.value : this.state.reservation.duration);
+                                                    }
+                                                }}
+                                                onBlur={(e) => {
+                                                    this.setParams('duration', e.value ? e.value : this.setDurationOrEndValue("stop_time"));
+                                                }}></InputMask>
+                                            <label className={this.state.errors.duration && this.state.touched.duration ? "error" : "info"}>
+                                                {this.state.errors.duration && this.state.touched.duration ? this.state.errors.duration : ""}
+                                            </label>
+                                        </div>
+                                    </div>
                                 </div>
 
                                 <div className="p-grid">
                                     <div className="p-col-12">
-                                        {this.state.paramsSchema?jeditor:""}
+                                        {this.state.paramsSchema ? jeditor : ""}
                                     </div>
                                 </div>
-                        </div>
+                            </div>
 
-                        <div className="p-grid p-justify-start">
-                            <div className="p-col-1">
-                                <Button label="Save" className="p-button-primary" icon="pi pi-check" onClick={this.saveReservation} 
+
+                            <div className="p-grid p-justify-start">
+                                <div className="p-col-1">
+                                    <Button label="Save" className="p-button-primary" icon="pi pi-check" onClick={this.saveReservation}
                                         disabled={!this.state.validEditor || !this.state.validForm} data-testid="save-btn" />
-                            </div>
-                            <div className="p-col-1">
-                                <Button label="Cancel" className="p-button-danger" icon="pi pi-times" onClick={this.checkIsDirty}  />
+                                </div>
+                                <div className="p-col-1">
+                                    <Button label="Cancel" className="p-button-danger" icon="pi pi-times" onClick={this.checkIsDirty} />
+                                </div>
                             </div>
                         </div>
-                    </div>
-                </>
+                    </>
                 }
 
                 {/* Dialog component to show messages and get input */}
                 <div className="p-grid" data-testid="confirm_dialog">
-                    <Dialog header={this.state.dialog.header} visible={this.state.dialogVisible} style={{width: '25vw'}} inputId="confirm_dialog"
-                            modal={true}  onHide={() => {this.setState({dialogVisible: false})}} 
-                            footer={<div>
-                                <Button key="back" onClick={() => {this.setState({dialogVisible: false, redirect: `/reservation/list`});}} label="No" />
-                                <Button key="submit" type="primary" onClick={this.reset} label="Yes" />
-                                </div>
-                            } >
-                            <div className="p-grid">
-                                <div className="col-lg-2 col-md-2 col-sm-2" style={{margin: 'auto'}}>
-                                    <i className="pi pi-check-circle pi-large pi-success"></i>
-                                </div>
-                                <div className="col-lg-10 col-md-10 col-sm-10">
-                                    {this.state.dialog.detail}
-                                </div>
+                    <Dialog header={this.state.dialog.header} visible={this.state.dialogVisible} style={{ width: '25vw' }} inputId="confirm_dialog"
+                        modal={true} onHide={() => { this.setState({ dialogVisible: false }) }}
+                        footer={<div>
+                            <Button key="back" onClick={() => { this.setState({ dialogVisible: false, redirect: `/reservation/list` }); }} label="No" />
+                            <Button key="submit" type="primary" onClick={this.reset} label="Yes" />
+                        </div>
+                        } >
+                        <div className="p-grid">
+                            <div className="col-lg-2 col-md-2 col-sm-2" style={{ margin: 'auto' }}>
+                                <i className="pi pi-check-circle pi-large pi-success"></i>
                             </div>
+                            <div className="col-lg-10 col-md-10 col-sm-10">
+                                {this.state.dialog.detail}
+                            </div>
+                        </div>
                     </Dialog>
 
                     <CustomDialog type="confirmation" visible={this.state.showDialog} width="40vw"
-                            header={'Add Reservation'} message={'Do you want to leave this page? Your changes may not be saved.'} 
-                            content={''} onClose={this.close} onCancel={this.close} onSubmit={this.cancelCreate}>
-                        </CustomDialog>
+                        header={'Add Reservation'} message={'Do you want to leave this page? Your changes may not be saved.'}
+                        content={''} onClose={this.cancelCreate} onCancel={this.close} onSubmit={this.cancelCreate}>
+                    </CustomDialog>
                 </div>
             </React.Fragment>
         );
diff --git a/SAS/TMSS/frontend/tmss_webapp/src/routes/Reservation/reservation.edit.js b/SAS/TMSS/frontend/tmss_webapp/src/routes/Reservation/reservation.edit.js
index 255eea3828b4cd62a3190ca0a4417ab2f87f5176..46e6f0f87d0ad4e0461e67ed4d31ae49e732c574 100644
--- a/SAS/TMSS/frontend/tmss_webapp/src/routes/Reservation/reservation.edit.js
+++ b/SAS/TMSS/frontend/tmss_webapp/src/routes/Reservation/reservation.edit.js
@@ -3,7 +3,7 @@ import { Redirect } from 'react-router-dom'
 
 import { Button } from 'primereact/button';
 import { Dropdown } from 'primereact/dropdown';
-import {InputText } from 'primereact/inputtext';
+import { InputText } from 'primereact/inputtext';
 import { InputTextarea } from 'primereact/inputtextarea';
 
 import moment from 'moment';
@@ -11,7 +11,6 @@ import _ from 'lodash';
 import Flatpickr from "react-flatpickr";
 
 import { publish } from '../../App';
-
 import { CustomDialog } from '../../layout/components/CustomDialog';
 import { appGrowl } from '../../layout/components/AppGrowl';
 import AppLoader from '../../layout/components/AppLoader';
@@ -21,6 +20,8 @@ import UIConstants from '../../utils/ui.constants';
 import ProjectService from '../../services/project.service';
 import ReservationService from '../../services/reservation.service';
 import UtilService from '../../services/util.service';
+import { InputMask } from 'primereact/inputmask';
+import UnitConverter from '../../utils/unit.converter';
 
 export class ReservationEdit extends Component {
     constructor(props) {
@@ -40,19 +41,21 @@ export class ReservationEdit extends Component {
         this.projects = [];                         // All projects to load project dropdown
         this.reservationTemplates = [];
         this.reservationStrategies = [];
+        this.tooltipOptions = UIConstants.tooltipOptions;
 
         this.setEditorOutput = this.setEditorOutput.bind(this);
         this.setEditorFunction = this.setEditorFunction.bind(this);
         this.checkIsDirty = this.checkIsDirty.bind(this);
+        this.isValidDuration = this.isValidDuration.bind(this);
         this.saveReservation = this.saveReservation.bind(this);
         this.close = this.close.bind(this);
         this.cancelEdit = this.cancelEdit.bind(this);
 
-         // Validateion Rules
+        // Validateion Rules
         this.formRules = {
-            name: {required: true, message: "Name can not be empty"},
-            description: {required: true, message: "Description can not be empty"},
-            start_time: {required: true, message: "Start Time can not be empty"},
+            name: { required: true, message: "Name can not be empty" },
+            description: { required: true, message: "Description can not be empty" },
+            start_time: { required: true, message: "Start Time can not be empty" },
         };
     }
 
@@ -65,21 +68,20 @@ export class ReservationEdit extends Component {
      * @param {Function} editorFunction 
      */
     setEditorFunction(editorFunction) {
-        this.setState({editorFunction: editorFunction});
+        this.setState({ editorFunction: editorFunction });
     }
-
+  
     /**
      * Initialize the Reservation and related
      */
     async initReservation() {
-        const reserId = this.props.match?this.props.match.params.id: null;
-        
-        const promises = [  ProjectService.getProjectList(),
-                            ReservationService.getReservationTemplates(),
-                            UtilService.getUTC(),
-                            ReservationService.getReservationStrategyTemplates()
-                        ];
-        let emptyProjects = [{url: null, name: "Select Project"}];
+        const reserId = this.props.match ? this.props.match.params.id : null;
+        const promises = [ProjectService.getProjectList(),
+        ReservationService.getReservationTemplates(),
+        UtilService.getUTC(),
+        ReservationService.getReservationStrategyTemplates()
+        ];
+        let emptyProjects = [{ url: null, name: "Select Project" }];
         Promise.all(promises).then(responses => {
             this.projects = emptyProjects.concat(responses[0]);
             this.reservationTemplates = responses[1];
@@ -88,7 +90,7 @@ export class ReservationEdit extends Component {
             let schema = {
                 properties: {}
             };
-            if(this.state.reservationTemplate) {
+            if (this.state.reservationTemplate) {
                 schema = this.state.reservationTemplate.schema;
             }
             this.setState({
@@ -97,10 +99,10 @@ export class ReservationEdit extends Component {
                 systemTime: systemTime
             });
             this.getReservationDetails(reserId);
-        });    
-       
-    }
+        });
 
+    }
+    
     /**
      * To get the reservation details from the backend using the service
      * @param {number} Reservation Id
@@ -108,66 +110,69 @@ export class ReservationEdit extends Component {
     async getReservationDetails(id) {
         if (id) {
             await ReservationService.getReservation(id)
-            .then(async (reservation) => {
-                if (reservation) {
-                    let reservationTemplate = this.reservationTemplates.find(reserTemplate => reserTemplate.id === reservation.specifications_template_id);
-                    if (this.state.editorFunction) {
-                        this.state.editorFunction();
-                    }
-                    // no project then allow to select project from dropdown list
-                    this.hasProject = reservation.project?true:false;
-                    let schema = {
-                        properties: {}
-                    };
-                    if(reservationTemplate) {
-                        schema = reservationTemplate.schema;
-                    }
-                    let project = this.projects.find(project => project.name === reservation.project_id);
-                    reservation['project']=  project ? project.name: null;
-                    let strategyName = reservation.specifications_doc.activity.name;
-                    let reservationStrategy = null;
-                    if (strategyName) {
-                        reservationStrategy =  this.reservationStrategies.find(strategy => strategy.name === strategyName);
-                    }   else {
-                        reservationStrategy= {
-                            id: null,
+                .then(async (reservation) => {
+                    if (reservation) {                        
+                        reservation.duration = reservation.duration || 0;
+                        reservation.duration = UnitConverter.getSecsToDDHHmmss(reservation.duration); //this.secondsToHms(reservation.duration);
+                        let reservationTemplate = this.reservationTemplates.find(reserTemplate => reserTemplate.id === reservation.specifications_template_id);
+                        if (this.state.editorFunction) {
+                            this.state.editorFunction();
+                        }
+                        // no project then allow to select project from dropdown list
+                        this.hasProject = reservation.project ? true : false;
+                        let schema = {
+                            properties: {}
+                        };
+                        if (reservationTemplate) {
+                            schema = reservationTemplate.schema;
+                        }
+                        let project = this.projects.find(project => project.name === reservation.project_id);
+                        reservation['project'] = project ? project.name : null;
+                        let strategyName = reservation.specifications_doc.activity.name;
+                        let reservationStrategy = null;
+                        if (strategyName) {
+                            reservationStrategy = this.reservationStrategies.find(strategy => strategy.name === strategyName);
+                        } else {
+                            reservationStrategy = {
+                                id: null,
+                            }
                         }
-                    }
 
-                    this.setState({
-                        reservationStrategy: reservationStrategy,
-                        reservation: reservation, 
-                        reservationTemplate: reservationTemplate,
-                        paramsSchema: schema,});    
-                }   else {
-                    this.setState({redirect: "/not-found"});
-                }
-            });
-        }   else {
-            this.setState({redirect: "/not-found"});
+                        this.setState({
+                            reservationStrategy: reservationStrategy,
+                            reservation: reservation,
+                            reservationTemplate: reservationTemplate,
+                            paramsSchema: schema,
+                        });
+                    } else {
+                        this.setState({ redirect: "/not-found" });
+                    }
+                });
+        } else {
+            this.setState({ redirect: "/not-found" });
         }
     }
 
     close() {
-        this.setState({showDialog: false});
+        this.setState({ showDialog: false });
     }
- 
+
     /**
      * Cancel edit and redirect to Reservation View page
      */
-     cancelEdit() {
-        publish('edit-dirty', false);
-        this.props.history.goBack();
-        this.setState({showDialog: false});
-        this.props.history.goBack();
+    cancelEdit() {      
+        const reserId = this.props.match ? this.props.match.params.id : null;
+        publish('edit-dirty', false);       
+        this.setState({ showDialog: false });
+        this.props.history.goBack();        
     }
 
     /**
      * warn before cancel this page if any changes detected 
      */
-     checkIsDirty() {
-        if( this.state.isDirty ){
-            this.setState({showDialog: true});
+    checkIsDirty() {
+        if (this.state.isDirty) {
+            this.setState({ showDialog: true });
         } else {
             this.cancelEdit();
         }
@@ -178,7 +183,7 @@ export class ReservationEdit extends Component {
      * If no argument passed for fieldName, validates all fields in the form.
      * @param {string} fieldName 
      */
-     validateForm(fieldName) {
+    validateForm(fieldName) {
         let validForm = false;
         let errors = this.state.errors;
         let validFields = this.state.validFields;
@@ -190,13 +195,13 @@ export class ReservationEdit extends Component {
                 const fieldValue = this.state.reservation[fieldName];
                 if (rule.required) {
                     if (!fieldValue) {
-                        errors[fieldName] = rule.message?rule.message:`${fieldName} is required`;
-                    }   else {
+                        errors[fieldName] = rule.message ? rule.message : `${fieldName} is required`;
+                    } else {
                         validFields[fieldName] = true;
                     }
                 }
-            }  
-        }  else {
+            }
+        } else {
             errors = {};
             validFields = {};
             for (const fieldName in this.formRules) {
@@ -204,14 +209,14 @@ export class ReservationEdit extends Component {
                 const fieldValue = this.state.reservation[fieldName];
                 if (rule.required) {
                     if (!fieldValue) {
-                        errors[fieldName] = rule.message?rule.message:`${fieldName} is required`;
-                    }   else {
+                        errors[fieldName] = rule.message ? rule.message : `${fieldName} is required`;
+                    } else {
                         validFields[fieldName] = true;
                     }
                 }
             }
         }
-        this.setState({errors: errors, validFields: validFields});
+        this.setState({ errors: errors, validFields: validFields });
         if (Object.keys(validFields).length === Object.keys(this.formRules).length) {
             validForm = true;
             delete errors['start_time'];
@@ -227,7 +232,20 @@ export class ReservationEdit extends Component {
                 errors['stop_time'] = "End Time cannot be same or before Start Time";
                 delete errors['start_time'];
             }
-            this.setState({errors: errors});
+            this.setState({ errors: errors });
+        }
+        if (fieldName === 'duration' && this.state.reservation.duration) {
+            var values = this.state.reservation.duration.split(' ');
+            var days = values[0];
+            var dValues = values[1].split(':');           
+            delete errors['duration'];
+            if ((days *1 )===0 && (dValues[0] * 1) === 0 && (dValues[1] * 1) === 0 && (dValues[2] * 1) === 0) {
+                validForm = false;
+                if (!fieldName || fieldName === 'duration') {
+                    errors['duration'] = "Duration cannot be zero";
+                }
+                this.setState({ errors: errors });
+            }
         }
         return validForm;
     }
@@ -238,17 +256,17 @@ export class ReservationEdit extends Component {
      * @param {Date} toDate 
      * @returns boolean
      */
-     validateDates(fromDate, toDate) {
+    validateDates(fromDate, toDate) {
         if (fromDate && toDate && moment(toDate).isSameOrBefore(moment(fromDate))) {
             return false;
         }
         return true;
     }
 
-     /**
-     * This function is mainly added for Unit Tests. If this function is removed Unit Tests will fail.
-     */
-      validateEditor() {
+    /**
+    * This function is mainly added for Unit Tests. If this function is removed Unit Tests will fail.
+    */
+    validateEditor() {
         return this.validEditor;
     }
 
@@ -257,22 +275,89 @@ export class ReservationEdit extends Component {
      * @param {string} key 
      * @param {any} value 
      */
-     setParams(key, value, type) {
+    setParams(key, value, type) {
         let reservation = this.state.reservation;
-        switch(type) {
+        switch (type) {
             case 'NUMBER': {
-                reservation[key] = value?parseInt(value):0;
+                reservation[key] = value ? parseInt(value) : 0;
                 break;
             }
             default: {
-                reservation[key] = value;                
+                reservation[key] = value;
                 break;
             }
         }
-        this.setState({reservation: reservation, validForm: this.validateForm(key), isDirty: true});
+        this.setState({ reservation: reservation, validForm: this.validateForm(key), isDirty: true },
+            () => {
+                this.setDurationOrEndValue(key);
+            });
         publish('edit-dirty', true);
     }
 
+    /**
+     * Function to set the value for the dependant fields when value is set to one field.
+     * When start_time or stop_time is changed, duration will be updated accordingly.
+     * Similarly if duration is changed, stop_time is updated.
+     * @param {String} key - property name of the reservation
+     */
+    setDurationOrEndValue = (key) => {
+        let state = this.state;
+        if ( key === 'start_time' || key === 'stop_time') {
+            if (this.state.reservation.start_time && this.state.reservation.stop_time) {
+                var delta = Math.abs(new Date(this.state.reservation.start_time) - new Date(this.state.reservation.stop_time)) / 1000;
+                let tempDuration = UnitConverter.getSecsToDDHHmmss(delta);              
+                this.setDurationOrStopTime('duration', tempDuration);
+            }   else if (key === 'start_time' && this.state.reservation.start_time && this.state.reservation.duration) {
+                let stopDate = UnitConverter.getEndDateFromDuration(this.state.reservation.start_time, this.state.reservation.duration);               
+                this.setDurationOrStopTime('stop_time', stopDate);
+            }   else if (key === 'stop_time' && !this.state.reservation.stop_time) {
+                this.setDurationOrStopTime('duration', "");
+            }
+        }
+        else if (key === 'duration') {            
+            if (this.state.reservation.start_time) {
+                let stopDate = UnitConverter.getEndDateFromDuration(this.state.reservation.start_time, this.state.reservation.duration);               
+                this.setDurationOrStopTime('stop_time', stopDate);
+            }
+        }
+    }
+    
+    /**
+     * Function to set calcualted value for either duration or stop_time
+     * @param {String} key - name of the field
+     * @param {*} value - value to set for the field
+     */
+     setDurationOrStopTime(key, value) {
+        let reservation = this.state.reservation;
+        reservation[key] = value;
+        this.setState({ reservation: reservation, validForm: this.validateForm(key), isDirty: true });
+    }
+
+    /**
+     * Function to validate the duration field.
+     * @param {String} value - Duration in format 'Days HH:mm:ss'
+     * @returns boolean
+     */
+     isValidDuration(value) {
+        let errors = this.state.errors;
+        let touched = this.state.touched;
+        let reservation = this.state.reservation;
+        let validForm = this.state.validForm;
+        if (value.length === 12 && (value === "000 00:00:00" ||
+            !value.match(/^([0-1]90 00:00:00)|([0-1][0-8][0-9] ([0-1]?\d|2[0-3]):([0-5]?\d):([0-5]?\d))$/))) {
+            errors.duration = "Not valid duration. Duration should be in Days Hours:minutes:seconds. Min - 000 00:00:01, Max - 190 00:00:00";
+            touched.duration = true;
+            validForm = false;
+        }   else {
+            delete errors["duration"];
+            delete touched["duration"];
+            validForm = this.validateForm();
+        }
+        reservation.duration = value;
+        this.setState({errors: errors, touched: touched, reservation: reservation, validForm: validForm});
+        return errors.duration?false:true;
+    }
+
     /**
      * Set JEditor output
      * @param {*} jsonOutput 
@@ -281,66 +366,74 @@ export class ReservationEdit extends Component {
     setEditorOutput(jsonOutput, errors) {
         this.paramsOutput = jsonOutput;
         this.validEditor = errors.length === 0;
-        if  ( !this.state.isDirty && this.state.paramsOutput && !_.isEqual(this.state.paramsOutput, jsonOutput) ) {
-            this.setState({ paramsOutput: jsonOutput, 
+        if (!this.state.isDirty && this.state.paramsOutput && !_.isEqual(this.state.paramsOutput, jsonOutput)) {
+            this.setState({
+                paramsOutput: jsonOutput,
                 validEditor: errors.length === 0,
                 validForm: this.validateForm(),
-                isDirty: true});
+                isDirty: true
+            });
             publish('edit-dirty', true);
-        }   else {
-            this.setState({ paramsOutput: jsonOutput, 
+        } else {
+            this.setState({
+                paramsOutput: jsonOutput,
                 validEditor: errors.length === 0,
-                validForm: this.validateForm()});
+                validForm: this.validateForm()
+            });
         }
     }
-    
+
     /**
      * Function to set form values to the Reservation object
      * @param {string} key 
      * @param {object} value 
      */
-     setReservationParams(key, value) {
+    setReservationParams(key, value) {
         let reservation = _.cloneDeep(this.state.reservation);
         reservation[key] = value;
-        if  ( !this.state.isDirty && !_.isEqual(this.state.reservation, reservation) ) {
-            this.setState({reservation: reservation, validForm: this.validateForm(key), validEditor: this.validateEditor(), touched: { 
-                ...this.state.touched,
-                [key]: true
-            }, isDirty: true});
+        if (!this.state.isDirty && !_.isEqual(this.state.reservation, reservation)) {
+            this.setState({
+                reservation: reservation, validForm: this.validateForm(key), validEditor: this.validateEditor(), touched: {
+                    ...this.state.touched,
+                    [key]: true
+                }, isDirty: true
+            });
             publish('edit-dirty', true);
-        }   else {
-            this.setState({reservation: reservation, validForm: this.validateForm(key), validEditor: this.validateEditor(),touched: { 
-                ...this.state.touched,
-                [key]: true
-            }});
+        } else {
+            this.setState({
+                reservation: reservation, validForm: this.validateForm(key), validEditor: this.validateEditor(), touched: {
+                    ...this.state.touched,
+                    [key]: true
+                }
+            });
         }
     }
 
     /**
      * Update reservation
      */
-    async saveReservation(){
+    async saveReservation() {
         let reservation = this.state.reservation;
         let project = this.projects.find(project => project.name === reservation.project);
         reservation['start_time'] = moment(reservation['start_time']).format(UIConstants.CALENDAR_DATETIME_FORMAT);
-        reservation['stop_time'] = (reservation['stop_time'] &&  reservation['stop_time'] !== 'Invalid date') ?moment(reservation['stop_time']).format(UIConstants.CALENDAR_DATETIME_FORMAT):null;
-        reservation['project']=  project ? project.url: null;
-        reservation['specifications_doc']= this.paramsOutput;
-        reservation = await ReservationService.updateReservation(reservation); 
-        if (reservation && reservation.id){
-            appGrowl.show({severity: 'success', summary: 'Success', detail: 'Reservation updated successfully.'});
+        reservation['stop_time'] = (reservation['stop_time'] && reservation['stop_time'] !== 'Invalid date') ? moment(reservation['stop_time']).format(UIConstants.CALENDAR_DATETIME_FORMAT) : null;
+        reservation['project'] = project ? project.url : null;
+        reservation['specifications_doc'] = this.paramsOutput;
+        reservation = await ReservationService.updateReservation(reservation);
+        if (reservation && reservation.id) {
+            appGrowl.show({ severity: 'success', summary: 'Success', detail: 'Reservation updated successfully.' });
             this.props.history.push({
                 pathname: `/reservation/view/${this.props.match.params.id}`,
-            }); 
+            });
             publish('edit-dirty', false);
-        }   else {
-            appGrowl.show({severity: 'error', summary: 'Error Occured', detail: 'Unable to update Reservation', showDialog: false, isDirty: false});
+        } else {
+            appGrowl.show({ severity: 'error', summary: 'Error Occured', detail: 'Unable to update Reservation', showDialog: false, isDirty: false });
         }
     }
 
     render() {
         if (this.state.redirect) {
-            return <Redirect to={ {pathname: this.state.redirect} }></Redirect>
+            return <Redirect to={{ pathname: this.state.redirect }}></Redirect>
         }
         let jeditor = null;
         if (this.state.reservationTemplate) {
@@ -348,107 +441,53 @@ export class ReservationEdit extends Component {
                 delete this.state.reservation.specifications_doc.$id;
                 delete this.state.reservation.specifications_doc.$schema;
             }
-            jeditor = React.createElement(Jeditor, {title: "Reservation Parameters", 
-                                                        schema: this.state.reservationTemplate.schema,
-                                                        initValue: this.state.reservation.specifications_doc,
-                                                        disabled: false,
-                                                        callback: this.setEditorOutput,
-                                                        parentFunction: this.setEditorFunction
-                                                    });
+            jeditor = React.createElement(Jeditor, {
+                title: "Reservation Parameters",
+                schema: this.state.reservationTemplate.schema,
+                initValue: this.state.reservation.specifications_doc,
+                disabled: false,
+                callback: this.setEditorOutput,
+                parentFunction: this.setEditorFunction
+            });
         }
 
         return (
             <React.Fragment>
-                <PageHeader location={this.props.location} title={'Reservation - Edit'} actions={[{icon:'fa-window-close',
-                title:'Click to Close Reservation - Edit', type: 'button',  actOn: 'click', props:{ callback: this.checkIsDirty }}]}/>
+                <PageHeader location={this.props.location} title={'Reservation - Edit'} actions={[{
+                    icon: 'fa-window-close',
+                    title: 'Click to Close Reservation - Edit', type: 'button', actOn: 'click', props: { callback: this.checkIsDirty }
+                }]} />
 
-                { this.state.isLoading? <AppLoader /> : this.state.reservation &&
+                { this.state.isLoading ? <AppLoader /> : this.state.reservation &&
                     <React.Fragment>
                         <div>
-                        <div className="p-fluid">
-                            <div className="p-field p-grid">
-                                <label htmlFor="reservationname" className="col-lg-2 col-md-2 col-sm-12">Name <span style={{color:'red'}}>*</span></label>
-                                <div className="col-lg-3 col-md-3 col-sm-12">
-                                    <InputText className={(this.state.errors.name && this.state.touched.name) ?'input-error':''} id="reservationname" data-testid="name" 
-                                                tooltip="Enter name of the Reservation Name" tooltipOptions={this.tooltipOptions} maxLength="128"
-                                                ref={input => {this.nameInput = input;}}
-                                                value={this.state.reservation.name} autoFocus
-                                                onChange={(e) => this.setReservationParams('name', e.target.value)}
-                                                onBlur={(e) => this.setReservationParams('name', e.target.value)}/>
-                                    <label className={(this.state.errors.name && this.state.touched.name)?"error":"info"}>
-                                        {this.state.errors.name && this.state.touched.name ? this.state.errors.name : "Max 128 characters"}
-                                    </label>
-                                </div>
-                                <div className="col-lg-1 col-md-1 col-sm-12"></div>
-                                <label htmlFor="description" className="col-lg-2 col-md-2 col-sm-12">Description <span style={{color:'red'}}>*</span></label>
-                                <div className="col-lg-3 col-md-3 col-sm-12">
-                                    <InputTextarea className={(this.state.errors.description && this.state.touched.description) ?'input-error':''} rows={3} cols={30} 
-                                                tooltip="Longer description of the Reservation" 
-                                                tooltipOptions={this.tooltipOptions}
-                                                maxLength="128"
-                                                data-testid="description" 
-                                                value={this.state.reservation.description} 
-                                                onChange={(e) => this.setReservationParams('description', e.target.value)}
-                                                onBlur={(e) => this.setReservationParams('description', e.target.value)}/>
-                                    <label className={(this.state.errors.description && this.state.touched.description) ?"error":"info"}>
-                                        {(this.state.errors.description && this.state.touched.description) ? this.state.errors.description : "Max 255 characters"}
-                                    </label>
-                                </div>
-                            </div>
-                            <div className="p-field p-grid">
-                                    <label className="col-lg-2 col-md-2 col-sm-12">Start Time<span style={{color:'red'}}>*</span></label>
+                            <div className="p-fluid">
+                                <div className="p-field p-grid">
+                                    <label htmlFor="reservationname" className="col-lg-2 col-md-2 col-sm-12">Name <span style={{ color: 'red' }}>*</span></label>
                                     <div className="col-lg-3 col-md-3 col-sm-12">
-                                        <Flatpickr data-enable-time data-input options={{
-                                                    "inlineHideInput": true,
-                                                    "wrap": true,
-                                                    "enableSeconds": true,
-                                                    "time_24hr": true,
-                                                    "minuteIncrement": 1,
-                                                    "allowInput": true,
-                                                    "defaultDate": this.state.systemTime.format(UIConstants.CALENDAR_DEFAULTDATE_FORMAT),
-                                                    "defaultHour": this.state.systemTime.hours(),
-                                                    "defaultMinute": this.state.systemTime.minutes()
-                                                    }}
-                                                    title="Start of this reservation"
-                                                    value={this.state.reservation.start_time}
-                                                    onChange= {value => {this.setParams('start_time', value[0]?value[0]:this.state.reservation.start_time);
-                                                        this.setReservationParams('start_time', value[0]?value[0]:this.state.reservation.start_time)}} >
-                                            <input type="text" data-input className={`p-inputtext p-component ${this.state.errors.start_time && this.state.touched.start_time?'input-error':''}`} />
-                                            <i className="fa fa-calendar" data-toggle style={{position: "absolute", marginLeft: '-25px', marginTop:'5px', cursor: 'pointer'}} ></i>
-                                            <i className="fa fa-times" style={{position: "absolute", marginLeft: '-50px', marginTop:'5px', cursor: 'pointer'}} 
-                                                onClick={e => {this.setParams('start_time', ''); this.setReservationParams('start_time', '')}}></i>
-                                        </Flatpickr>
-                                        <label className={this.state.errors.start_time && this.state.touched.start_time?"error":"info"}>
-                                            {this.state.errors.start_time && this.state.touched.start_time ? this.state.errors.start_time : ""}
+                                        <InputText className={(this.state.errors.name && this.state.touched.name) ? 'input-error' : ''} id="reservationname" data-testid="name"
+                                            tooltip="Enter name of the Reservation" tooltipOptions={this.tooltipOptions} maxLength="128"
+                                            ref={input => { this.nameInput = input; }}
+                                            value={this.state.reservation.name} autoFocus
+                                            onChange={(e) => this.setReservationParams('name', e.target.value)}
+                                            onBlur={(e) => this.setReservationParams('name', e.target.value)} />
+                                        <label className={(this.state.errors.name && this.state.touched.name) ? "error" : "info"}>
+                                            {this.state.errors.name && this.state.touched.name ? this.state.errors.name : "Max 128 characters"}
                                         </label>
                                     </div>
                                     <div className="col-lg-1 col-md-1 col-sm-12"></div>
-                             
-                                    <label className="col-lg-2 col-md-2 col-sm-12">End time</label>
+                                    <label htmlFor="description" className="col-lg-2 col-md-2 col-sm-12">Description <span style={{ color: 'red' }}>*</span></label>
                                     <div className="col-lg-3 col-md-3 col-sm-12">
-                                        <Flatpickr data-enable-time data-input options={{
-                                                    "inlineHideInput": true,
-                                                    "wrap": true,
-                                                    "enableSeconds": true,
-                                                    "time_24hr": true,
-                                                    "minuteIncrement": 1,
-                                                    "allowInput": true,
-                                                    "minDate": this.state.reservation.stop_time?this.state.reservation.stop_time.toDate:'',
-                                                    "defaultDate": this.state.systemTime.format(UIConstants.CALENDAR_DEFAULTDATE_FORMAT),
-                                                    "defaultHour": this.state.systemTime.hours(),
-                                                    "defaultMinute": this.state.systemTime.minutes()
-                                                    }}
-                                                    title="End of this reservation. If empty, then this reservation is indefinite."
-                                                    value={this.state.reservation.stop_time}
-                                                    onChange= {value => {this.setParams('stop_time', value[0]?value[0]:this.state.reservation.stop_time);
-                                                                            this.setReservationParams('stop_time', value[0]?value[0]:this.state.reservation.stop_time)}} >
-                                            <input type="text" data-input className={`p-inputtext p-component ${this.state.errors.stop_time && this.state.touched.stop_time?'input-error':''}`} />
-                                            <i className="fa fa-calendar" data-toggle style={{position: "absolute", marginLeft: '-25px', marginTop:'5px', cursor: 'pointer'}} ></i>
-                                            <i className="fa fa-times" style={{position: "absolute", marginLeft: '-50px', marginTop:'5px', cursor: 'pointer'}} 
-                                                onClick={e => {this.setParams('stop_time', ''); this.setReservationParams('stop_time', '')}}></i>
-                                        </Flatpickr>
-                                        <label className={this.state.errors.stop_time && this.state.touched.stop_time?"error":"info"}>
-                                            {this.state.errors.stop_time && this.state.touched.stop_time ? this.state.errors.stop_time : ""}
+                                        <InputTextarea className={(this.state.errors.description && this.state.touched.description) ? 'input-error' : ''} rows={3} cols={30}
+                                            tooltip="Longer description of the Reservation"
+                                            tooltipOptions={this.tooltipOptions}
+                                            maxLength="128"
+                                            data-testid="description"
+                                            value={this.state.reservation.description}
+                                            onChange={(e) => this.setReservationParams('description', e.target.value)}
+                                            onBlur={(e) => this.setReservationParams('description', e.target.value)} />
+                                        <label className={(this.state.errors.description && this.state.touched.description) ? "error" : "info"}>
+                                            {(this.state.errors.description && this.state.touched.description) ? this.state.errors.description : "Max 255 characters"}
                                         </label>
                                     </div>
                                 </div>
@@ -456,19 +495,19 @@ export class ReservationEdit extends Component {
                                 <div className="p-field p-grid">
                                     <label htmlFor="project" className="col-lg-2 col-md-2 col-sm-12">Project</label>
                                     <div className="col-lg-3 col-md-3 col-sm-12" data-testid="project" >
-                                        <Dropdown inputId="project" optionLabel="name" optionValue="name" 
-                                                tooltip="Project" tooltipOptions={this.tooltipOptions}
-                                                value={this.state.reservation.project}
-                                                options={this.projects} 
-                                                onChange={(e) => {this.setParams('project',e.value)}} 
-                                                placeholder="Select Project"
-                                                disabled={this.hasProject} 
-                                                />
-                                        <label className={(this.state.errors.project && this.state.touched.project) ?"error":"info"}>
-                                            {(this.state.errors.project && this.state.touched.project) ? this.state.errors.project : this.state.reservation.project? '': "Select Project"}
+                                        <Dropdown inputId="project" optionLabel="name" optionValue="name"
+                                            tooltip="Project" tooltipOptions={this.tooltipOptions}
+                                            value={this.state.reservation.project}
+                                            options={this.projects}
+                                            onChange={(e) => { this.setParams('project', e.value) }}
+                                            placeholder="Select Project"
+                                            disabled={this.hasProject}
+                                        />
+                                        <label className={(this.state.errors.project && this.state.touched.project) ? "error" : "info"}>
+                                            {(this.state.errors.project && this.state.touched.project) ? this.state.errors.project : "Select Project"}
                                         </label>
                                     </div>
-                                    {/* <div className="col-lg-1 col-md-1 col-sm-12"></div>
+                                    {/*  <div className="col-lg-1 col-md-1 col-sm-12"></div>
                                     <label htmlFor="strategy" className="col-lg-2 col-md-2 col-sm-12">Reservation Strategy</label>
                                     <div className="col-lg-3 col-md-3 col-sm-12" data-testid="strategy" >
                                         {this.state.reservationStrategy.id &&
@@ -481,33 +520,119 @@ export class ReservationEdit extends Component {
                                                 disabled= {true} />
                                         }
                                     </div> */}
+                                </div>
+
+                                <div className="p-field p-grid">
+                                    <label htmlFor="start-time" className="col-lg-2 col-md-2 col-sm-12" >Start Time<span style={{ color: 'red' }}>*</span></label>
+                                    <div className="col-lg-3 col-md-3 col-sm-12">
+                                        <Flatpickr data-enable-time data-input options={{
+                                            "inlineHideInput": true,
+                                            "wrap": true,
+                                            "enableSeconds": true,
+                                            "time_24hr": true,
+                                            "minuteIncrement": 1,
+                                            "allowInput": true,
+                                            "defaultDate": this.state.systemTime.format(UIConstants.CALENDAR_DEFAULTDATE_FORMAT),
+                                            "defaultHour": this.state.systemTime.hours(),
+                                            "defaultMinute": this.state.systemTime.minutes()
+                                        }}
+                                            title="Start of this reservation"
+                                            value={this.state.reservation.start_time}
+                                            onChange={value => {
+                                                this.setParams('start_time', value[0] ? value[0] : this.state.reservation.start_time);
+                                                this.setReservationParams('start_time', value[0] ? value[0] : this.state.reservation.start_time)
+                                            }} >
+                                            <input type="text" data-input className={`p-inputtext p-component ${this.state.errors.start_time && this.state.touched.start_time ? 'input-error' : ''}`} />
+                                            <i className="fa fa-calendar" data-toggle style={{ position: "absolute", marginLeft: '-25px', marginTop: '5px', cursor: 'pointer' }} ></i>
+                                            <i className="fa fa-times" style={{ position: "absolute", marginLeft: '-50px', marginTop: '5px', cursor: 'pointer' }}
+                                                onClick={e => { this.setParams('start_time', ''); this.setReservationParams('start_time', '') }}></i>
+                                        </Flatpickr>
+                                        <label className={this.state.errors.start_time && this.state.touched.start_time ? "error" : "info"}>
+                                            {this.state.errors.start_time && this.state.touched.start_time ? this.state.errors.start_time : ""}
+                                        </label>
+                                    </div>
+                                    <div className="col-lg-1 col-md-1 col-sm-12"></div>
+                                    <label className="col-lg-2 col-md-2 col-sm-12">End time</label>
+                                    <div className="col-lg-3 col-md-3 col-sm-12">
+                                        <Flatpickr data-enable-time data-input options={{
+                                            "inlineHideInput": true,
+                                            "wrap": true,
+                                            "enableSeconds": true,
+                                            "time_24hr": true,
+                                            "minuteIncrement": 1,
+                                            "allowInput": true,
+                                            "minDate": this.state.reservation.stop_time ? this.state.reservation.stop_time.toDate : '',
+                                            "defaultDate": this.state.systemTime.format(UIConstants.CALENDAR_DEFAULTDATE_FORMAT),
+                                            "defaultHour": this.state.systemTime.hours(),
+                                            "defaultMinute": this.state.systemTime.minutes()
+                                        }}
+                                            title="End of this reservation. If empty, then this reservation is indefinite."
+                                            value={this.state.reservation.stop_time}
+                                            onChange={value => {
+                                                this.setParams('stop_time', value[0] ? value[0] : this.state.reservation.stop_time);
+                                                this.setReservationParams('stop_time', value[0] ? value[0] : this.state.reservation.stop_time)
+                                            }} >
+                                            <input type="text" data-input className={`p-inputtext p-component ${this.state.errors.stop_time && this.state.touched.stop_time ? 'input-error' : ''}`} />
+                                            <i className="fa fa-calendar" data-toggle style={{ position: "absolute", marginLeft: '-25px', marginTop: '5px', cursor: 'pointer' }} ></i>
+                                            <i className="fa fa-times" style={{ position: "absolute", marginLeft: '-50px', marginTop: '5px', cursor: 'pointer' }}
+                                                onClick={e => { this.setParams('stop_time', ''); this.setReservationParams('stop_time', '') }}></i>
+                                        </Flatpickr>
+                                        <label className={this.state.errors.stop_time && this.state.touched.stop_time ? "error" : "info"}>
+                                            {this.state.errors.stop_time && this.state.touched.stop_time ? this.state.errors.stop_time : ""}
+                                        </label>
+                                    </div>
+                                </div>
 
+                                <div className="p-field p-grid">
+                                    <label className="col-lg-2 col-md-2 col-sm-12">Duration</label>
+                                    <div className="col-lg-3 col-md-3 col-sm-12">
+                                        <InputMask mask="999 99:99:99"
+                                            tooltip="Enter duration in (Days HH:mm:ss) format. Min-000 00:00:01 & Max-190 00:00:00."
+                                            tooltipOptions={this.tooltipOptions} 
+                                            value={this.state.reservation.duration}
+                                            placeholder="DDD HH:MM:SS"
+                                            onChange={(e) =>{if(!e.value) {this.setDurationOrEndValue("stop_time")}}}
+                                            onComplete={(e) => {
+                                                if (this.isValidDuration(e.value)) {
+                                                    this.setReservationParams('duration', e.value);
+                                                    this.setParams('duration', e.value ? e.value : this.state.reservation.duration);
+                                                }
+                                            }}
+                                            onBlur={(e) => {
+                                                this.setParams('duration', e.value ? e.value : this.state.reservation.duration);
+                                            }}></InputMask>
+                                        <label className={this.state.errors.duration && this.state.touched.duration ? "error" : "info"}>
+                                            {this.state.errors.duration && this.state.touched.duration ? this.state.errors.duration : ""}
+                                        </label>
+                                    </div>
                                 </div>
 
                                 <div className="p-grid">
                                     <div className="p-col-12">
-                                        {this.state.paramsSchema?jeditor:""}
+                                        {this.state.paramsSchema ? jeditor : ""}
                                     </div>
                                 </div>
-                        </div>
+                            </div>
 
-                        <div className="p-grid p-justify-start">
-                            <div className="p-col-1">
-                                <Button label="Save" className="p-button-primary" icon="pi pi-check" onClick={this.saveReservation} 
+                            <div className="p-grid p-justify-start">
+                                <div className="p-col-1">
+                                    <Button label="Save" className="p-button-primary" icon="pi pi-check" onClick={this.saveReservation}
                                         disabled={!this.state.validEditor || !this.state.validForm} data-testid="save-btn" />
-                            </div>
-                            <div className="p-col-1">
-                                <Button label="Cancel" className="p-button-danger" icon="pi pi-times" onClick={this.checkIsDirty}  />
+                                </div>
+                                <div className="p-col-1">
+                                    <Button label="Cancel" className="p-button-danger" icon="pi pi-times" onClick={this.checkIsDirty} />
+                                </div>
                             </div>
                         </div>
-                    </div>
-              
+
                     </React.Fragment>
                 }
+
                 <CustomDialog type="confirmation" visible={this.state.showDialog} width="40vw"
-                        header={'Edit Reservation'} message={'Do you want to leave this page? Your changes may not be saved.'} 
-                        content={''} onClose={this.close} onCancel={this.close} onSubmit={this.cancelEdit}>
-                    </CustomDialog>
+                    header={'Edit Reservation'} message={'Do you want to leave this page? Your changes may not be saved.'}
+                    content={''} onClose={this.cancelEdit} onCancel={this.close} onSubmit={this.cancelEdit}>
+                </CustomDialog>
+
             </React.Fragment>
         );
     }
diff --git a/SAS/TMSS/frontend/tmss_webapp/src/routes/Reservation/reservation.list.js b/SAS/TMSS/frontend/tmss_webapp/src/routes/Reservation/reservation.list.js
index a1192925ef42f23a809a60da71488e4d3430e7a9..22ddbc9addc2b443f597267cffd26ede7e25dfcc 100644
--- a/SAS/TMSS/frontend/tmss_webapp/src/routes/Reservation/reservation.list.js
+++ b/SAS/TMSS/frontend/tmss_webapp/src/routes/Reservation/reservation.list.js
@@ -43,7 +43,7 @@ export class ReservationList extends Component{
                     format:UIConstants.CALENDAR_DATETIME_FORMAT
                 },
                 duration:{
-                    name:"Duration (HH:mm:ss)",
+                    name:"Duration (Days HH:mm:ss)",
                     format:UIConstants.CALENDAR_TIME_FORMAT
                 },
                 type: {
@@ -86,7 +86,7 @@ export class ReservationList extends Component{
             optionalcolumns:  [{ 
             }],
             columnclassname: [{
-                "Duration (HH:mm:ss)":"filter-input-75",
+                "Duration (Days HH:mm:ss)":"filter-input-75",
                 "Reservation type":"filter-input-100",
                 "Subject":"filter-input-75",
                 "Planned":"filter-input-50",
@@ -143,7 +143,7 @@ export class ReservationList extends Component{
                     reservation['stop_time']= 'Unknown';
                 } else {
                     let duration = reservation.duration;
-                    reservation.duration = UnitService.getSecsToHHmmss(reservation.duration);
+                    reservation.duration = UnitService.getSecsToDDHHmmss(reservation.duration);
                     reservation['stop_time']= moment(reservation['stop_time']).format(UIConstants.CALENDAR_DATETIME_FORMAT);
                 }
                 reservation['start_time']= moment(reservation['start_time']).format(UIConstants.CALENDAR_DATETIME_FORMAT);
diff --git a/SAS/TMSS/frontend/tmss_webapp/src/routes/Reservation/reservation.view.js b/SAS/TMSS/frontend/tmss_webapp/src/routes/Reservation/reservation.view.js
index 2e0c8fc3074ea65abdd83ccd06974d00c9665b0d..7a94d01dc16dbe5f7d4419347308f4e89bb2fcc8 100644
--- a/SAS/TMSS/frontend/tmss_webapp/src/routes/Reservation/reservation.view.js
+++ b/SAS/TMSS/frontend/tmss_webapp/src/routes/Reservation/reservation.view.js
@@ -12,6 +12,7 @@ import { appGrowl } from '../../layout/components/AppGrowl';
 import AppLoader from '../../layout/components/AppLoader';
 import PageHeader from '../../layout/components/PageHeader';
 import ReservationService from '../../services/reservation.service';
+import UnitConverter from '../../utils/unit.converter';
 
 export class ReservationView extends Component {
     constructor(props) {
@@ -176,6 +177,8 @@ export class ReservationView extends Component {
                             <span className="col-lg-4 col-md-4 col-sm-12">{(this.state.reservation.project_id)?this.state.reservation.project_id:''}</span>
                             {/* <label className="col-lg-2 col-md-2 col-sm-12">Reservation Strategy</label>
                             <span className="col-lg-4 col-md-4 col-sm-12">{this.state.reservation.specifications_doc.activity.name}</span> */}
+                            <label className="col-lg-2 col-md-2 col-sm-12">Duration (Days HH:mm:ss)</label>
+                            <span className="col-lg-4 col-md-4 col-sm-12">{(this.state.reservation.duration)?UnitConverter.getSecsToDDHHmmss(this.state.reservation.duration):'Unknown'}</span>
                         </div>
                        
                         <div className="p-fluid">
diff --git a/SAS/TMSS/frontend/tmss_webapp/src/utils/unit.converter.js b/SAS/TMSS/frontend/tmss_webapp/src/utils/unit.converter.js
index c4f80c5163ab31be1dc4791e730f32be215eeda2..1f135a9fd6fd152fab1765bb0909f1886c72a260 100644
--- a/SAS/TMSS/frontend/tmss_webapp/src/utils/unit.converter.js
+++ b/SAS/TMSS/frontend/tmss_webapp/src/utils/unit.converter.js
@@ -1,62 +1,96 @@
 import _, { round } from 'lodash';
+import moment from "moment";
 
 const UnitConverter = {
-    resourceUnitMap: {'time':{display: 'Hours', conversionFactor: 3600, mode:'decimal', minFractionDigits:0, maxFractionDigits: 2 }, 
-                      'bytes': {display: 'TB', conversionFactor: (1024*1024*1024*1024), mode:'decimal', minFractionDigits:0, maxFractionDigits: 3}, 
-                      'number': {display: 'Numbers', conversionFactor: 1, mode:'decimal', minFractionDigits:0, maxFractionDigits: 0},
-                      'days': {display: 'Days', conversionFactor: (3600*24), mode:'decimal', minFractionDigits:0, maxFractionDigits: 0}},
+    resourceUnitMap: {
+        'time': { display: 'Hours', conversionFactor: 3600, mode: 'decimal', minFractionDigits: 0, maxFractionDigits: 2 },
+        'bytes': { display: 'TB', conversionFactor: (1024 * 1024 * 1024 * 1024), mode: 'decimal', minFractionDigits: 0, maxFractionDigits: 3 },
+        'number': { display: 'Numbers', conversionFactor: 1, mode: 'decimal', minFractionDigits: 0, maxFractionDigits: 0 },
+        'days': { display: 'Days', conversionFactor: (3600 * 24), mode: 'decimal', minFractionDigits: 0, maxFractionDigits: 0 }
+    },
 
-    getDBResourceUnit: function() {
+    getDBResourceUnit: function () {
 
     },
 
-    getUIResourceUnit: function(type, value) {
-        try{
-            if(this.resourceUnitMap[type]){
-                var retval = Number.parseFloat(value/(this.resourceUnitMap[type].conversionFactor)).toFixed(this.resourceUnitMap[type].maxFractionDigits)
+    getUIResourceUnit: function (type, value) {
+        try {
+            if (this.resourceUnitMap[type]) {
+                var retval = Number.parseFloat(value / (this.resourceUnitMap[type].conversionFactor)).toFixed(this.resourceUnitMap[type].maxFractionDigits)
                 return retval;
             }
-          
-        }catch(error){
-            console.error('[unit.converter.getUIResourceUnit]',error);
+
+        } catch (error) {
+            console.error('[unit.converter.getUIResourceUnit]', error);
         }
         return value;
     },
-    getSecsToHHmmss: function(seconds) {
-        if (seconds) {
-            const hh = Math.floor(seconds/3600);
-            const mm = Math.floor((seconds - hh*3600) / 60 );
-            const ss = +((seconds -(hh*3600)-(mm*60)) / 1);
-            return (hh<10?`0${hh}`:`${hh}`) + ':' + (mm<10?`0${mm}`:`${mm}`) + ':' + (ss<10?`0${ss}`:`${ss}`);
+
+    /**
+     * Function to convert the duration to string format (Days HH:mm:ss). 
+     * The days part is of 3 characters prefixed with 0s if it is less than 3 characters.
+     * @param {Number} duration - Duration in seconds
+     * @returns String - Formatted to 'Day HH:mm:ss' format.
+     */
+    getSecsToDDHHmmss: function(duration) {
+        var days = Math.floor(duration / 86400);
+        duration -= days * 86400;
+
+        return `${(days+"").padStart(3,0)} ${this.getSecsToHHmmss(duration)}`;
+    },
+  
+    /**
+     * Function to get a date (to date) offset from another date(from date) by certain duration.
+     * The duration is defined in 'Days Hours:minutes:seconds' format.
+     * @param {String} startdate - string of a date object
+     * @param {String} duration - duration in string format 'DDD HH:mm:ss'
+     * @returns 
+     */
+    getEndDateFromDuration: function(startdate, duration) {  
+        var values = duration.split(' ');
+        var days = values[0];
+        let tempStart = moment(startdate);
+        let tempEnd = _.clone(tempStart);
+        tempEnd.add(days, 'days');
+        tempEnd.add(this.getHHmmssToSecs(values[1]), 'seconds');
+        return tempEnd.toDate();
+    },
+
+    getSecsToHHmmss: function (seconds) {
+        if (seconds >= 0) {
+            const hh = Math.floor(seconds / 3600);
+            const mm = Math.floor((seconds - hh * 3600) / 60);
+            const ss = +((seconds - (hh * 3600) - (mm * 60)) / 1);
+            return (hh < 10 ? `0${hh}` : `${hh}`) + ':' + (mm < 10 ? `0${mm}` : `${mm}`) + ':' + (ss < 10 ? `0${ss}` : `${ss}`);
         }
         return seconds;
     },
-    getHHmmssToSecs: function(seconds) {
+    getHHmmssToSecs: function (seconds) {
         if (seconds) {
             const strSeconds = _.split(seconds, ":");
-            return strSeconds[0]*3600 + strSeconds[1]*60 + Number(strSeconds[2]);
+            return strSeconds[0] * 3600 + strSeconds[1] * 60 + Number(strSeconds[2]);
         }
         return 0;
     },
-    radiansToDegree: function(object) {
-        for(let type in object) {
+    radiansToDegree: function (object) {
+        for (let type in object) {
             if (type === 'transit_offset') {
                 continue;
-            }else if (typeof object[type] === 'object') {
-               this.radiansToDegree(object[type]);
+            } else if (typeof object[type] === 'object') {
+                this.radiansToDegree(object[type]);
             } else {
                 object[type] = (object[type] * 180) / Math.PI;
             }
         }
     },
     degreeToRadians(object) {
-        for(let type in object) {
+        for (let type in object) {
             if (type === 'transit_offset') {
                 continue;
             } else if (typeof object[type] === 'object') {
                 this.degreeToRadians(object[type]);
             } else {
-                object[type] = object[type] * (Math.PI/180);
+                object[type] = object[type] * (Math.PI / 180);
             }
         }
     },
@@ -64,23 +98,23 @@ const UnitConverter = {
      * Function to convert Angle 1 & 2 input value for UI. 
      */
     getAngleInput(prpInput, isDegree) {
-        if (prpInput){
-            const isNegative = prpInput<0;
-            prpInput = prpInput * (isNegative?-1:1);
+        if (prpInput) {
+            const isNegative = prpInput < 0;
+            prpInput = prpInput * (isNegative ? -1 : 1);
             const degrees = prpInput * 180 / Math.PI;
             if (isDegree) {
                 const dd = Math.floor(prpInput * 180 / Math.PI);
-                const mm = Math.floor((degrees-dd) * 60);
-                const ss = round((degrees-dd-(mm/60)) * 3600,4);
-                return (isNegative?'-':'') + (dd<10?`0${dd}`:`${dd}`) + 'd' + (mm<10?`0${mm}`:`${mm}`) + 'm' + (ss<10?`0${ss}`:`${ss}`) + 's';
-            }   else {
-                const hh = Math.floor(degrees/15);
-                const mm = Math.floor((degrees - (hh*15))/15 * 60 );
-                const ss = round((degrees -(hh*15)-(mm*15/60))/15 * 3600, 4);
-                return (hh<10?`0${hh}`:`${hh}`) + 'h' + (mm<10?`0${mm}`:`${mm}`) + 'm' + (ss<10?`0${ss}`:`${ss}`) + 's';
+                const mm = Math.floor((degrees - dd) * 60);
+                const ss = round((degrees - dd - (mm / 60)) * 3600, 4);
+                return (isNegative ? '-' : '') + (dd < 10 ? `0${dd}` : `${dd}`) + 'd' + (mm < 10 ? `0${mm}` : `${mm}`) + 'm' + (ss < 10 ? `0${ss}` : `${ss}`) + 's';
+            } else {
+                const hh = Math.floor(degrees / 15);
+                const mm = Math.floor((degrees - (hh * 15)) / 15 * 60);
+                const ss = round((degrees - (hh * 15) - (mm * 15 / 60)) / 15 * 3600, 4);
+                return (hh < 10 ? `0${hh}` : `${hh}`) + 'h' + (mm < 10 ? `0${mm}` : `${mm}`) + 'm' + (ss < 10 ? `0${ss}` : `${ss}`) + 's';
             }
         } else {
-            return isDegree?"0d0m0s":'0h0m0s';
+            return isDegree ? "0d0m0s" : '0h0m0s';
         }
     },
 
@@ -88,17 +122,17 @@ const UnitConverter = {
      * Function to convert Angle 1 & 2 input value for Backend. 
      */
     getAngleOutput(prpOutput, isDegree) {
-        if(prpOutput){
+        if (prpOutput) {
             const splitOutput = prpOutput.split(':');
-            const seconds = splitOutput[2]?splitOutput[2].split('.')[0]:splitOutput[2];
+            const seconds = splitOutput[2] ? splitOutput[2].split('.')[0] : splitOutput[2];
             let milliSeconds = prpOutput.split('.')[1] || '0000';
-            milliSeconds = milliSeconds.padEnd(4,0);
+            milliSeconds = milliSeconds.padEnd(4, 0);
             if (isDegree) {
-                return ((splitOutput[0]*1 + splitOutput[1]/60 + seconds/3600 + milliSeconds/36000000)*Math.PI/180);
-            }   else {
-                return ((splitOutput[0]*15 + splitOutput[1]/4  + seconds/240 + milliSeconds/2400000)*Math.PI/180);
+                return ((splitOutput[0] * 1 + splitOutput[1] / 60 + seconds / 3600 + milliSeconds / 36000000) * Math.PI / 180);
+            } else {
+                return ((splitOutput[0] * 15 + splitOutput[1] / 4 + seconds / 240 + milliSeconds / 2400000) * Math.PI / 180);
             }
-        }else{
+        } else {
             return "00:00:00.0000";
         }
     },
@@ -113,19 +147,19 @@ const UnitConverter = {
     getAngleInputType(input) {
         if (input.match(/^\-?((\d0?d(0?0m)(0?0(\.\d{1,4})?s))|(([0-8]?\d)d(([0-5]?\d)m)(([0-5]?\d)(\.\d{1,4})?s)))$/)) {
             return 'dms';
-        }   else if (input.match(/^([0-1]?\d|2[0-3])h([0-5]?\d)m([0-5]?\d)(\.\d{1,4})?s$/)) {
+        } else if (input.match(/^([0-1]?\d|2[0-3])h([0-5]?\d)m([0-5]?\d)(\.\d{1,4})?s$/)) {
             return 'hms';
-        }   else if (input.match(/^-?((\d0(.0{1,4})?)|([0-8]?\d)(\.\d{1,4})?) ?d(egree)?s?$/)) {
+        } else if (input.match(/^-?((\d0(.0{1,4})?)|([0-8]?\d)(\.\d{1,4})?) ?d(egree)?s?$/)) {
             return 'degrees';
-        }   else if (input.match(/^([0-1]?\d|2[0-3])(\.\d{1,4})? ?h(our)?s?$/)) {
+        } else if (input.match(/^([0-1]?\d|2[0-3])(\.\d{1,4})? ?h(our)?s?$/)) {
             return 'hours';
-        }   else if (input.match(/^\-?((\d0?:(00:)(00))|(([0-8]\d):(([0-5]\d):)(([0-5]\d)(\.\d{1,4})?))) ?d(egree)?s?$/)) {
+        } else if (input.match(/^\-?((\d0?:(00:)(00))|(([0-8]\d):(([0-5]\d):)(([0-5]\d)(\.\d{1,4})?))) ?d(egree)?s?$/)) {
             return 'deg_format';
-        }   else if (input.match(/^([0-1]?\d|2[0-3]):([0-5]?\d):([0-5]?\d)(\.\d{1,4})? ?h(our)?s?$/)) {
+        } else if (input.match(/^([0-1]?\d|2[0-3]):([0-5]?\d):([0-5]?\d)(\.\d{1,4})? ?h(our)?s?$/)) {
             return 'hour_format';
-        }   else if (input.match(/^\-?[0-6](\.\d{1,20})?$/)) {
+        } else if (input.match(/^\-?[0-6](\.\d{1,20})?$/)) {
             return 'radians';
-        }   else {
+        } else {
             return null;
         }
     },
@@ -137,29 +171,29 @@ const UnitConverter = {
     parseAngle(angle) {
         let radians = 0;
         const angleType = this.getAngleInputType(angle);
-        switch(angleType) {
-            case 'dms' : {
+        switch (angleType) {
+            case 'dms': {
                 radians = this.convertAngleToRadian(angle);
                 break;
             }
-            case 'hms' : {
+            case 'hms': {
                 radians = this.convertAngleToRadian(angle);
                 break;
             }
-            case 'degrees' : {
-                radians = this.convertToRadians(angle.replace('d','').replace('egree','').replace('s','').replace(' ',''));
+            case 'degrees': {
+                radians = this.convertToRadians(angle.replace('d', '').replace('egree', '').replace('s', '').replace(' ', ''));
                 break;
             }
-            case 'hours' : {
-                radians = this.convertToRadians(angle.replace('h','').replace('our','').replace('s','').replace(' ','') * 15);
+            case 'hours': {
+                radians = this.convertToRadians(angle.replace('h', '').replace('our', '').replace('s', '').replace(' ', '') * 15);
                 break;
             }
-            case 'deg_format' : {
-                radians  = this.getAngleOutput(angle.replace('d','').replace('egree','').replace('s','').replace(' ',''), true);
+            case 'deg_format': {
+                radians = this.getAngleOutput(angle.replace('d', '').replace('egree', '').replace('s', '').replace(' ', ''), true);
                 break;
             }
-            case 'hour_format' : {
-                radians = this.getAngleOutput(angle.replace('h','').replace('our','').replace('s','').replace(' ',''), false);
+            case 'hour_format': {
+                radians = this.getAngleOutput(angle.replace('h', '').replace('our', '').replace('s', '').replace(' ', ''), false);
                 break;
             }
             case 'radians': {
@@ -178,7 +212,7 @@ const UnitConverter = {
      * @returns 
      */
     convertToRadians(angle) {
-        return angle * Math.PI /180;
+        return angle * Math.PI / 180;
     },
     /**
      * Converts a formatted string to a radian value
@@ -188,18 +222,18 @@ const UnitConverter = {
     convertAngleToRadian(angle) {
         let radian = 0;
         const isDegree = angle.indexOf('d') > 0;
-        const degreeHourSplit = isDegree?angle.split("d"):angle.split("h");
+        const degreeHourSplit = isDegree ? angle.split("d") : angle.split("h");
         let degreeHour = degreeHourSplit[0];
-        const isNegativeAngle = parseInt(degreeHour)<0;
-        degreeHour = isNegativeAngle?degreeHour*-1:degreeHour;
+        const isNegativeAngle = parseInt(degreeHour) < 0;
+        degreeHour = isNegativeAngle ? degreeHour * -1 : degreeHour;
         const minuteSplit = degreeHourSplit[1].split('m');
         const minute = minuteSplit[0];
-        const second = minuteSplit[1].replace('s','');
+        const second = minuteSplit[1].replace('s', '');
         if (isDegree) {
-            radian = this.convertToRadians((degreeHour*1 + minute/60 + second/3600));
-            radian = isNegativeAngle?radian*-1:radian;
-        }   else {
-            radian = this.convertToRadians((degreeHour*15 + minute/4 + second/240));
+            radian = this.convertToRadians((degreeHour * 1 + minute / 60 + second / 3600));
+            radian = isNegativeAngle ? radian * -1 : radian;
+        } else {
+            radian = this.convertToRadians((degreeHour * 15 + minute / 4 + second / 240));
         }
         return radian;
     }