Fixed time comparison validation func. Now compares min/max value of array.

This commit is contained in:
Daniel Schick 2024-01-05 10:51:13 +01:00
parent c24bc981b0
commit d8fabe0f97

View File

@ -60,13 +60,13 @@ class ValidationRuleBaseFunctions():
def describe_error_message(self, key)->str: def describe_error_message(self, key)->str:
""" """
Takes any error message, which typically is the validation rule's function name and returns a description of the error. Takes any error message, which typically is the validation rule's function name and returns a description of the error.
In case that the error code is not defined in self.error_message_dict, return the cryptic error code instead In case that the error code is not defined in self.error_message_dict, return the cryptic error code instead
returns: string returns: string
""" """
return self.error_message_dict.get(key,key) return self.error_message_dict.get(key,key)
def get_no_violation_default_output(self): def get_no_violation_default_output(self):
"""return the default output of a validation function with no validation: a tuple of (GREEN state, None)""" """return the default output of a validation function with no validation: a tuple of (GREEN state, None)"""
return (StatusFlags.GREEN, None) return (StatusFlags.GREEN, None)
@ -75,7 +75,7 @@ class ValidationRuleBaseFunctions():
""" """
# base function for all validation rules in the group {0001} A-L # base function for all validation rules in the group {0001} A-L
measures the time between NOW and query_time. measures the time between NOW and query_time.
When the query_time lays in the past, the delta is negative When the query_time lays in the past, the delta is negative
when the query_time lays in the future, the delta is positive when the query_time lays in the future, the delta is positive
@ -93,11 +93,11 @@ class ValidationRuleBaseFunctions():
# rule is only applicable, when 'key_time' is not defined (neither None, nor pd.NaT) # rule is only applicable, when 'key_time' is not defined (neither None, nor pd.NaT)
if (key_time is not None) and (key_time is not pd.NaT): if (key_time is not None) and (key_time is not pd.NaT):
return False return False
# when query_time is not valid, the rule cannot be applied # when query_time is not valid, the rule cannot be applied
if self.check_is_not_a_time_or_is_none(query_time): if self.check_is_not_a_time_or_is_none(query_time):
return False return False
# otherwise, this rule applies and the difference between 'now' and the query time is measured # otherwise, this rule applies and the difference between 'now' and the query time is measured
delta = self.time_logic.time_delta_from_now_to_tgt(tgt_time=query_time, unit="m") delta = self.time_logic.time_delta_from_now_to_tgt(tgt_time=query_time, unit="m")
@ -105,7 +105,7 @@ class ValidationRuleBaseFunctions():
# Violation, if delta <= threshold # Violation, if delta <= threshold
violation_state = (delta<=threshold) violation_state = (delta<=threshold)
return violation_state return violation_state
def check_participants_agree_on_estimated_time(self, shipcall, query, df_times, applicable_shipcall_type)->bool: def check_participants_agree_on_estimated_time(self, shipcall, query, df_times, applicable_shipcall_type)->bool:
""" """
# base function for all validation rules in the group {0002} A-C # base function for all validation rules in the group {0002} A-C
@ -116,11 +116,11 @@ class ValidationRuleBaseFunctions():
No violations are observed, when No violations are observed, when
- the shipcall belongs to a different type than the rule expects - the shipcall belongs to a different type than the rule expects
- there are no matching times for the provided {query} (e.g., "eta_berth") - there are no matching times for the provided {query} (e.g., "eta_berth")
Instead of comparing each individual result, this function counts the amount of unique instances. Instead of comparing each individual result, this function counts the amount of unique instances.
When there is not only one unique value, there are deviating time estimates, and a violation occurs When there is not only one unique value, there are deviating time estimates, and a violation occurs
To reduce the potential of false violations, the agreement is rounded (e.g., by minute). To reduce the potential of false violations, the agreement is rounded (e.g., by minute).
returns: violation_state (bool) returns: violation_state (bool)
""" """
@ -133,28 +133,31 @@ class ValidationRuleBaseFunctions():
if not self.ignore_port_administration_flag: if not self.ignore_port_administration_flag:
participant_types = [ParticipantType.AGENCY.value, ParticipantType.MOORING.value, ParticipantType.PORT_ADMINISTRATION.value, ParticipantType.PILOT.value, ParticipantType.TUG.value] participant_types = [ParticipantType.AGENCY.value, ParticipantType.MOORING.value, ParticipantType.PORT_ADMINISTRATION.value, ParticipantType.PILOT.value, ParticipantType.TUG.value]
else: else:
participant_types = [ParticipantType.AGENCY.value, ParticipantType.MOORING.value, ParticipantType.PORT_ADMINISTRATION.value, ParticipantType.PILOT.value, ParticipantType.TUG.value] participant_types = [ParticipantType.AGENCY.value, ParticipantType.MOORING.value, ParticipantType.PILOT.value, ParticipantType.TUG.value]
df_times = df_times.loc[df_times["participant_type"].isin(participant_types),:] df_times = df_times.loc[df_times["participant_type"].isin(participant_types),:]
# exclude missing entries and consider only pd.Timestamp entries (which ignores pd.NaT/null entries) # exclude missing entries and consider only pd.Timestamp entries (which ignores pd.NaT/null entries)
estimated_times = [time_ for time_ in df_times.loc[:,query].tolist() if isinstance(time_, pd.Timestamp)] # df_times = df_times.loc[~df_times[query].isnull(),:] estimated_times = [time_ for time_ in df_times.loc[:,query].tolist() if isinstance(time_, pd.Timestamp)] # df_times = df_times.loc[~df_times[query].isnull(),:]
# apply rounding. For example, the agreement of different participants may be required to match minute-wise
# '15min' rounds to 'every 15 minutes'. E.g., '2023-09-22 08:18:49' becomes '2023-09-22 08:15:00'
estimated_times = [time_.round("15min") for time_ in estimated_times]
# when there are no entries left (no entries are provided), skip # when there are no entries left (no entries are provided), skip
if len(estimated_times)==0: if len(estimated_times)==0:
violation_state = False violation_state = False
return violation_state return violation_state
difference = np.max(estimated_times) - np.min(estimated_times)
violation_state = difference > pd.Timedelta("15min")
# apply rounding. For example, the agreement of different participants may be required to match minute-wise
# '15min' rounds to 'every 15 minutes'. E.g., '2023-09-22 08:18:49' becomes '2023-09-22 08:15:00'
# estimated_times = [time_.round("15min") for time_ in estimated_times]
# there should only be one eta_berth, when all participants have provided the same time # there should only be one eta_berth, when all participants have provided the same time
# this equates to the same criteria as checking, whether # this equates to the same criteria as checking, whether
# times_agency.eta_berth==times_mooring.eta_berth==times_portadministration.eta_berth==times_pilot.eta_berth==times_tug.eta_berth # times_agency.eta_berth==times_mooring.eta_berth==times_portadministration.eta_berth==times_pilot.eta_berth==times_tug.eta_berth
n_unique_times = len(np.unique(estimated_times)) # n_unique_times = len(np.unique(estimated_times))
violation_state = n_unique_times!=1 # violation_state = n_unique_times!=1
return violation_state return violation_state
def check_unique_shipcall_counts(self, query:str, times_agency:pd.DataFrame, rounding="min", maximum_threshold=3, all_times_agency=None)->bool: def check_unique_shipcall_counts(self, query:str, times_agency:pd.DataFrame, rounding="min", maximum_threshold=3, all_times_agency=None)->bool:
""" """
# base function for all validation rules in the group {0005} A&B # base function for all validation rules in the group {0005} A&B
@ -182,13 +185,13 @@ class ValidationRuleBaseFunctions():
class ValidationRuleFunctions(ValidationRuleBaseFunctions): class ValidationRuleFunctions(ValidationRuleBaseFunctions):
""" """
an accumulation object that makes sure, that any validation rule is translated to a function with default naming convention and an accumulation object that makes sure, that any validation rule is translated to a function with default naming convention and
return types. Each function should return a ValidationRuleState enumeration object and a description string to which validation rule return types. Each function should return a ValidationRuleState enumeration object and a description string to which validation rule
the result belongs. These are returned as tuples (ValidationRuleState, validation_name) the result belongs. These are returned as tuples (ValidationRuleState, validation_name)
Each rule should have the same input arguments (self, shipcall, df_times, *args, **kwargs) Each rule should have the same input arguments (self, shipcall, df_times, *args, **kwargs)
The object makes heavy use of calls from an SQLHandler object, which provides functions for dataframe access and filtering. The object makes heavy use of calls from an SQLHandler object, which provides functions for dataframe access and filtering.
each validation_name is generated by calling the function inside a method each validation_name is generated by calling the function inside a method
validation_name = inspect.currentframe().f_code.co_name # validation_name then returns the name of the method from where 'currentframe()' was called. validation_name = inspect.currentframe().f_code.co_name # validation_name then returns the name of the method from where 'currentframe()' was called.
@ -199,12 +202,12 @@ class ValidationRuleFunctions(ValidationRuleBaseFunctions):
""" """
def __init__(self, sql_handler): def __init__(self, sql_handler):
super().__init__(sql_handler) super().__init__(sql_handler)
return return
def get_validation_rule_functions(self): def get_validation_rule_functions(self):
"""return a list of all methods in this object, which are all validation rule functions.""" """return a list of all methods in this object, which are all validation rule functions."""
return [self.__getattribute__(mthd_) for mthd_ in dir(self) if ('validation_rule_fct' in mthd_) and (isinstance(self.__getattribute__(mthd_), types.MethodType))] return [self.__getattribute__(mthd_) for mthd_ in dir(self) if ('validation_rule_fct' in mthd_) and (isinstance(self.__getattribute__(mthd_), types.MethodType))]
def validation_rule_fct_missing_time_agency_berth_eta(self, shipcall, df_times, *args, **kwargs): def validation_rule_fct_missing_time_agency_berth_eta(self, shipcall, df_times, *args, **kwargs):
""" """
Code: #0001-A Code: #0001-A
@ -213,17 +216,17 @@ class ValidationRuleFunctions(ValidationRuleBaseFunctions):
a certain threshold (e.g., 20 hours), a violation occurs a certain threshold (e.g., 20 hours), a violation occurs
0001-A: 0001-A:
- Checks, if times_agency.eta_berth is filled in. - Checks, if times_agency.eta_berth is filled in.
- Measures the difference between 'now' and 'shipcall.eta'. - Measures the difference between 'now' and 'shipcall.eta'.
""" """
if not shipcall.type in [ShipcallType.INCOMING.value]: if not shipcall.type in [ShipcallType.INCOMING.value]:
return self.get_no_violation_default_output() return self.get_no_violation_default_output()
# check, if the header is filled in # check, if the header is filled in
unassigned = self.sql_handler.check_if_any_participant_of_type_is_unassigned(shipcall, *[ParticipantType.AGENCY]) unassigned = self.sql_handler.check_if_any_participant_of_type_is_unassigned(shipcall, *[ParticipantType.AGENCY])
if unassigned: if unassigned:
return self.get_no_violation_default_output() return self.get_no_violation_default_output()
# preparation: obtain the correct times of the participant, define the query time and the key time # preparation: obtain the correct times of the participant, define the query time and the key time
times_agency = self.sql_handler.get_times_for_participant_type(df_times, participant_type=ParticipantType.AGENCY.value) times_agency = self.sql_handler.get_times_for_participant_type(df_times, participant_type=ParticipantType.AGENCY.value)
query_time = shipcall.eta query_time = shipcall.eta
@ -236,7 +239,7 @@ class ValidationRuleFunctions(ValidationRuleBaseFunctions):
return (StatusFlags.YELLOW, validation_name) return (StatusFlags.YELLOW, validation_name)
else: else:
return self.get_no_violation_default_output() return self.get_no_violation_default_output()
def validation_rule_fct_missing_time_agency_berth_etd(self, shipcall, df_times, *args, **kwargs): def validation_rule_fct_missing_time_agency_berth_etd(self, shipcall, df_times, *args, **kwargs):
""" """
Code: #0001-B Code: #0001-B
@ -245,17 +248,17 @@ class ValidationRuleFunctions(ValidationRuleBaseFunctions):
a certain threshold (e.g., 20 hours), a violation occurs a certain threshold (e.g., 20 hours), a violation occurs
0001-B: 0001-B:
- Checks, if times_agency.etd_berth is filled in. - Checks, if times_agency.etd_berth is filled in.
- Measures the difference between 'now' and 'shipcall.etd'. - Measures the difference between 'now' and 'shipcall.etd'.
""" """
if not shipcall.type in [ShipcallType.OUTGOING.value, ShipcallType.SHIFTING.value]: if not shipcall.type in [ShipcallType.OUTGOING.value, ShipcallType.SHIFTING.value]:
return self.get_no_violation_default_output() return self.get_no_violation_default_output()
# check, if the header is filled in # check, if the header is filled in
unassigned = self.sql_handler.check_if_any_participant_of_type_is_unassigned(shipcall, *[ParticipantType.AGENCY]) unassigned = self.sql_handler.check_if_any_participant_of_type_is_unassigned(shipcall, *[ParticipantType.AGENCY])
if unassigned: if unassigned:
return self.get_no_violation_default_output() return self.get_no_violation_default_output()
# preparation: obtain the correct times of the participant, define the query time and the key time # preparation: obtain the correct times of the participant, define the query time and the key time
times_agency = self.sql_handler.get_times_for_participant_type(df_times, participant_type=ParticipantType.AGENCY.value) times_agency = self.sql_handler.get_times_for_participant_type(df_times, participant_type=ParticipantType.AGENCY.value)
query_time = shipcall.etd query_time = shipcall.etd
@ -268,7 +271,7 @@ class ValidationRuleFunctions(ValidationRuleBaseFunctions):
return (StatusFlags.YELLOW, validation_name) return (StatusFlags.YELLOW, validation_name)
else: else:
return self.get_no_violation_default_output() return self.get_no_violation_default_output()
def validation_rule_fct_missing_time_mooring_berth_eta(self, shipcall, df_times, *args, **kwargs): def validation_rule_fct_missing_time_mooring_berth_eta(self, shipcall, df_times, *args, **kwargs):
""" """
Code: #0001-C Code: #0001-C
@ -277,12 +280,12 @@ class ValidationRuleFunctions(ValidationRuleBaseFunctions):
a certain threshold (e.g., 20 hours), a violation occurs a certain threshold (e.g., 20 hours), a violation occurs
0001-C: 0001-C:
- Checks, if times_mooring.eta_berth is filled in. - Checks, if times_mooring.eta_berth is filled in.
- Measures the difference between 'now' and 'times_agency.eta_berth'. - Measures the difference between 'now' and 'times_agency.eta_berth'.
""" """
if not shipcall.type in [ShipcallType.INCOMING.value]: if not shipcall.type in [ShipcallType.INCOMING.value]:
return self.get_no_violation_default_output() return self.get_no_violation_default_output()
# check, if the header is filled in # check, if the header is filled in
unassigned = self.sql_handler.check_if_any_participant_of_type_is_unassigned(shipcall, *[ParticipantType.AGENCY, ParticipantType.MOORING]) unassigned = self.sql_handler.check_if_any_participant_of_type_is_unassigned(shipcall, *[ParticipantType.AGENCY, ParticipantType.MOORING])
if unassigned: if unassigned:
@ -302,7 +305,7 @@ class ValidationRuleFunctions(ValidationRuleBaseFunctions):
return (StatusFlags.YELLOW, validation_name) return (StatusFlags.YELLOW, validation_name)
else: else:
return self.get_no_violation_default_output() return self.get_no_violation_default_output()
def validation_rule_fct_missing_time_mooring_berth_etd(self, shipcall, df_times, *args, **kwargs): def validation_rule_fct_missing_time_mooring_berth_etd(self, shipcall, df_times, *args, **kwargs):
""" """
Code: #0001-D Code: #0001-D
@ -311,12 +314,12 @@ class ValidationRuleFunctions(ValidationRuleBaseFunctions):
a certain threshold (e.g., 20 hours), a violation occurs a certain threshold (e.g., 20 hours), a violation occurs
0001-D: 0001-D:
- Checks, if times_mooring.etd_berth is filled in. - Checks, if times_mooring.etd_berth is filled in.
- Measures the difference between 'now' and 'times_agency.etd_berth'. - Measures the difference between 'now' and 'times_agency.etd_berth'.
""" """
if not shipcall.type in [ShipcallType.OUTGOING.value, ShipcallType.SHIFTING.value]: if not shipcall.type in [ShipcallType.OUTGOING.value, ShipcallType.SHIFTING.value]:
return self.get_no_violation_default_output() return self.get_no_violation_default_output()
# check, if the header is filled in # check, if the header is filled in
unassigned = self.sql_handler.check_if_any_participant_of_type_is_unassigned(shipcall, *[ParticipantType.AGENCY, ParticipantType.MOORING]) unassigned = self.sql_handler.check_if_any_participant_of_type_is_unassigned(shipcall, *[ParticipantType.AGENCY, ParticipantType.MOORING])
if unassigned: if unassigned:
@ -336,7 +339,7 @@ class ValidationRuleFunctions(ValidationRuleBaseFunctions):
return (StatusFlags.YELLOW, validation_name) return (StatusFlags.YELLOW, validation_name)
else: else:
return self.get_no_violation_default_output() return self.get_no_violation_default_output()
def validation_rule_fct_missing_time_portadministration_berth_eta(self, shipcall, df_times, *args, **kwargs): def validation_rule_fct_missing_time_portadministration_berth_eta(self, shipcall, df_times, *args, **kwargs):
""" """
Code: #0001-F Code: #0001-F
@ -345,20 +348,20 @@ class ValidationRuleFunctions(ValidationRuleBaseFunctions):
a certain threshold (e.g., 20 hours), a violation occurs a certain threshold (e.g., 20 hours), a violation occurs
0001-F: 0001-F:
- Checks, if times_port_administration.eta_berth is filled in. - Checks, if times_port_administration.eta_berth is filled in.
- Measures the difference between 'now' and 'times_agency.eta_berth'. - Measures the difference between 'now' and 'times_agency.eta_berth'.
""" """
if self.ignore_port_administration_flag: if self.ignore_port_administration_flag:
return self.get_no_violation_default_output() return self.get_no_violation_default_output()
if not shipcall.type in [ShipcallType.INCOMING.value]: if not shipcall.type in [ShipcallType.INCOMING.value]:
return self.get_no_violation_default_output() return self.get_no_violation_default_output()
# check, if the header is filled in # check, if the header is filled in
unassigned = self.sql_handler.check_if_any_participant_of_type_is_unassigned(shipcall, *[ParticipantType.AGENCY, ParticipantType.PORT_ADMINISTRATION]) unassigned = self.sql_handler.check_if_any_participant_of_type_is_unassigned(shipcall, *[ParticipantType.AGENCY, ParticipantType.PORT_ADMINISTRATION])
if unassigned: if unassigned:
return self.get_no_violation_default_output() return self.get_no_violation_default_output()
# preparation: obtain the correct times of the participant, define the query time and the key time # preparation: obtain the correct times of the participant, define the query time and the key time
times_agency = self.sql_handler.get_times_for_participant_type(df_times, participant_type=ParticipantType.AGENCY.value) times_agency = self.sql_handler.get_times_for_participant_type(df_times, participant_type=ParticipantType.AGENCY.value)
times_port_administration = self.sql_handler.get_times_for_participant_type(df_times, participant_type=ParticipantType.PORT_ADMINISTRATION.value) times_port_administration = self.sql_handler.get_times_for_participant_type(df_times, participant_type=ParticipantType.PORT_ADMINISTRATION.value)
@ -373,7 +376,7 @@ class ValidationRuleFunctions(ValidationRuleBaseFunctions):
return (StatusFlags.YELLOW, validation_name) return (StatusFlags.YELLOW, validation_name)
else: else:
return self.get_no_violation_default_output() return self.get_no_violation_default_output()
def validation_rule_fct_missing_time_portadministration_berth_etd(self, shipcall, df_times, *args, **kwargs): def validation_rule_fct_missing_time_portadministration_berth_etd(self, shipcall, df_times, *args, **kwargs):
""" """
Code: #0001-G Code: #0001-G
@ -382,7 +385,7 @@ class ValidationRuleFunctions(ValidationRuleBaseFunctions):
a certain threshold (e.g., 20 hours), a violation occurs a certain threshold (e.g., 20 hours), a violation occurs
0001-G: 0001-G:
- Checks, if times_port_administration.etd_berth is filled in. - Checks, if times_port_administration.etd_berth is filled in.
- Measures the difference between 'now' and 'times_agency.etd_berth'. - Measures the difference between 'now' and 'times_agency.etd_berth'.
""" """
if self.ignore_port_administration_flag: if self.ignore_port_administration_flag:
@ -390,12 +393,12 @@ class ValidationRuleFunctions(ValidationRuleBaseFunctions):
if not shipcall.type in [ShipcallType.OUTGOING.value, ShipcallType.SHIFTING.value]: if not shipcall.type in [ShipcallType.OUTGOING.value, ShipcallType.SHIFTING.value]:
return self.get_no_violation_default_output() return self.get_no_violation_default_output()
# check, if the header is filled in # check, if the header is filled in
unassigned = self.sql_handler.check_if_any_participant_of_type_is_unassigned(shipcall, *[ParticipantType.AGENCY, ParticipantType.PORT_ADMINISTRATION]) unassigned = self.sql_handler.check_if_any_participant_of_type_is_unassigned(shipcall, *[ParticipantType.AGENCY, ParticipantType.PORT_ADMINISTRATION])
if unassigned: if unassigned:
return self.get_no_violation_default_output() return self.get_no_violation_default_output()
# preparation: obtain the correct times of the participant, define the query time and the key time # preparation: obtain the correct times of the participant, define the query time and the key time
# when there are no times, the function returns None # when there are no times, the function returns None
times_agency = self.sql_handler.get_times_for_participant_type(df_times, participant_type=ParticipantType.AGENCY.value) times_agency = self.sql_handler.get_times_for_participant_type(df_times, participant_type=ParticipantType.AGENCY.value)
@ -411,7 +414,7 @@ class ValidationRuleFunctions(ValidationRuleBaseFunctions):
return (StatusFlags.YELLOW, validation_name) return (StatusFlags.YELLOW, validation_name)
else: else:
return self.get_no_violation_default_output() return self.get_no_violation_default_output()
def validation_rule_fct_missing_time_pilot_berth_eta(self, shipcall, df_times, *args, **kwargs): def validation_rule_fct_missing_time_pilot_berth_eta(self, shipcall, df_times, *args, **kwargs):
""" """
Code: #0001-H Code: #0001-H
@ -420,17 +423,17 @@ class ValidationRuleFunctions(ValidationRuleBaseFunctions):
a certain threshold (e.g., 20 hours), a violation occurs a certain threshold (e.g., 20 hours), a violation occurs
0001-H: 0001-H:
- Checks, if times_pilot.eta_berth is filled in. - Checks, if times_pilot.eta_berth is filled in.
- Measures the difference between 'now' and 'times_agency.eta_berth'. - Measures the difference between 'now' and 'times_agency.eta_berth'.
""" """
if not shipcall.type in [ShipcallType.INCOMING.value]: if not shipcall.type in [ShipcallType.INCOMING.value]:
return self.get_no_violation_default_output() return self.get_no_violation_default_output()
# check, if the header is filled in # check, if the header is filled in
unassigned = self.sql_handler.check_if_any_participant_of_type_is_unassigned(shipcall, *[ParticipantType.AGENCY, ParticipantType.PILOT]) unassigned = self.sql_handler.check_if_any_participant_of_type_is_unassigned(shipcall, *[ParticipantType.AGENCY, ParticipantType.PILOT])
if unassigned: if unassigned:
return self.get_no_violation_default_output() return self.get_no_violation_default_output()
# preparation: obtain the correct times of the participant, define the query time and the key time # preparation: obtain the correct times of the participant, define the query time and the key time
times_agency = self.sql_handler.get_times_for_participant_type(df_times, participant_type=ParticipantType.AGENCY.value) times_agency = self.sql_handler.get_times_for_participant_type(df_times, participant_type=ParticipantType.AGENCY.value)
times_pilot = self.sql_handler.get_times_for_participant_type(df_times, participant_type=ParticipantType.PILOT.value) times_pilot = self.sql_handler.get_times_for_participant_type(df_times, participant_type=ParticipantType.PILOT.value)
@ -439,13 +442,13 @@ class ValidationRuleFunctions(ValidationRuleBaseFunctions):
key_time = times_pilot.eta_berth if times_pilot is not None else None key_time = times_pilot.eta_berth if times_pilot is not None else None
threshold = ParticipantwiseTimeDelta.PILOT threshold = ParticipantwiseTimeDelta.PILOT
violation_state = self.check_time_delta_violation_query_time_to_now(query_time=query_time, key_time=key_time, threshold=threshold) violation_state = self.check_time_delta_violation_query_time_to_now(query_time=query_time, key_time=key_time, threshold=threshold)
if violation_state: if violation_state:
validation_name = "validation_rule_fct_missing_time_pilot_berth_eta" validation_name = "validation_rule_fct_missing_time_pilot_berth_eta"
return (StatusFlags.YELLOW, validation_name) return (StatusFlags.YELLOW, validation_name)
else: else:
return self.get_no_violation_default_output() return self.get_no_violation_default_output()
def validation_rule_fct_missing_time_pilot_berth_etd(self, shipcall, df_times, *args, **kwargs): def validation_rule_fct_missing_time_pilot_berth_etd(self, shipcall, df_times, *args, **kwargs):
""" """
Code: #0001-I Code: #0001-I
@ -454,17 +457,17 @@ class ValidationRuleFunctions(ValidationRuleBaseFunctions):
a certain threshold (e.g., 20 hours), a violation occurs a certain threshold (e.g., 20 hours), a violation occurs
0001-I: 0001-I:
- Checks, if times_pilot.etd_berth is filled in. - Checks, if times_pilot.etd_berth is filled in.
- Measures the difference between 'now' and 'times_agency.etd_berth'. - Measures the difference between 'now' and 'times_agency.etd_berth'.
""" """
if not shipcall.type in [ShipcallType.OUTGOING.value, ShipcallType.SHIFTING.value]: if not shipcall.type in [ShipcallType.OUTGOING.value, ShipcallType.SHIFTING.value]:
return self.get_no_violation_default_output() return self.get_no_violation_default_output()
# check, if the header is filled in # check, if the header is filled in
unassigned = self.sql_handler.check_if_any_participant_of_type_is_unassigned(shipcall, *[ParticipantType.AGENCY, ParticipantType.PILOT]) unassigned = self.sql_handler.check_if_any_participant_of_type_is_unassigned(shipcall, *[ParticipantType.AGENCY, ParticipantType.PILOT])
if unassigned: if unassigned:
return self.get_no_violation_default_output() return self.get_no_violation_default_output()
# preparation: obtain the correct times of the participant, define the query time and the key time # preparation: obtain the correct times of the participant, define the query time and the key time
times_agency = self.sql_handler.get_times_for_participant_type(df_times, participant_type=ParticipantType.AGENCY.value) times_agency = self.sql_handler.get_times_for_participant_type(df_times, participant_type=ParticipantType.AGENCY.value)
times_pilot = self.sql_handler.get_times_for_participant_type(df_times, participant_type=ParticipantType.PILOT.value) times_pilot = self.sql_handler.get_times_for_participant_type(df_times, participant_type=ParticipantType.PILOT.value)
@ -473,13 +476,13 @@ class ValidationRuleFunctions(ValidationRuleBaseFunctions):
key_time = times_pilot.etd_berth if times_pilot is not None else None key_time = times_pilot.etd_berth if times_pilot is not None else None
threshold = ParticipantwiseTimeDelta.PILOT threshold = ParticipantwiseTimeDelta.PILOT
violation_state = self.check_time_delta_violation_query_time_to_now(query_time=query_time, key_time=key_time, threshold=threshold) violation_state = self.check_time_delta_violation_query_time_to_now(query_time=query_time, key_time=key_time, threshold=threshold)
if violation_state: if violation_state:
validation_name = "validation_rule_fct_missing_time_pilot_berth_etd" validation_name = "validation_rule_fct_missing_time_pilot_berth_etd"
return (StatusFlags.YELLOW, validation_name) return (StatusFlags.YELLOW, validation_name)
else: else:
return self.get_no_violation_default_output() return self.get_no_violation_default_output()
def validation_rule_fct_missing_time_tug_berth_eta(self, shipcall, df_times, *args, **kwargs): def validation_rule_fct_missing_time_tug_berth_eta(self, shipcall, df_times, *args, **kwargs):
""" """
Code: #0001-J Code: #0001-J
@ -488,17 +491,17 @@ class ValidationRuleFunctions(ValidationRuleBaseFunctions):
a certain threshold (e.g., 20 hours), a violation occurs a certain threshold (e.g., 20 hours), a violation occurs
0001-J: 0001-J:
- Checks, if times_tug.eta_berth is filled in. - Checks, if times_tug.eta_berth is filled in.
- Measures the difference between 'now' and 'times_agency.eta_berth'. - Measures the difference between 'now' and 'times_agency.eta_berth'.
""" """
if not shipcall.type in [ShipcallType.INCOMING.value]: if not shipcall.type in [ShipcallType.INCOMING.value]:
return self.get_no_violation_default_output() return self.get_no_violation_default_output()
# check, if the header is filled in # check, if the header is filled in
unassigned = self.sql_handler.check_if_any_participant_of_type_is_unassigned(shipcall, *[ParticipantType.AGENCY, ParticipantType.TUG]) unassigned = self.sql_handler.check_if_any_participant_of_type_is_unassigned(shipcall, *[ParticipantType.AGENCY, ParticipantType.TUG])
if unassigned: if unassigned:
return self.get_no_violation_default_output() return self.get_no_violation_default_output()
# preparation: obtain the correct times of the participant, define the query time and the key time # preparation: obtain the correct times of the participant, define the query time and the key time
times_agency = self.sql_handler.get_times_for_participant_type(df_times, participant_type=ParticipantType.AGENCY.value) times_agency = self.sql_handler.get_times_for_participant_type(df_times, participant_type=ParticipantType.AGENCY.value)
times_tug = self.sql_handler.get_times_for_participant_type(df_times, participant_type=ParticipantType.TUG.value) times_tug = self.sql_handler.get_times_for_participant_type(df_times, participant_type=ParticipantType.TUG.value)
@ -507,13 +510,13 @@ class ValidationRuleFunctions(ValidationRuleBaseFunctions):
key_time = times_tug.eta_berth if times_tug is not None else None key_time = times_tug.eta_berth if times_tug is not None else None
threshold = ParticipantwiseTimeDelta.TUG threshold = ParticipantwiseTimeDelta.TUG
violation_state = self.check_time_delta_violation_query_time_to_now(query_time=query_time, key_time=key_time, threshold=threshold) violation_state = self.check_time_delta_violation_query_time_to_now(query_time=query_time, key_time=key_time, threshold=threshold)
if violation_state: if violation_state:
validation_name = "validation_rule_fct_missing_time_tug_berth_eta" validation_name = "validation_rule_fct_missing_time_tug_berth_eta"
return (StatusFlags.YELLOW, validation_name) return (StatusFlags.YELLOW, validation_name)
else: else:
return self.get_no_violation_default_output() return self.get_no_violation_default_output()
def validation_rule_fct_missing_time_tug_berth_etd(self, shipcall, df_times, *args, **kwargs): def validation_rule_fct_missing_time_tug_berth_etd(self, shipcall, df_times, *args, **kwargs):
""" """
Code: #0001-K Code: #0001-K
@ -522,17 +525,17 @@ class ValidationRuleFunctions(ValidationRuleBaseFunctions):
a certain threshold (e.g., 20 hours), a violation occurs a certain threshold (e.g., 20 hours), a violation occurs
0001-K: 0001-K:
- Checks, if times_tug.etd_berth is filled in. - Checks, if times_tug.etd_berth is filled in.
- Measures the difference between 'now' and 'times_agency.etd_berth'. - Measures the difference between 'now' and 'times_agency.etd_berth'.
""" """
if not shipcall.type in [ShipcallType.OUTGOING.value, ShipcallType.SHIFTING.value]: if not shipcall.type in [ShipcallType.OUTGOING.value, ShipcallType.SHIFTING.value]:
return self.get_no_violation_default_output() return self.get_no_violation_default_output()
# check, if the header is filled in # check, if the header is filled in
unassigned = self.sql_handler.check_if_any_participant_of_type_is_unassigned(shipcall, *[ParticipantType.AGENCY, ParticipantType.TUG]) unassigned = self.sql_handler.check_if_any_participant_of_type_is_unassigned(shipcall, *[ParticipantType.AGENCY, ParticipantType.TUG])
if unassigned: if unassigned:
return self.get_no_violation_default_output() return self.get_no_violation_default_output()
# preparation: obtain the correct times of the participant, define the query time and the key time # preparation: obtain the correct times of the participant, define the query time and the key time
times_agency = self.sql_handler.get_times_for_participant_type(df_times, participant_type=ParticipantType.AGENCY.value) times_agency = self.sql_handler.get_times_for_participant_type(df_times, participant_type=ParticipantType.AGENCY.value)
times_tug = self.sql_handler.get_times_for_participant_type(df_times, participant_type=ParticipantType.TUG.value) times_tug = self.sql_handler.get_times_for_participant_type(df_times, participant_type=ParticipantType.TUG.value)
@ -541,13 +544,13 @@ class ValidationRuleFunctions(ValidationRuleBaseFunctions):
key_time = times_tug.etd_berth if times_tug is not None else None key_time = times_tug.etd_berth if times_tug is not None else None
threshold = ParticipantwiseTimeDelta.TUG threshold = ParticipantwiseTimeDelta.TUG
violation_state = self.check_time_delta_violation_query_time_to_now(query_time=query_time, key_time=key_time, threshold=threshold) violation_state = self.check_time_delta_violation_query_time_to_now(query_time=query_time, key_time=key_time, threshold=threshold)
if violation_state: if violation_state:
validation_name = "validation_rule_fct_missing_time_tug_berth_etd" validation_name = "validation_rule_fct_missing_time_tug_berth_etd"
return (StatusFlags.YELLOW, validation_name) return (StatusFlags.YELLOW, validation_name)
else: else:
return self.get_no_violation_default_output() return self.get_no_violation_default_output()
def validation_rule_fct_missing_time_terminal_berth_eta(self, shipcall, df_times, *args, **kwargs): def validation_rule_fct_missing_time_terminal_berth_eta(self, shipcall, df_times, *args, **kwargs):
""" """
Code: #0001-L Code: #0001-L
@ -556,17 +559,17 @@ class ValidationRuleFunctions(ValidationRuleBaseFunctions):
a certain threshold (e.g., 20 hours), a violation occurs a certain threshold (e.g., 20 hours), a violation occurs
0001-L: 0001-L:
- Checks, if times_terminal.operations_start is filled in. - Checks, if times_terminal.operations_start is filled in.
- Measures the difference between 'now' and 'times_agency.eta_berth'. - Measures the difference between 'now' and 'times_agency.eta_berth'.
""" """
if not shipcall.type in [ShipcallType.INCOMING.value]: if not shipcall.type in [ShipcallType.INCOMING.value]:
return self.get_no_violation_default_output() return self.get_no_violation_default_output()
# check, if the header is filled in # check, if the header is filled in
unassigned = self.sql_handler.check_if_any_participant_of_type_is_unassigned(shipcall, *[ParticipantType.AGENCY, ParticipantType.TERMINAL]) unassigned = self.sql_handler.check_if_any_participant_of_type_is_unassigned(shipcall, *[ParticipantType.AGENCY, ParticipantType.TERMINAL])
if unassigned: if unassigned:
return self.get_no_violation_default_output() return self.get_no_violation_default_output()
# preparation: obtain the correct times of the participant, define the query time and the key time # preparation: obtain the correct times of the participant, define the query time and the key time
times_agency = self.sql_handler.get_times_for_participant_type(df_times, participant_type=ParticipantType.AGENCY.value) times_agency = self.sql_handler.get_times_for_participant_type(df_times, participant_type=ParticipantType.AGENCY.value)
times_terminal = self.sql_handler.get_times_for_participant_type(df_times, participant_type=ParticipantType.TERMINAL.value) times_terminal = self.sql_handler.get_times_for_participant_type(df_times, participant_type=ParticipantType.TERMINAL.value)
@ -575,13 +578,13 @@ class ValidationRuleFunctions(ValidationRuleBaseFunctions):
key_time = times_terminal.operations_start if times_terminal is not None else None # eta_berth does not exist in times_terminal! Instead, it is called operations_start key_time = times_terminal.operations_start if times_terminal is not None else None # eta_berth does not exist in times_terminal! Instead, it is called operations_start
threshold = ParticipantwiseTimeDelta.TERMINAL threshold = ParticipantwiseTimeDelta.TERMINAL
violation_state = self.check_time_delta_violation_query_time_to_now(query_time=query_time, key_time=key_time, threshold=threshold) violation_state = self.check_time_delta_violation_query_time_to_now(query_time=query_time, key_time=key_time, threshold=threshold)
if violation_state: if violation_state:
validation_name = "validation_rule_fct_missing_time_terminal_berth_eta" validation_name = "validation_rule_fct_missing_time_terminal_berth_eta"
return (StatusFlags.YELLOW, validation_name) return (StatusFlags.YELLOW, validation_name)
else: else:
return self.get_no_violation_default_output() return self.get_no_violation_default_output()
def validation_rule_fct_missing_time_terminal_berth_etd(self, shipcall, df_times, *args, **kwargs): def validation_rule_fct_missing_time_terminal_berth_etd(self, shipcall, df_times, *args, **kwargs):
""" """
Code: #0001-M Code: #0001-M
@ -590,17 +593,17 @@ class ValidationRuleFunctions(ValidationRuleBaseFunctions):
a certain threshold (e.g., 20 hours), a violation occurs a certain threshold (e.g., 20 hours), a violation occurs
0001-M: 0001-M:
- Checks, if times_terminal.operations_end is filled in. - Checks, if times_terminal.operations_end is filled in.
- Measures the difference between 'now' and 'times_agency.etd_berth'. - Measures the difference between 'now' and 'times_agency.etd_berth'.
""" """
if not shipcall.type in [ShipcallType.OUTGOING.value, ShipcallType.SHIFTING.value]: if not shipcall.type in [ShipcallType.OUTGOING.value, ShipcallType.SHIFTING.value]:
return self.get_no_violation_default_output() return self.get_no_violation_default_output()
# check, if the header is filled in # check, if the header is filled in
unassigned = self.sql_handler.check_if_any_participant_of_type_is_unassigned(shipcall, *[ParticipantType.AGENCY, ParticipantType.TERMINAL]) unassigned = self.sql_handler.check_if_any_participant_of_type_is_unassigned(shipcall, *[ParticipantType.AGENCY, ParticipantType.TERMINAL])
if unassigned: if unassigned:
return self.get_no_violation_default_output() return self.get_no_violation_default_output()
# preparation: obtain the correct times of the participant, define the query time and the key time # preparation: obtain the correct times of the participant, define the query time and the key time
times_agency = self.sql_handler.get_times_for_participant_type(df_times, participant_type=ParticipantType.AGENCY.value) times_agency = self.sql_handler.get_times_for_participant_type(df_times, participant_type=ParticipantType.AGENCY.value)
times_terminal = self.sql_handler.get_times_for_participant_type(df_times, participant_type=ParticipantType.TERMINAL.value) times_terminal = self.sql_handler.get_times_for_participant_type(df_times, participant_type=ParticipantType.TERMINAL.value)
@ -609,13 +612,13 @@ class ValidationRuleFunctions(ValidationRuleBaseFunctions):
key_time = times_terminal.operations_end if times_terminal is not None else None # etd_berth does not exist in times_terminal! Instead, it is called operations_end key_time = times_terminal.operations_end if times_terminal is not None else None # etd_berth does not exist in times_terminal! Instead, it is called operations_end
threshold = ParticipantwiseTimeDelta.TERMINAL threshold = ParticipantwiseTimeDelta.TERMINAL
violation_state = self.check_time_delta_violation_query_time_to_now(query_time=query_time, key_time=key_time, threshold=threshold) violation_state = self.check_time_delta_violation_query_time_to_now(query_time=query_time, key_time=key_time, threshold=threshold)
if violation_state: if violation_state:
validation_name = "validation_rule_fct_missing_time_terminal_berth_etd" validation_name = "validation_rule_fct_missing_time_terminal_berth_etd"
return (StatusFlags.YELLOW, validation_name) return (StatusFlags.YELLOW, validation_name)
else: else:
return self.get_no_violation_default_output() return self.get_no_violation_default_output()
def validation_rule_fct_shipcall_incoming_participants_disagree_on_eta(self, shipcall, df_times, *args, **kwargs): def validation_rule_fct_shipcall_incoming_participants_disagree_on_eta(self, shipcall, df_times, *args, **kwargs):
""" """
Code: #0002-A Code: #0002-A
@ -624,21 +627,21 @@ class ValidationRuleFunctions(ValidationRuleBaseFunctions):
Filter: only applies to incoming shipcalls Filter: only applies to incoming shipcalls
""" """
query = "eta_berth" query = "eta_berth"
violation_state = self.check_participants_agree_on_estimated_time(
shipcall = shipcall,
query=query, violation_state = self.check_participants_agree_on_estimated_time(
df_times=df_times, shipcall = shipcall,
query=query,
df_times=df_times,
applicable_shipcall_type=ShipcallType.INCOMING applicable_shipcall_type=ShipcallType.INCOMING
) )
if violation_state: if violation_state:
validation_name = "validation_rule_fct_shipcall_incoming_participants_disagree_on_eta" validation_name = "validation_rule_fct_shipcall_incoming_participants_disagree_on_eta"
return (StatusFlags.RED, validation_name) return (StatusFlags.RED, validation_name)
else: else:
return self.get_no_violation_default_output() return self.get_no_violation_default_output()
def validation_rule_fct_shipcall_outgoing_participants_disagree_on_etd(self, shipcall, df_times, *args, **kwargs): def validation_rule_fct_shipcall_outgoing_participants_disagree_on_etd(self, shipcall, df_times, *args, **kwargs):
""" """
Code: #0002-B Code: #0002-B
@ -647,12 +650,12 @@ class ValidationRuleFunctions(ValidationRuleBaseFunctions):
Filter: only applies to outgoing shipcalls Filter: only applies to outgoing shipcalls
""" """
query = "etd_berth" query = "etd_berth"
violation_state = self.check_participants_agree_on_estimated_time(
shipcall = shipcall,
query=query, violation_state = self.check_participants_agree_on_estimated_time(
df_times=df_times, shipcall = shipcall,
query=query,
df_times=df_times,
applicable_shipcall_type=ShipcallType.OUTGOING applicable_shipcall_type=ShipcallType.OUTGOING
) )
@ -661,7 +664,7 @@ class ValidationRuleFunctions(ValidationRuleBaseFunctions):
return (StatusFlags.RED, validation_name) return (StatusFlags.RED, validation_name)
else: else:
return self.get_no_violation_default_output() return self.get_no_violation_default_output()
def validation_rule_fct_shipcall_shifting_participants_disagree_on_eta_or_etd(self, shipcall, df_times, *args, **kwargs): def validation_rule_fct_shipcall_shifting_participants_disagree_on_eta_or_etd(self, shipcall, df_times, *args, **kwargs):
""" """
Code: #0002-C Code: #0002-C
@ -670,21 +673,21 @@ class ValidationRuleFunctions(ValidationRuleBaseFunctions):
Filter: only applies to shifting shipcalls Filter: only applies to shifting shipcalls
""" """
violation_state_eta = self.check_participants_agree_on_estimated_time( violation_state_eta = self.check_participants_agree_on_estimated_time(
shipcall = shipcall, shipcall = shipcall,
query="eta_berth", query="eta_berth",
df_times=df_times, df_times=df_times,
applicable_shipcall_type=ShipcallType.SHIFTING applicable_shipcall_type=ShipcallType.SHIFTING
) )
violation_state_etd = self.check_participants_agree_on_estimated_time( violation_state_etd = self.check_participants_agree_on_estimated_time(
shipcall = shipcall, shipcall = shipcall,
query="etd_berth", query="etd_berth",
df_times=df_times, df_times=df_times,
applicable_shipcall_type=ShipcallType.SHIFTING applicable_shipcall_type=ShipcallType.SHIFTING
) )
# apply 'eta_berth' check # apply 'eta_berth' check
# apply 'etd_berth' # apply 'etd_berth'
# violation: if either 'eta_berth' or 'etd_berth' is violated # violation: if either 'eta_berth' or 'etd_berth' is violated
@ -698,7 +701,7 @@ class ValidationRuleFunctions(ValidationRuleBaseFunctions):
return (StatusFlags.RED, validation_name) return (StatusFlags.RED, validation_name)
else: else:
return self.get_no_violation_default_output() return self.get_no_violation_default_output()
def validation_rule_fct_eta_time_not_in_operation_window(self, shipcall, df_times, *args, **kwargs): def validation_rule_fct_eta_time_not_in_operation_window(self, shipcall, df_times, *args, **kwargs):
""" """
Code: #0003-A Code: #0003-A
@ -710,14 +713,14 @@ class ValidationRuleFunctions(ValidationRuleBaseFunctions):
""" """
if not shipcall.type in [ShipcallType.INCOMING.value]: if not shipcall.type in [ShipcallType.INCOMING.value]:
return self.get_no_violation_default_output() return self.get_no_violation_default_output()
# check, if the header is filled in (agency & terminal) # check, if the header is filled in (agency & terminal)
if len(df_times.loc[df_times["participant_type"]==ParticipantType.AGENCY.value]) != 1: if len(df_times.loc[df_times["participant_type"]==ParticipantType.AGENCY.value]) != 1:
return self.get_no_violation_default_output() # rule not applicable return self.get_no_violation_default_output() # rule not applicable
if len(df_times.loc[df_times["participant_type"]==ParticipantType.TERMINAL.value]) != 1: if len(df_times.loc[df_times["participant_type"]==ParticipantType.TERMINAL.value]) != 1:
return self.get_no_violation_default_output() # rule not applicable return self.get_no_violation_default_output() # rule not applicable
# get agency & terminal times # get agency & terminal times
times_agency = self.sql_handler.get_times_for_participant_type(df_times, participant_type=ParticipantType.AGENCY.value) times_agency = self.sql_handler.get_times_for_participant_type(df_times, participant_type=ParticipantType.AGENCY.value)
times_terminal = self.sql_handler.get_times_for_participant_type(df_times, participant_type=ParticipantType.TERMINAL.value) times_terminal = self.sql_handler.get_times_for_participant_type(df_times, participant_type=ParticipantType.TERMINAL.value)
@ -738,7 +741,7 @@ class ValidationRuleFunctions(ValidationRuleBaseFunctions):
return (StatusFlags.RED, validation_name) return (StatusFlags.RED, validation_name)
else: else:
return self.get_no_violation_default_output() return self.get_no_violation_default_output()
def validation_rule_fct_etd_time_not_in_operation_window(self, shipcall, df_times, *args, **kwargs): def validation_rule_fct_etd_time_not_in_operation_window(self, shipcall, df_times, *args, **kwargs):
""" """
Code: #0003-B Code: #0003-B
@ -750,14 +753,14 @@ class ValidationRuleFunctions(ValidationRuleBaseFunctions):
""" """
if not shipcall.type in [ShipcallType.OUTGOING.value, ShipcallType.SHIFTING.value]: if not shipcall.type in [ShipcallType.OUTGOING.value, ShipcallType.SHIFTING.value]:
return self.get_no_violation_default_output() return self.get_no_violation_default_output()
# check, if the header is filled in (agency & terminal) # check, if the header is filled in (agency & terminal)
if len(df_times.loc[df_times["participant_type"]==ParticipantType.AGENCY.value]) != 1: if len(df_times.loc[df_times["participant_type"]==ParticipantType.AGENCY.value]) != 1:
return self.get_no_violation_default_output() # rule not applicable return self.get_no_violation_default_output() # rule not applicable
if len(df_times.loc[df_times["participant_type"]==ParticipantType.TERMINAL.value]) != 1: if len(df_times.loc[df_times["participant_type"]==ParticipantType.TERMINAL.value]) != 1:
return self.get_no_violation_default_output() # rule not applicable return self.get_no_violation_default_output() # rule not applicable
# get agency & terminal times # get agency & terminal times
times_agency = self.sql_handler.get_times_for_participant_type(df_times, participant_type=ParticipantType.AGENCY.value) times_agency = self.sql_handler.get_times_for_participant_type(df_times, participant_type=ParticipantType.AGENCY.value)
times_terminal = self.sql_handler.get_times_for_participant_type(df_times, participant_type=ParticipantType.TERMINAL.value) times_terminal = self.sql_handler.get_times_for_participant_type(df_times, participant_type=ParticipantType.TERMINAL.value)
@ -778,7 +781,7 @@ class ValidationRuleFunctions(ValidationRuleBaseFunctions):
return (StatusFlags.RED, validation_name) return (StatusFlags.RED, validation_name)
else: else:
return self.get_no_violation_default_output() return self.get_no_violation_default_output()
def validation_rule_fct_eta_time_not_in_tidal_window(self, shipcall, df_times, *args, **kwargs): def validation_rule_fct_eta_time_not_in_tidal_window(self, shipcall, df_times, *args, **kwargs):
""" """
Code: #0004-A Code: #0004-A
@ -790,7 +793,7 @@ class ValidationRuleFunctions(ValidationRuleBaseFunctions):
""" """
if not shipcall.type in [ShipcallType.INCOMING.value]: if not shipcall.type in [ShipcallType.INCOMING.value]:
return self.get_no_violation_default_output() return self.get_no_violation_default_output()
# check, if the header is filled in (agency) # check, if the header is filled in (agency)
if len(df_times.loc[df_times["participant_type"].isin([ParticipantType.AGENCY.value])]) != 1: if len(df_times.loc[df_times["participant_type"].isin([ParticipantType.AGENCY.value])]) != 1:
return self.get_no_violation_default_output() return self.get_no_violation_default_output()
@ -809,7 +812,7 @@ class ValidationRuleFunctions(ValidationRuleBaseFunctions):
return (StatusFlags.RED, validation_name) return (StatusFlags.RED, validation_name)
else: else:
return self.get_no_violation_default_output() return self.get_no_violation_default_output()
def validation_rule_fct_etd_time_not_in_tidal_window(self, shipcall, df_times, *args, **kwargs): def validation_rule_fct_etd_time_not_in_tidal_window(self, shipcall, df_times, *args, **kwargs):
""" """
Code: #0004-B Code: #0004-B
@ -821,7 +824,7 @@ class ValidationRuleFunctions(ValidationRuleBaseFunctions):
""" """
if not shipcall.type in [ShipcallType.OUTGOING.value, ShipcallType.SHIFTING.value]: if not shipcall.type in [ShipcallType.OUTGOING.value, ShipcallType.SHIFTING.value]:
return self.get_no_violation_default_output() return self.get_no_violation_default_output()
# check, if the header is filled in (agency) # check, if the header is filled in (agency)
if len(df_times.loc[df_times["participant_type"].isin([ParticipantType.AGENCY.value])]) != 1: if len(df_times.loc[df_times["participant_type"].isin([ParticipantType.AGENCY.value])]) != 1:
return self.get_no_violation_default_output() return self.get_no_violation_default_output()
@ -840,7 +843,7 @@ class ValidationRuleFunctions(ValidationRuleBaseFunctions):
return (StatusFlags.RED, validation_name) return (StatusFlags.RED, validation_name)
else: else:
return self.get_no_violation_default_output() return self.get_no_violation_default_output()
def validation_rule_fct_too_many_identical_eta_times(self, shipcall, df_times, rounding = "min", maximum_threshold = 3, all_times_agency=None, *args, **kwargs): def validation_rule_fct_too_many_identical_eta_times(self, shipcall, df_times, rounding = "min", maximum_threshold = 3, all_times_agency=None, *args, **kwargs):
""" """
Code: #0005-A Code: #0005-A
@ -861,7 +864,7 @@ class ValidationRuleFunctions(ValidationRuleBaseFunctions):
return (StatusFlags.YELLOW, validation_name) return (StatusFlags.YELLOW, validation_name)
else: else:
return self.get_no_violation_default_output() return self.get_no_violation_default_output()
def validation_rule_fct_too_many_identical_etd_times(self, shipcall, df_times, rounding = "min", maximum_threshold = 3, all_times_agency=None, *args, **kwargs): def validation_rule_fct_too_many_identical_etd_times(self, shipcall, df_times, rounding = "min", maximum_threshold = 3, all_times_agency=None, *args, **kwargs):
""" """
Code: #0005-B Code: #0005-B
@ -882,7 +885,7 @@ class ValidationRuleFunctions(ValidationRuleBaseFunctions):
return (StatusFlags.YELLOW, validation_name) return (StatusFlags.YELLOW, validation_name)
else: else:
return self.get_no_violation_default_output() return self.get_no_violation_default_output()
def validation_rule_fct_agency_and_terminal_berth_id_disagreement(self, shipcall, df_times, *args, **kwargs): def validation_rule_fct_agency_and_terminal_berth_id_disagreement(self, shipcall, df_times, *args, **kwargs):
""" """
Code: #0006-A Code: #0006-A
@ -895,18 +898,18 @@ class ValidationRuleFunctions(ValidationRuleBaseFunctions):
if len(df_times.loc[df_times["participant_type"]==ParticipantType.TERMINAL.value]) == 0: if len(df_times.loc[df_times["participant_type"]==ParticipantType.TERMINAL.value]) == 0:
return self.get_no_violation_default_output() # rule not applicable return self.get_no_violation_default_output() # rule not applicable
times_agency = self.sql_handler.get_times_for_participant_type(df_times, participant_type=ParticipantType.AGENCY.value) times_agency = self.sql_handler.get_times_for_participant_type(df_times, participant_type=ParticipantType.AGENCY.value)
times_terminal = self.sql_handler.get_times_for_participant_type(df_times, participant_type=ParticipantType.TERMINAL.value) times_terminal = self.sql_handler.get_times_for_participant_type(df_times, participant_type=ParticipantType.TERMINAL.value)
# when one of the two values is null, the state is GREEN # when one of the two values is null, the state is GREEN
if (times_agency.berth_id is None) or (times_terminal.berth_id is None): if (times_agency.berth_id is None) or (times_terminal.berth_id is None):
return self.get_no_violation_default_output() return self.get_no_violation_default_output()
# when one of the two values is null, the state is GREEN # when one of the two values is null, the state is GREEN
if (pd.isnull(times_agency.berth_id)) or (pd.isnull(times_terminal.berth_id)): if (pd.isnull(times_agency.berth_id)) or (pd.isnull(times_terminal.berth_id)):
return self.get_no_violation_default_output() return self.get_no_violation_default_output()
if shipcall.type in [ShipcallType.OUTGOING.value, ShipcallType.SHIFTING.value]: if shipcall.type in [ShipcallType.OUTGOING.value, ShipcallType.SHIFTING.value]:
return self.get_no_violation_default_output() return self.get_no_violation_default_output()
@ -918,7 +921,7 @@ class ValidationRuleFunctions(ValidationRuleBaseFunctions):
return (StatusFlags.YELLOW, validation_name) return (StatusFlags.YELLOW, validation_name)
else: else:
return self.get_no_violation_default_output() return self.get_no_violation_default_output()
def validation_rule_fct_agency_and_terminal_pier_side_disagreement(self, shipcall, df_times, *args, **kwargs): def validation_rule_fct_agency_and_terminal_pier_side_disagreement(self, shipcall, df_times, *args, **kwargs):
""" """
Code: #0006-B Code: #0006-B
@ -931,18 +934,18 @@ class ValidationRuleFunctions(ValidationRuleBaseFunctions):
if len(df_times.loc[df_times["participant_type"]==ParticipantType.TERMINAL.value]) == 0: if len(df_times.loc[df_times["participant_type"]==ParticipantType.TERMINAL.value]) == 0:
return self.get_no_violation_default_output() # rule not applicable return self.get_no_violation_default_output() # rule not applicable
times_agency = self.sql_handler.get_times_for_participant_type(df_times, participant_type=ParticipantType.AGENCY.value) times_agency = self.sql_handler.get_times_for_participant_type(df_times, participant_type=ParticipantType.AGENCY.value)
times_terminal = self.sql_handler.get_times_for_participant_type(df_times, participant_type=ParticipantType.TERMINAL.value) times_terminal = self.sql_handler.get_times_for_participant_type(df_times, participant_type=ParticipantType.TERMINAL.value)
# when one of the two values is null, the state is GREEN # when one of the two values is null, the state is GREEN
if (shipcall.pier_side is None) or (times_terminal.pier_side is None): if (shipcall.pier_side is None) or (times_terminal.pier_side is None):
return self.get_no_violation_default_output() return self.get_no_violation_default_output()
# when one of the two values is null, the state is GREEN # when one of the two values is null, the state is GREEN
if (pd.isnull(shipcall.pier_side)) or (pd.isnull(times_terminal.pier_side)): if (pd.isnull(shipcall.pier_side)) or (pd.isnull(times_terminal.pier_side)):
return self.get_no_violation_default_output() return self.get_no_violation_default_output()
# only incoming shipcalls matter. The other ones are not relevant for the pier_side selection # only incoming shipcalls matter. The other ones are not relevant for the pier_side selection
if shipcall.type in [ShipcallType.OUTGOING.value, ShipcallType.SHIFTING.value]: if shipcall.type in [ShipcallType.OUTGOING.value, ShipcallType.SHIFTING.value]:
return self.get_no_violation_default_output() return self.get_no_violation_default_output()