Fixed time comparison validation func. Now compares min/max value of array.
This commit is contained in:
parent
c24bc981b0
commit
d8fabe0f97
@ -60,13 +60,13 @@ class ValidationRuleBaseFunctions():
|
||||
|
||||
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
|
||||
|
||||
returns: string
|
||||
"""
|
||||
return self.error_message_dict.get(key,key)
|
||||
|
||||
|
||||
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 (StatusFlags.GREEN, None)
|
||||
@ -75,7 +75,7 @@ class ValidationRuleBaseFunctions():
|
||||
"""
|
||||
# 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 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)
|
||||
if (key_time is not None) and (key_time is not pd.NaT):
|
||||
return False
|
||||
|
||||
|
||||
# when query_time is not valid, the rule cannot be applied
|
||||
if self.check_is_not_a_time_or_is_none(query_time):
|
||||
return False
|
||||
|
||||
|
||||
# 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")
|
||||
|
||||
@ -105,7 +105,7 @@ class ValidationRuleBaseFunctions():
|
||||
# Violation, if delta <= threshold
|
||||
violation_state = (delta<=threshold)
|
||||
return violation_state
|
||||
|
||||
|
||||
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
|
||||
@ -116,11 +116,11 @@ class ValidationRuleBaseFunctions():
|
||||
No violations are observed, when
|
||||
- the shipcall belongs to a different type than the rule expects
|
||||
- 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.
|
||||
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)
|
||||
"""
|
||||
@ -133,28 +133,31 @@ class ValidationRuleBaseFunctions():
|
||||
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]
|
||||
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),:]
|
||||
|
||||
# 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(),:]
|
||||
|
||||
# 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
|
||||
if len(estimated_times)==0:
|
||||
violation_state = False
|
||||
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
|
||||
# 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
|
||||
n_unique_times = len(np.unique(estimated_times))
|
||||
violation_state = n_unique_times!=1
|
||||
# n_unique_times = len(np.unique(estimated_times))
|
||||
# violation_state = n_unique_times!=1
|
||||
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:
|
||||
"""
|
||||
# base function for all validation rules in the group {0005} A&B
|
||||
@ -182,13 +185,13 @@ class 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
|
||||
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)
|
||||
|
||||
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
|
||||
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):
|
||||
super().__init__(sql_handler)
|
||||
return
|
||||
|
||||
return
|
||||
|
||||
def get_validation_rule_functions(self):
|
||||
"""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))]
|
||||
|
||||
|
||||
def validation_rule_fct_missing_time_agency_berth_eta(self, shipcall, df_times, *args, **kwargs):
|
||||
"""
|
||||
Code: #0001-A
|
||||
@ -213,17 +216,17 @@ class ValidationRuleFunctions(ValidationRuleBaseFunctions):
|
||||
a certain threshold (e.g., 20 hours), a violation occurs
|
||||
|
||||
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'.
|
||||
"""
|
||||
if not shipcall.type in [ShipcallType.INCOMING.value]:
|
||||
return self.get_no_violation_default_output()
|
||||
|
||||
|
||||
# check, if the header is filled in
|
||||
unassigned = self.sql_handler.check_if_any_participant_of_type_is_unassigned(shipcall, *[ParticipantType.AGENCY])
|
||||
if unassigned:
|
||||
return self.get_no_violation_default_output()
|
||||
|
||||
|
||||
# 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)
|
||||
query_time = shipcall.eta
|
||||
@ -236,7 +239,7 @@ class ValidationRuleFunctions(ValidationRuleBaseFunctions):
|
||||
return (StatusFlags.YELLOW, validation_name)
|
||||
else:
|
||||
return self.get_no_violation_default_output()
|
||||
|
||||
|
||||
def validation_rule_fct_missing_time_agency_berth_etd(self, shipcall, df_times, *args, **kwargs):
|
||||
"""
|
||||
Code: #0001-B
|
||||
@ -245,17 +248,17 @@ class ValidationRuleFunctions(ValidationRuleBaseFunctions):
|
||||
a certain threshold (e.g., 20 hours), a violation occurs
|
||||
|
||||
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'.
|
||||
"""
|
||||
if not shipcall.type in [ShipcallType.OUTGOING.value, ShipcallType.SHIFTING.value]:
|
||||
return self.get_no_violation_default_output()
|
||||
|
||||
|
||||
# check, if the header is filled in
|
||||
unassigned = self.sql_handler.check_if_any_participant_of_type_is_unassigned(shipcall, *[ParticipantType.AGENCY])
|
||||
if unassigned:
|
||||
return self.get_no_violation_default_output()
|
||||
|
||||
|
||||
# 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)
|
||||
query_time = shipcall.etd
|
||||
@ -268,7 +271,7 @@ class ValidationRuleFunctions(ValidationRuleBaseFunctions):
|
||||
return (StatusFlags.YELLOW, validation_name)
|
||||
else:
|
||||
return self.get_no_violation_default_output()
|
||||
|
||||
|
||||
def validation_rule_fct_missing_time_mooring_berth_eta(self, shipcall, df_times, *args, **kwargs):
|
||||
"""
|
||||
Code: #0001-C
|
||||
@ -277,12 +280,12 @@ class ValidationRuleFunctions(ValidationRuleBaseFunctions):
|
||||
a certain threshold (e.g., 20 hours), a violation occurs
|
||||
|
||||
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'.
|
||||
"""
|
||||
if not shipcall.type in [ShipcallType.INCOMING.value]:
|
||||
return self.get_no_violation_default_output()
|
||||
|
||||
|
||||
# check, if the header is filled in
|
||||
unassigned = self.sql_handler.check_if_any_participant_of_type_is_unassigned(shipcall, *[ParticipantType.AGENCY, ParticipantType.MOORING])
|
||||
if unassigned:
|
||||
@ -302,7 +305,7 @@ class ValidationRuleFunctions(ValidationRuleBaseFunctions):
|
||||
return (StatusFlags.YELLOW, validation_name)
|
||||
else:
|
||||
return self.get_no_violation_default_output()
|
||||
|
||||
|
||||
def validation_rule_fct_missing_time_mooring_berth_etd(self, shipcall, df_times, *args, **kwargs):
|
||||
"""
|
||||
Code: #0001-D
|
||||
@ -311,12 +314,12 @@ class ValidationRuleFunctions(ValidationRuleBaseFunctions):
|
||||
a certain threshold (e.g., 20 hours), a violation occurs
|
||||
|
||||
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'.
|
||||
"""
|
||||
if not shipcall.type in [ShipcallType.OUTGOING.value, ShipcallType.SHIFTING.value]:
|
||||
return self.get_no_violation_default_output()
|
||||
|
||||
|
||||
# check, if the header is filled in
|
||||
unassigned = self.sql_handler.check_if_any_participant_of_type_is_unassigned(shipcall, *[ParticipantType.AGENCY, ParticipantType.MOORING])
|
||||
if unassigned:
|
||||
@ -336,7 +339,7 @@ class ValidationRuleFunctions(ValidationRuleBaseFunctions):
|
||||
return (StatusFlags.YELLOW, validation_name)
|
||||
else:
|
||||
return self.get_no_violation_default_output()
|
||||
|
||||
|
||||
def validation_rule_fct_missing_time_portadministration_berth_eta(self, shipcall, df_times, *args, **kwargs):
|
||||
"""
|
||||
Code: #0001-F
|
||||
@ -345,20 +348,20 @@ class ValidationRuleFunctions(ValidationRuleBaseFunctions):
|
||||
a certain threshold (e.g., 20 hours), a violation occurs
|
||||
|
||||
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'.
|
||||
"""
|
||||
if self.ignore_port_administration_flag:
|
||||
return self.get_no_violation_default_output()
|
||||
|
||||
|
||||
if not shipcall.type in [ShipcallType.INCOMING.value]:
|
||||
return self.get_no_violation_default_output()
|
||||
|
||||
|
||||
# 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])
|
||||
if unassigned:
|
||||
return self.get_no_violation_default_output()
|
||||
|
||||
|
||||
# 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_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)
|
||||
else:
|
||||
return self.get_no_violation_default_output()
|
||||
|
||||
|
||||
def validation_rule_fct_missing_time_portadministration_berth_etd(self, shipcall, df_times, *args, **kwargs):
|
||||
"""
|
||||
Code: #0001-G
|
||||
@ -382,7 +385,7 @@ class ValidationRuleFunctions(ValidationRuleBaseFunctions):
|
||||
a certain threshold (e.g., 20 hours), a violation occurs
|
||||
|
||||
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'.
|
||||
"""
|
||||
if self.ignore_port_administration_flag:
|
||||
@ -390,12 +393,12 @@ class ValidationRuleFunctions(ValidationRuleBaseFunctions):
|
||||
|
||||
if not shipcall.type in [ShipcallType.OUTGOING.value, ShipcallType.SHIFTING.value]:
|
||||
return self.get_no_violation_default_output()
|
||||
|
||||
|
||||
# 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])
|
||||
if unassigned:
|
||||
return self.get_no_violation_default_output()
|
||||
|
||||
|
||||
# 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
|
||||
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)
|
||||
else:
|
||||
return self.get_no_violation_default_output()
|
||||
|
||||
|
||||
def validation_rule_fct_missing_time_pilot_berth_eta(self, shipcall, df_times, *args, **kwargs):
|
||||
"""
|
||||
Code: #0001-H
|
||||
@ -420,17 +423,17 @@ class ValidationRuleFunctions(ValidationRuleBaseFunctions):
|
||||
a certain threshold (e.g., 20 hours), a violation occurs
|
||||
|
||||
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'.
|
||||
"""
|
||||
if not shipcall.type in [ShipcallType.INCOMING.value]:
|
||||
return self.get_no_violation_default_output()
|
||||
|
||||
|
||||
# check, if the header is filled in
|
||||
unassigned = self.sql_handler.check_if_any_participant_of_type_is_unassigned(shipcall, *[ParticipantType.AGENCY, ParticipantType.PILOT])
|
||||
if unassigned:
|
||||
return self.get_no_violation_default_output()
|
||||
|
||||
|
||||
# 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_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
|
||||
threshold = ParticipantwiseTimeDelta.PILOT
|
||||
violation_state = self.check_time_delta_violation_query_time_to_now(query_time=query_time, key_time=key_time, threshold=threshold)
|
||||
|
||||
|
||||
if violation_state:
|
||||
validation_name = "validation_rule_fct_missing_time_pilot_berth_eta"
|
||||
return (StatusFlags.YELLOW, validation_name)
|
||||
else:
|
||||
return self.get_no_violation_default_output()
|
||||
|
||||
|
||||
def validation_rule_fct_missing_time_pilot_berth_etd(self, shipcall, df_times, *args, **kwargs):
|
||||
"""
|
||||
Code: #0001-I
|
||||
@ -454,17 +457,17 @@ class ValidationRuleFunctions(ValidationRuleBaseFunctions):
|
||||
a certain threshold (e.g., 20 hours), a violation occurs
|
||||
|
||||
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'.
|
||||
"""
|
||||
if not shipcall.type in [ShipcallType.OUTGOING.value, ShipcallType.SHIFTING.value]:
|
||||
return self.get_no_violation_default_output()
|
||||
|
||||
|
||||
# check, if the header is filled in
|
||||
unassigned = self.sql_handler.check_if_any_participant_of_type_is_unassigned(shipcall, *[ParticipantType.AGENCY, ParticipantType.PILOT])
|
||||
if unassigned:
|
||||
return self.get_no_violation_default_output()
|
||||
|
||||
|
||||
# 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_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
|
||||
threshold = ParticipantwiseTimeDelta.PILOT
|
||||
violation_state = self.check_time_delta_violation_query_time_to_now(query_time=query_time, key_time=key_time, threshold=threshold)
|
||||
|
||||
|
||||
if violation_state:
|
||||
validation_name = "validation_rule_fct_missing_time_pilot_berth_etd"
|
||||
return (StatusFlags.YELLOW, validation_name)
|
||||
else:
|
||||
return self.get_no_violation_default_output()
|
||||
|
||||
|
||||
def validation_rule_fct_missing_time_tug_berth_eta(self, shipcall, df_times, *args, **kwargs):
|
||||
"""
|
||||
Code: #0001-J
|
||||
@ -488,17 +491,17 @@ class ValidationRuleFunctions(ValidationRuleBaseFunctions):
|
||||
a certain threshold (e.g., 20 hours), a violation occurs
|
||||
|
||||
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'.
|
||||
"""
|
||||
if not shipcall.type in [ShipcallType.INCOMING.value]:
|
||||
return self.get_no_violation_default_output()
|
||||
|
||||
|
||||
# check, if the header is filled in
|
||||
unassigned = self.sql_handler.check_if_any_participant_of_type_is_unassigned(shipcall, *[ParticipantType.AGENCY, ParticipantType.TUG])
|
||||
if unassigned:
|
||||
return self.get_no_violation_default_output()
|
||||
|
||||
|
||||
# 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_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
|
||||
threshold = ParticipantwiseTimeDelta.TUG
|
||||
violation_state = self.check_time_delta_violation_query_time_to_now(query_time=query_time, key_time=key_time, threshold=threshold)
|
||||
|
||||
|
||||
if violation_state:
|
||||
validation_name = "validation_rule_fct_missing_time_tug_berth_eta"
|
||||
return (StatusFlags.YELLOW, validation_name)
|
||||
else:
|
||||
return self.get_no_violation_default_output()
|
||||
|
||||
|
||||
def validation_rule_fct_missing_time_tug_berth_etd(self, shipcall, df_times, *args, **kwargs):
|
||||
"""
|
||||
Code: #0001-K
|
||||
@ -522,17 +525,17 @@ class ValidationRuleFunctions(ValidationRuleBaseFunctions):
|
||||
a certain threshold (e.g., 20 hours), a violation occurs
|
||||
|
||||
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'.
|
||||
"""
|
||||
if not shipcall.type in [ShipcallType.OUTGOING.value, ShipcallType.SHIFTING.value]:
|
||||
return self.get_no_violation_default_output()
|
||||
|
||||
|
||||
# check, if the header is filled in
|
||||
unassigned = self.sql_handler.check_if_any_participant_of_type_is_unassigned(shipcall, *[ParticipantType.AGENCY, ParticipantType.TUG])
|
||||
if unassigned:
|
||||
return self.get_no_violation_default_output()
|
||||
|
||||
|
||||
# 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_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
|
||||
threshold = ParticipantwiseTimeDelta.TUG
|
||||
violation_state = self.check_time_delta_violation_query_time_to_now(query_time=query_time, key_time=key_time, threshold=threshold)
|
||||
|
||||
|
||||
if violation_state:
|
||||
validation_name = "validation_rule_fct_missing_time_tug_berth_etd"
|
||||
return (StatusFlags.YELLOW, validation_name)
|
||||
else:
|
||||
return self.get_no_violation_default_output()
|
||||
|
||||
|
||||
def validation_rule_fct_missing_time_terminal_berth_eta(self, shipcall, df_times, *args, **kwargs):
|
||||
"""
|
||||
Code: #0001-L
|
||||
@ -556,17 +559,17 @@ class ValidationRuleFunctions(ValidationRuleBaseFunctions):
|
||||
a certain threshold (e.g., 20 hours), a violation occurs
|
||||
|
||||
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'.
|
||||
"""
|
||||
if not shipcall.type in [ShipcallType.INCOMING.value]:
|
||||
return self.get_no_violation_default_output()
|
||||
|
||||
|
||||
# check, if the header is filled in
|
||||
unassigned = self.sql_handler.check_if_any_participant_of_type_is_unassigned(shipcall, *[ParticipantType.AGENCY, ParticipantType.TERMINAL])
|
||||
if unassigned:
|
||||
return self.get_no_violation_default_output()
|
||||
|
||||
|
||||
# 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_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
|
||||
threshold = ParticipantwiseTimeDelta.TERMINAL
|
||||
violation_state = self.check_time_delta_violation_query_time_to_now(query_time=query_time, key_time=key_time, threshold=threshold)
|
||||
|
||||
|
||||
if violation_state:
|
||||
validation_name = "validation_rule_fct_missing_time_terminal_berth_eta"
|
||||
return (StatusFlags.YELLOW, validation_name)
|
||||
else:
|
||||
return self.get_no_violation_default_output()
|
||||
|
||||
|
||||
def validation_rule_fct_missing_time_terminal_berth_etd(self, shipcall, df_times, *args, **kwargs):
|
||||
"""
|
||||
Code: #0001-M
|
||||
@ -590,17 +593,17 @@ class ValidationRuleFunctions(ValidationRuleBaseFunctions):
|
||||
a certain threshold (e.g., 20 hours), a violation occurs
|
||||
|
||||
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'.
|
||||
"""
|
||||
if not shipcall.type in [ShipcallType.OUTGOING.value, ShipcallType.SHIFTING.value]:
|
||||
return self.get_no_violation_default_output()
|
||||
|
||||
|
||||
# check, if the header is filled in
|
||||
unassigned = self.sql_handler.check_if_any_participant_of_type_is_unassigned(shipcall, *[ParticipantType.AGENCY, ParticipantType.TERMINAL])
|
||||
if unassigned:
|
||||
return self.get_no_violation_default_output()
|
||||
|
||||
|
||||
# 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_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
|
||||
threshold = ParticipantwiseTimeDelta.TERMINAL
|
||||
violation_state = self.check_time_delta_violation_query_time_to_now(query_time=query_time, key_time=key_time, threshold=threshold)
|
||||
|
||||
|
||||
if violation_state:
|
||||
validation_name = "validation_rule_fct_missing_time_terminal_berth_etd"
|
||||
return (StatusFlags.YELLOW, validation_name)
|
||||
else:
|
||||
return self.get_no_violation_default_output()
|
||||
|
||||
|
||||
def validation_rule_fct_shipcall_incoming_participants_disagree_on_eta(self, shipcall, df_times, *args, **kwargs):
|
||||
"""
|
||||
Code: #0002-A
|
||||
@ -624,21 +627,21 @@ class ValidationRuleFunctions(ValidationRuleBaseFunctions):
|
||||
Filter: only applies to incoming shipcalls
|
||||
"""
|
||||
query = "eta_berth"
|
||||
|
||||
violation_state = self.check_participants_agree_on_estimated_time(
|
||||
shipcall = shipcall,
|
||||
|
||||
query=query,
|
||||
df_times=df_times,
|
||||
violation_state = self.check_participants_agree_on_estimated_time(
|
||||
shipcall = shipcall,
|
||||
|
||||
query=query,
|
||||
df_times=df_times,
|
||||
applicable_shipcall_type=ShipcallType.INCOMING
|
||||
)
|
||||
|
||||
|
||||
if violation_state:
|
||||
validation_name = "validation_rule_fct_shipcall_incoming_participants_disagree_on_eta"
|
||||
return (StatusFlags.RED, validation_name)
|
||||
else:
|
||||
return self.get_no_violation_default_output()
|
||||
|
||||
|
||||
def validation_rule_fct_shipcall_outgoing_participants_disagree_on_etd(self, shipcall, df_times, *args, **kwargs):
|
||||
"""
|
||||
Code: #0002-B
|
||||
@ -647,12 +650,12 @@ class ValidationRuleFunctions(ValidationRuleBaseFunctions):
|
||||
Filter: only applies to outgoing shipcalls
|
||||
"""
|
||||
query = "etd_berth"
|
||||
|
||||
violation_state = self.check_participants_agree_on_estimated_time(
|
||||
shipcall = shipcall,
|
||||
|
||||
query=query,
|
||||
df_times=df_times,
|
||||
violation_state = self.check_participants_agree_on_estimated_time(
|
||||
shipcall = shipcall,
|
||||
|
||||
query=query,
|
||||
df_times=df_times,
|
||||
applicable_shipcall_type=ShipcallType.OUTGOING
|
||||
)
|
||||
|
||||
@ -661,7 +664,7 @@ class ValidationRuleFunctions(ValidationRuleBaseFunctions):
|
||||
return (StatusFlags.RED, validation_name)
|
||||
else:
|
||||
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):
|
||||
"""
|
||||
Code: #0002-C
|
||||
@ -670,21 +673,21 @@ class ValidationRuleFunctions(ValidationRuleBaseFunctions):
|
||||
Filter: only applies to shifting shipcalls
|
||||
"""
|
||||
violation_state_eta = self.check_participants_agree_on_estimated_time(
|
||||
shipcall = shipcall,
|
||||
shipcall = shipcall,
|
||||
|
||||
query="eta_berth",
|
||||
df_times=df_times,
|
||||
query="eta_berth",
|
||||
df_times=df_times,
|
||||
applicable_shipcall_type=ShipcallType.SHIFTING
|
||||
)
|
||||
|
||||
|
||||
violation_state_etd = self.check_participants_agree_on_estimated_time(
|
||||
shipcall = shipcall,
|
||||
shipcall = shipcall,
|
||||
|
||||
query="etd_berth",
|
||||
df_times=df_times,
|
||||
query="etd_berth",
|
||||
df_times=df_times,
|
||||
applicable_shipcall_type=ShipcallType.SHIFTING
|
||||
)
|
||||
|
||||
|
||||
# apply 'eta_berth' check
|
||||
# apply 'etd_berth'
|
||||
# violation: if either 'eta_berth' or 'etd_berth' is violated
|
||||
@ -698,7 +701,7 @@ class ValidationRuleFunctions(ValidationRuleBaseFunctions):
|
||||
return (StatusFlags.RED, validation_name)
|
||||
else:
|
||||
return self.get_no_violation_default_output()
|
||||
|
||||
|
||||
def validation_rule_fct_eta_time_not_in_operation_window(self, shipcall, df_times, *args, **kwargs):
|
||||
"""
|
||||
Code: #0003-A
|
||||
@ -710,14 +713,14 @@ class ValidationRuleFunctions(ValidationRuleBaseFunctions):
|
||||
"""
|
||||
if not shipcall.type in [ShipcallType.INCOMING.value]:
|
||||
return self.get_no_violation_default_output()
|
||||
|
||||
|
||||
# check, if the header is filled in (agency & terminal)
|
||||
if len(df_times.loc[df_times["participant_type"]==ParticipantType.AGENCY.value]) != 1:
|
||||
return self.get_no_violation_default_output() # rule not applicable
|
||||
|
||||
if len(df_times.loc[df_times["participant_type"]==ParticipantType.TERMINAL.value]) != 1:
|
||||
return self.get_no_violation_default_output() # rule not applicable
|
||||
|
||||
|
||||
# get agency & terminal times
|
||||
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)
|
||||
@ -738,7 +741,7 @@ class ValidationRuleFunctions(ValidationRuleBaseFunctions):
|
||||
return (StatusFlags.RED, validation_name)
|
||||
else:
|
||||
return self.get_no_violation_default_output()
|
||||
|
||||
|
||||
def validation_rule_fct_etd_time_not_in_operation_window(self, shipcall, df_times, *args, **kwargs):
|
||||
"""
|
||||
Code: #0003-B
|
||||
@ -750,14 +753,14 @@ class ValidationRuleFunctions(ValidationRuleBaseFunctions):
|
||||
"""
|
||||
if not shipcall.type in [ShipcallType.OUTGOING.value, ShipcallType.SHIFTING.value]:
|
||||
return self.get_no_violation_default_output()
|
||||
|
||||
|
||||
# check, if the header is filled in (agency & terminal)
|
||||
if len(df_times.loc[df_times["participant_type"]==ParticipantType.AGENCY.value]) != 1:
|
||||
return self.get_no_violation_default_output() # rule not applicable
|
||||
|
||||
if len(df_times.loc[df_times["participant_type"]==ParticipantType.TERMINAL.value]) != 1:
|
||||
return self.get_no_violation_default_output() # rule not applicable
|
||||
|
||||
|
||||
# get agency & terminal times
|
||||
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)
|
||||
@ -778,7 +781,7 @@ class ValidationRuleFunctions(ValidationRuleBaseFunctions):
|
||||
return (StatusFlags.RED, validation_name)
|
||||
else:
|
||||
return self.get_no_violation_default_output()
|
||||
|
||||
|
||||
def validation_rule_fct_eta_time_not_in_tidal_window(self, shipcall, df_times, *args, **kwargs):
|
||||
"""
|
||||
Code: #0004-A
|
||||
@ -790,7 +793,7 @@ class ValidationRuleFunctions(ValidationRuleBaseFunctions):
|
||||
"""
|
||||
if not shipcall.type in [ShipcallType.INCOMING.value]:
|
||||
return self.get_no_violation_default_output()
|
||||
|
||||
|
||||
# check, if the header is filled in (agency)
|
||||
if len(df_times.loc[df_times["participant_type"].isin([ParticipantType.AGENCY.value])]) != 1:
|
||||
return self.get_no_violation_default_output()
|
||||
@ -809,7 +812,7 @@ class ValidationRuleFunctions(ValidationRuleBaseFunctions):
|
||||
return (StatusFlags.RED, validation_name)
|
||||
else:
|
||||
return self.get_no_violation_default_output()
|
||||
|
||||
|
||||
def validation_rule_fct_etd_time_not_in_tidal_window(self, shipcall, df_times, *args, **kwargs):
|
||||
"""
|
||||
Code: #0004-B
|
||||
@ -821,7 +824,7 @@ class ValidationRuleFunctions(ValidationRuleBaseFunctions):
|
||||
"""
|
||||
if not shipcall.type in [ShipcallType.OUTGOING.value, ShipcallType.SHIFTING.value]:
|
||||
return self.get_no_violation_default_output()
|
||||
|
||||
|
||||
# check, if the header is filled in (agency)
|
||||
if len(df_times.loc[df_times["participant_type"].isin([ParticipantType.AGENCY.value])]) != 1:
|
||||
return self.get_no_violation_default_output()
|
||||
@ -840,7 +843,7 @@ class ValidationRuleFunctions(ValidationRuleBaseFunctions):
|
||||
return (StatusFlags.RED, validation_name)
|
||||
else:
|
||||
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):
|
||||
"""
|
||||
Code: #0005-A
|
||||
@ -861,7 +864,7 @@ class ValidationRuleFunctions(ValidationRuleBaseFunctions):
|
||||
return (StatusFlags.YELLOW, validation_name)
|
||||
else:
|
||||
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):
|
||||
"""
|
||||
Code: #0005-B
|
||||
@ -882,7 +885,7 @@ class ValidationRuleFunctions(ValidationRuleBaseFunctions):
|
||||
return (StatusFlags.YELLOW, validation_name)
|
||||
else:
|
||||
return self.get_no_violation_default_output()
|
||||
|
||||
|
||||
def validation_rule_fct_agency_and_terminal_berth_id_disagreement(self, shipcall, df_times, *args, **kwargs):
|
||||
"""
|
||||
Code: #0006-A
|
||||
@ -895,18 +898,18 @@ class ValidationRuleFunctions(ValidationRuleBaseFunctions):
|
||||
|
||||
if len(df_times.loc[df_times["participant_type"]==ParticipantType.TERMINAL.value]) == 0:
|
||||
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_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
|
||||
if (times_agency.berth_id is None) or (times_terminal.berth_id is None):
|
||||
return self.get_no_violation_default_output()
|
||||
|
||||
|
||||
# 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)):
|
||||
return self.get_no_violation_default_output()
|
||||
|
||||
|
||||
if shipcall.type in [ShipcallType.OUTGOING.value, ShipcallType.SHIFTING.value]:
|
||||
return self.get_no_violation_default_output()
|
||||
|
||||
@ -918,7 +921,7 @@ class ValidationRuleFunctions(ValidationRuleBaseFunctions):
|
||||
return (StatusFlags.YELLOW, validation_name)
|
||||
else:
|
||||
return self.get_no_violation_default_output()
|
||||
|
||||
|
||||
def validation_rule_fct_agency_and_terminal_pier_side_disagreement(self, shipcall, df_times, *args, **kwargs):
|
||||
"""
|
||||
Code: #0006-B
|
||||
@ -931,18 +934,18 @@ class ValidationRuleFunctions(ValidationRuleBaseFunctions):
|
||||
|
||||
if len(df_times.loc[df_times["participant_type"]==ParticipantType.TERMINAL.value]) == 0:
|
||||
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_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
|
||||
if (shipcall.pier_side is None) or (times_terminal.pier_side is None):
|
||||
return self.get_no_violation_default_output()
|
||||
|
||||
|
||||
# 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)):
|
||||
return self.get_no_violation_default_output()
|
||||
|
||||
|
||||
# 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]:
|
||||
return self.get_no_violation_default_output()
|
||||
|
||||
Reference in New Issue
Block a user