diff --git a/misc/BreCalApi.cs b/misc/BreCalApi.cs
index 8fb6f78..c816626 100644
--- a/misc/BreCalApi.cs
+++ b/misc/BreCalApi.cs
@@ -1,7 +1,7 @@
//----------------------
//
-// Generated REST API Client Code Generator v1.8.4.0 on 21.09.2023 07:07:32
+// Generated REST API Client Code Generator v1.8.4.0 on 23.10.2023 09:06:40
// Using the tool OpenAPI Generator v7.0.0
//
//----------------------
@@ -52,6 +52,7 @@ using System.Threading.Tasks;
namespace BreCalClient.misc.Api
{
#pragma warning disable CS8073 // The result of the expression is always the same since a value of this type is never equal to 'null'
+
///
/// Represents a collection of functions to interact with the API endpoints
///
@@ -69,7 +70,7 @@ namespace BreCalClient.misc.Api
/// Gets a list of all berths registered
///
///
- ///
+ ///
///
/// Thrown when fails to make API call
/// Index associated with the operation.
@@ -87,7 +88,7 @@ namespace BreCalClient.misc.Api
/// Returns a JWT session token and user data if successful
///
///
- ///
+ ///
///
/// Thrown when fails to make API call
/// Login credentials
@@ -107,7 +108,7 @@ namespace BreCalClient.misc.Api
/// Gets a list of notifications pursuant to a specified participant and ship call
///
///
- ///
+ ///
///
/// Thrown when fails to make API call
/// **Id of participant**. *Example: 2*. Id returned through loading of participant
@@ -127,7 +128,7 @@ namespace BreCalClient.misc.Api
/// gets a particular participant entry corresponding to user id
///
///
- ///
+ ///
///
/// Thrown when fails to make API call
/// **Id of user**. *Example: 2*. User id returned by verify call. (optional)
@@ -138,57 +139,59 @@ namespace BreCalClient.misc.Api
/// Gets a list of ship calls
///
/// Thrown when fails to make API call
+ /// number of days in the past to include in the result. *Example: 7*. (optional)
/// Index associated with the operation.
/// List<Shipcall>
- List ShipcallsGet(int operationIndex = 0);
+ List ShipcallsGet(int? pastDays = default(int?), int operationIndex = 0);
///
/// Gets a list of ship calls
///
///
- ///
+ ///
///
/// Thrown when fails to make API call
+ /// number of days in the past to include in the result. *Example: 7*. (optional)
/// Index associated with the operation.
/// ApiResponse of List<Shipcall>
- ApiResponse> ShipcallsGetWithHttpInfo(int operationIndex = 0);
+ ApiResponse> ShipcallsGetWithHttpInfo(int? pastDays = default(int?), int operationIndex = 0);
///
/// Create a new ship call
///
/// Thrown when fails to make API call
/// Creates a new ship call. **Do not** provide id parameter.
/// Index associated with the operation.
- ///
- void ShipcallsPost(Shipcall shipcall, int operationIndex = 0);
+ /// Id
+ Id ShipcallsPost(Shipcall shipcall, int operationIndex = 0);
///
/// Create a new ship call
///
///
- ///
+ ///
///
/// Thrown when fails to make API call
/// Creates a new ship call. **Do not** provide id parameter.
/// Index associated with the operation.
- /// ApiResponse of Object(void)
- ApiResponse ShipcallsPostWithHttpInfo(Shipcall shipcall, int operationIndex = 0);
+ /// ApiResponse of Id
+ ApiResponse ShipcallsPostWithHttpInfo(Shipcall shipcall, int operationIndex = 0);
///
/// Updates a ship call
///
/// Thrown when fails to make API call
/// Creates a new ship call. The id parameter is **required**.
/// Index associated with the operation.
- ///
- void ShipcallsPut(Shipcall shipcall, int operationIndex = 0);
+ /// Id
+ Id ShipcallsPut(Shipcall shipcall, int operationIndex = 0);
///
/// Updates a ship call
///
///
- ///
+ ///
///
/// Thrown when fails to make API call
/// Creates a new ship call. The id parameter is **required**.
/// Index associated with the operation.
- /// ApiResponse of Object(void)
- ApiResponse ShipcallsPutWithHttpInfo(Shipcall shipcall, int operationIndex = 0);
+ /// ApiResponse of Id
+ ApiResponse ShipcallsPutWithHttpInfo(Shipcall shipcall, int operationIndex = 0);
///
/// gets a list of registered shipcalls
///
@@ -200,7 +203,7 @@ namespace BreCalClient.misc.Api
/// gets a list of registered shipcalls
///
///
- ///
+ ///
///
/// Thrown when fails to make API call
/// Index associated with the operation.
@@ -218,7 +221,7 @@ namespace BreCalClient.misc.Api
/// Delete a times entry for a ship call.
///
///
- ///
+ ///
///
/// Thrown when fails to make API call
///
@@ -237,7 +240,7 @@ namespace BreCalClient.misc.Api
/// Get all recorded times for a a ship call
///
///
- ///
+ ///
///
/// Thrown when fails to make API call
/// **Id**. *Example: 42*. Id of referenced ship call. (optional)
@@ -250,38 +253,38 @@ namespace BreCalClient.misc.Api
/// Thrown when fails to make API call
/// Times entry that will be added to the ship call. **Do not** provide id parameter.
/// Index associated with the operation.
- ///
- void TimesPost(Times times, int operationIndex = 0);
+ /// Id
+ Id TimesPost(Times times, int operationIndex = 0);
///
/// Create a new times entry for a ship call
///
///
- ///
+ ///
///
/// Thrown when fails to make API call
/// Times entry that will be added to the ship call. **Do not** provide id parameter.
/// Index associated with the operation.
- /// ApiResponse of Object(void)
- ApiResponse TimesPostWithHttpInfo(Times times, int operationIndex = 0);
+ /// ApiResponse of Id
+ ApiResponse TimesPostWithHttpInfo(Times times, int operationIndex = 0);
///
/// Update a times entry for a ship call
///
/// Thrown when fails to make API call
/// Times entry that will be added to the ship call. The id parameter is **required**.
/// Index associated with the operation.
- ///
- void TimesPut(Times times, int operationIndex = 0);
+ /// Id
+ Id TimesPut(Times times, int operationIndex = 0);
///
/// Update a times entry for a ship call
///
///
- ///
+ ///
///
/// Thrown when fails to make API call
/// Times entry that will be added to the ship call. The id parameter is **required**.
/// Index associated with the operation.
- /// ApiResponse of Object(void)
- ApiResponse TimesPutWithHttpInfo(Times times, int operationIndex = 0);
+ /// ApiResponse of Id
+ ApiResponse TimesPutWithHttpInfo(Times times, int operationIndex = 0);
///
/// Update user details (first/last name, phone, password)
///
@@ -294,7 +297,7 @@ namespace BreCalClient.misc.Api
/// Update user details (first/last name, phone, password)
///
///
- ///
+ ///
///
/// Thrown when fails to make API call
/// User details
@@ -313,7 +316,7 @@ namespace BreCalClient.misc.Api
/// Gets a list of all berths registered
///
///
- ///
+ ///
///
/// Thrown when fails to make API call
/// Index associated with the operation.
@@ -324,7 +327,7 @@ namespace BreCalClient.misc.Api
/// Gets a list of all berths registered
///
///
- ///
+ ///
///
/// Thrown when fails to make API call
/// Index associated with the operation.
@@ -335,7 +338,7 @@ namespace BreCalClient.misc.Api
/// Returns a JWT session token and user data if successful
///
///
- ///
+ ///
///
/// Thrown when fails to make API call
/// Login credentials
@@ -347,7 +350,7 @@ namespace BreCalClient.misc.Api
/// Returns a JWT session token and user data if successful
///
///
- ///
+ ///
///
/// Thrown when fails to make API call
/// Login credentials
@@ -359,7 +362,7 @@ namespace BreCalClient.misc.Api
/// Gets a list of notifications pursuant to a specified participant and ship call
///
///
- ///
+ ///
///
/// Thrown when fails to make API call
/// **Id of participant**. *Example: 2*. Id returned through loading of participant
@@ -372,7 +375,7 @@ namespace BreCalClient.misc.Api
/// Gets a list of notifications pursuant to a specified participant and ship call
///
///
- ///
+ ///
///
/// Thrown when fails to make API call
/// **Id of participant**. *Example: 2*. Id returned through loading of participant
@@ -385,7 +388,7 @@ namespace BreCalClient.misc.Api
/// gets a particular participant entry corresponding to user id
///
///
- ///
+ ///
///
/// Thrown when fails to make API call
/// **Id of user**. *Example: 2*. User id returned by verify call. (optional)
@@ -397,7 +400,7 @@ namespace BreCalClient.misc.Api
/// gets a particular participant entry corresponding to user id
///
///
- ///
+ ///
///
/// Thrown when fails to make API call
/// **Id of user**. *Example: 2*. User id returned by verify call. (optional)
@@ -409,77 +412,79 @@ namespace BreCalClient.misc.Api
/// Gets a list of ship calls
///
///
- ///
+ ///
///
/// Thrown when fails to make API call
+ /// number of days in the past to include in the result. *Example: 7*. (optional)
/// Index associated with the operation.
/// Cancellation Token to cancel the request.
/// Task of List<Shipcall>
- System.Threading.Tasks.Task> ShipcallsGetAsync(int operationIndex = 0, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken));
+ System.Threading.Tasks.Task> ShipcallsGetAsync(int? pastDays = default(int?), int operationIndex = 0, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken));
///
/// Gets a list of ship calls
///
///
- ///
+ ///
///
/// Thrown when fails to make API call
+ /// number of days in the past to include in the result. *Example: 7*. (optional)
/// Index associated with the operation.
/// Cancellation Token to cancel the request.
/// Task of ApiResponse (List<Shipcall>)
- System.Threading.Tasks.Task>> ShipcallsGetWithHttpInfoAsync(int operationIndex = 0, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken));
+ System.Threading.Tasks.Task>> ShipcallsGetWithHttpInfoAsync(int? pastDays = default(int?), int operationIndex = 0, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken));
///
/// Create a new ship call
///
///
- ///
+ ///
///
/// Thrown when fails to make API call
/// Creates a new ship call. **Do not** provide id parameter.
/// Index associated with the operation.
/// Cancellation Token to cancel the request.
- /// Task of void
- System.Threading.Tasks.Task ShipcallsPostAsync(Shipcall shipcall, int operationIndex = 0, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken));
+ /// Task of Id
+ System.Threading.Tasks.Task ShipcallsPostAsync(Shipcall shipcall, int operationIndex = 0, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken));
///
/// Create a new ship call
///
///
- ///
+ ///
///
/// Thrown when fails to make API call
/// Creates a new ship call. **Do not** provide id parameter.
/// Index associated with the operation.
/// Cancellation Token to cancel the request.
- /// Task of ApiResponse
- System.Threading.Tasks.Task> ShipcallsPostWithHttpInfoAsync(Shipcall shipcall, int operationIndex = 0, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken));
+ /// Task of ApiResponse (Id)
+ System.Threading.Tasks.Task> ShipcallsPostWithHttpInfoAsync(Shipcall shipcall, int operationIndex = 0, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken));
///
/// Updates a ship call
///
///
- ///
+ ///
///
/// Thrown when fails to make API call
/// Creates a new ship call. The id parameter is **required**.
/// Index associated with the operation.
/// Cancellation Token to cancel the request.
- /// Task of void
- System.Threading.Tasks.Task ShipcallsPutAsync(Shipcall shipcall, int operationIndex = 0, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken));
+ /// Task of Id
+ System.Threading.Tasks.Task ShipcallsPutAsync(Shipcall shipcall, int operationIndex = 0, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken));
///
/// Updates a ship call
///
///
- ///
+ ///
///
/// Thrown when fails to make API call
/// Creates a new ship call. The id parameter is **required**.
/// Index associated with the operation.
/// Cancellation Token to cancel the request.
- /// Task of ApiResponse
- System.Threading.Tasks.Task> ShipcallsPutWithHttpInfoAsync(Shipcall shipcall, int operationIndex = 0, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken));
+ /// Task of ApiResponse (Id)
+ System.Threading.Tasks.Task> ShipcallsPutWithHttpInfoAsync(Shipcall shipcall, int operationIndex = 0, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken));
///
/// gets a list of registered shipcalls
///
///
- ///
+ ///
///
/// Thrown when fails to make API call
/// Index associated with the operation.
@@ -490,7 +495,7 @@ namespace BreCalClient.misc.Api
/// gets a list of registered shipcalls
///
///
- ///
+ ///
///
/// Thrown when fails to make API call
/// Index associated with the operation.
@@ -501,7 +506,7 @@ namespace BreCalClient.misc.Api
/// Delete a times entry for a ship call.
///
///
- ///
+ ///
///
/// Thrown when fails to make API call
///
@@ -513,7 +518,7 @@ namespace BreCalClient.misc.Api
/// Delete a times entry for a ship call.
///
///
- ///
+ ///
///
/// Thrown when fails to make API call
///
@@ -525,7 +530,7 @@ namespace BreCalClient.misc.Api
/// Get all recorded times for a a ship call
///
///
- ///
+ ///
///
/// Thrown when fails to make API call
/// **Id**. *Example: 42*. Id of referenced ship call. (optional)
@@ -537,7 +542,7 @@ namespace BreCalClient.misc.Api
/// Get all recorded times for a a ship call
///
///
- ///
+ ///
///
/// Thrown when fails to make API call
/// **Id**. *Example: 42*. Id of referenced ship call. (optional)
@@ -549,55 +554,55 @@ namespace BreCalClient.misc.Api
/// Create a new times entry for a ship call
///
///
- ///
+ ///
///
/// Thrown when fails to make API call
/// Times entry that will be added to the ship call. **Do not** provide id parameter.
/// Index associated with the operation.
/// Cancellation Token to cancel the request.
- /// Task of void
- System.Threading.Tasks.Task TimesPostAsync(Times times, int operationIndex = 0, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken));
+ /// Task of Id
+ System.Threading.Tasks.Task TimesPostAsync(Times times, int operationIndex = 0, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken));
///
/// Create a new times entry for a ship call
///
///
- ///
+ ///
///
/// Thrown when fails to make API call
/// Times entry that will be added to the ship call. **Do not** provide id parameter.
/// Index associated with the operation.
/// Cancellation Token to cancel the request.
- /// Task of ApiResponse
- System.Threading.Tasks.Task> TimesPostWithHttpInfoAsync(Times times, int operationIndex = 0, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken));
+ /// Task of ApiResponse (Id)
+ System.Threading.Tasks.Task> TimesPostWithHttpInfoAsync(Times times, int operationIndex = 0, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken));
///
/// Update a times entry for a ship call
///
///
- ///
+ ///
///
/// Thrown when fails to make API call
/// Times entry that will be added to the ship call. The id parameter is **required**.
/// Index associated with the operation.
/// Cancellation Token to cancel the request.
- /// Task of void
- System.Threading.Tasks.Task TimesPutAsync(Times times, int operationIndex = 0, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken));
+ /// Task of Id
+ System.Threading.Tasks.Task TimesPutAsync(Times times, int operationIndex = 0, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken));
///
/// Update a times entry for a ship call
///
///
- ///
+ ///
///
/// Thrown when fails to make API call
/// Times entry that will be added to the ship call. The id parameter is **required**.
/// Index associated with the operation.
/// Cancellation Token to cancel the request.
- /// Task of ApiResponse
- System.Threading.Tasks.Task> TimesPutWithHttpInfoAsync(Times times, int operationIndex = 0, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken));
+ /// Task of ApiResponse (Id)
+ System.Threading.Tasks.Task> TimesPutWithHttpInfoAsync(Times times, int operationIndex = 0, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken));
///
/// Update user details (first/last name, phone, password)
///
///
- ///
+ ///
///
/// Thrown when fails to make API call
/// User details
@@ -609,7 +614,7 @@ namespace BreCalClient.misc.Api
/// Update user details (first/last name, phone, password)
///
///
- ///
+ ///
///
/// Thrown when fails to make API call
/// User details
@@ -723,7 +728,7 @@ namespace BreCalClient.misc.Api
set { _exceptionFactory = value; }
}
///
- /// Gets a list of all berths registered
+ /// Gets a list of all berths registered
///
/// Thrown when fails to make API call
/// Index associated with the operation.
@@ -734,7 +739,7 @@ namespace BreCalClient.misc.Api
return localVarResponse.Data;
}
///
- /// Gets a list of all berths registered
+ /// Gets a list of all berths registered
///
/// Thrown when fails to make API call
/// Index associated with the operation.
@@ -778,7 +783,7 @@ namespace BreCalClient.misc.Api
return localVarResponse;
}
///
- /// Gets a list of all berths registered
+ /// Gets a list of all berths registered
///
/// Thrown when fails to make API call
/// Index associated with the operation.
@@ -790,7 +795,7 @@ namespace BreCalClient.misc.Api
return localVarResponse.Data;
}
///
- /// Gets a list of all berths registered
+ /// Gets a list of all berths registered
///
/// Thrown when fails to make API call
/// Index associated with the operation.
@@ -835,7 +840,7 @@ namespace BreCalClient.misc.Api
return localVarResponse;
}
///
- /// Returns a JWT session token and user data if successful
+ /// Returns a JWT session token and user data if successful
///
/// Thrown when fails to make API call
/// Login credentials
@@ -847,7 +852,7 @@ namespace BreCalClient.misc.Api
return localVarResponse.Data;
}
///
- /// Returns a JWT session token and user data if successful
+ /// Returns a JWT session token and user data if successful
///
/// Thrown when fails to make API call
/// Login credentials
@@ -899,7 +904,7 @@ namespace BreCalClient.misc.Api
return localVarResponse;
}
///
- /// Returns a JWT session token and user data if successful
+ /// Returns a JWT session token and user data if successful
///
/// Thrown when fails to make API call
/// Login credentials
@@ -912,7 +917,7 @@ namespace BreCalClient.misc.Api
return localVarResponse.Data;
}
///
- /// Returns a JWT session token and user data if successful
+ /// Returns a JWT session token and user data if successful
///
/// Thrown when fails to make API call
/// Login credentials
@@ -965,7 +970,7 @@ namespace BreCalClient.misc.Api
return localVarResponse;
}
///
- /// Gets a list of notifications pursuant to a specified participant and ship call
+ /// Gets a list of notifications pursuant to a specified participant and ship call
///
/// Thrown when fails to make API call
/// **Id of participant**. *Example: 2*. Id returned through loading of participant
@@ -978,7 +983,7 @@ namespace BreCalClient.misc.Api
return localVarResponse.Data;
}
///
- /// Gets a list of notifications pursuant to a specified participant and ship call
+ /// Gets a list of notifications pursuant to a specified participant and ship call
///
/// Thrown when fails to make API call
/// **Id of participant**. *Example: 2*. Id returned through loading of participant
@@ -1026,7 +1031,7 @@ namespace BreCalClient.misc.Api
return localVarResponse;
}
///
- /// Gets a list of notifications pursuant to a specified participant and ship call
+ /// Gets a list of notifications pursuant to a specified participant and ship call
///
/// Thrown when fails to make API call
/// **Id of participant**. *Example: 2*. Id returned through loading of participant
@@ -1040,7 +1045,7 @@ namespace BreCalClient.misc.Api
return localVarResponse.Data;
}
///
- /// Gets a list of notifications pursuant to a specified participant and ship call
+ /// Gets a list of notifications pursuant to a specified participant and ship call
///
/// Thrown when fails to make API call
/// **Id of participant**. *Example: 2*. Id returned through loading of participant
@@ -1089,7 +1094,7 @@ namespace BreCalClient.misc.Api
return localVarResponse;
}
///
- /// gets a particular participant entry corresponding to user id
+ /// gets a particular participant entry corresponding to user id
///
/// Thrown when fails to make API call
/// **Id of user**. *Example: 2*. User id returned by verify call. (optional)
@@ -1101,7 +1106,7 @@ namespace BreCalClient.misc.Api
return localVarResponse.Data;
}
///
- /// gets a particular participant entry corresponding to user id
+ /// gets a particular participant entry corresponding to user id
///
/// Thrown when fails to make API call
/// **Id of user**. *Example: 2*. User id returned by verify call. (optional)
@@ -1150,7 +1155,7 @@ namespace BreCalClient.misc.Api
return localVarResponse;
}
///
- /// gets a particular participant entry corresponding to user id
+ /// gets a particular participant entry corresponding to user id
///
/// Thrown when fails to make API call
/// **Id of user**. *Example: 2*. User id returned by verify call. (optional)
@@ -1163,7 +1168,7 @@ namespace BreCalClient.misc.Api
return localVarResponse.Data;
}
///
- /// gets a particular participant entry corresponding to user id
+ /// gets a particular participant entry corresponding to user id
///
/// Thrown when fails to make API call
/// **Id of user**. *Example: 2*. User id returned by verify call. (optional)
@@ -1213,23 +1218,25 @@ namespace BreCalClient.misc.Api
return localVarResponse;
}
///
- /// Gets a list of ship calls
+ /// Gets a list of ship calls
///
/// Thrown when fails to make API call
+ /// number of days in the past to include in the result. *Example: 7*. (optional)
/// Index associated with the operation.
/// List<Shipcall>
- public List ShipcallsGet(int operationIndex = 0)
+ public List ShipcallsGet(int? pastDays = default(int?), int operationIndex = 0)
{
- BreCalClient.misc.Client.ApiResponse> localVarResponse = ShipcallsGetWithHttpInfo();
+ BreCalClient.misc.Client.ApiResponse> localVarResponse = ShipcallsGetWithHttpInfo(pastDays);
return localVarResponse.Data;
}
///
- /// Gets a list of ship calls
+ /// Gets a list of ship calls
///
/// Thrown when fails to make API call
+ /// number of days in the past to include in the result. *Example: 7*. (optional)
/// Index associated with the operation.
/// ApiResponse of List<Shipcall>
- public BreCalClient.misc.Client.ApiResponse> ShipcallsGetWithHttpInfo(int operationIndex = 0)
+ public BreCalClient.misc.Client.ApiResponse> ShipcallsGetWithHttpInfo(int? pastDays = default(int?), int operationIndex = 0)
{
BreCalClient.misc.Client.RequestOptions localVarRequestOptions = new BreCalClient.misc.Client.RequestOptions();
string[] _contentTypes = new string[] {
@@ -1248,6 +1255,10 @@ namespace BreCalClient.misc.Api
{
localVarRequestOptions.HeaderParameters.Add("Accept", localVarAccept);
}
+ if (pastDays != null)
+ {
+ localVarRequestOptions.QueryParameters.Add(BreCalClient.misc.Client.ClientUtils.ParameterToMultiMap("", "past_days", pastDays));
+ }
localVarRequestOptions.Operation = "DefaultApi.ShipcallsGet";
localVarRequestOptions.OperationIndex = operationIndex;
// authentication (ApiKey) required
@@ -1268,25 +1279,27 @@ namespace BreCalClient.misc.Api
return localVarResponse;
}
///
- /// Gets a list of ship calls
+ /// Gets a list of ship calls
///
/// Thrown when fails to make API call
+ /// number of days in the past to include in the result. *Example: 7*. (optional)
/// Index associated with the operation.
/// Cancellation Token to cancel the request.
/// Task of List<Shipcall>
- public async System.Threading.Tasks.Task> ShipcallsGetAsync(int operationIndex = 0, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken))
+ public async System.Threading.Tasks.Task> ShipcallsGetAsync(int? pastDays = default(int?), int operationIndex = 0, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken))
{
- BreCalClient.misc.Client.ApiResponse> localVarResponse = await ShipcallsGetWithHttpInfoAsync(operationIndex, cancellationToken).ConfigureAwait(false);
+ BreCalClient.misc.Client.ApiResponse> localVarResponse = await ShipcallsGetWithHttpInfoAsync(pastDays, operationIndex, cancellationToken).ConfigureAwait(false);
return localVarResponse.Data;
}
///
- /// Gets a list of ship calls
+ /// Gets a list of ship calls
///
/// Thrown when fails to make API call
+ /// number of days in the past to include in the result. *Example: 7*. (optional)
/// Index associated with the operation.
/// Cancellation Token to cancel the request.
/// Task of ApiResponse (List<Shipcall>)
- public async System.Threading.Tasks.Task>> ShipcallsGetWithHttpInfoAsync(int operationIndex = 0, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken))
+ public async System.Threading.Tasks.Task>> ShipcallsGetWithHttpInfoAsync(int? pastDays = default(int?), int operationIndex = 0, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken))
{
BreCalClient.misc.Client.RequestOptions localVarRequestOptions = new BreCalClient.misc.Client.RequestOptions();
string[] _contentTypes = new string[] {
@@ -1305,6 +1318,10 @@ namespace BreCalClient.misc.Api
{
localVarRequestOptions.HeaderParameters.Add("Accept", localVarAccept);
}
+ if (pastDays != null)
+ {
+ localVarRequestOptions.QueryParameters.Add(BreCalClient.misc.Client.ClientUtils.ParameterToMultiMap("", "past_days", pastDays));
+ }
localVarRequestOptions.Operation = "DefaultApi.ShipcallsGet";
localVarRequestOptions.OperationIndex = operationIndex;
// authentication (ApiKey) required
@@ -1325,24 +1342,25 @@ namespace BreCalClient.misc.Api
return localVarResponse;
}
///
- /// Create a new ship call
+ /// Create a new ship call
///
/// Thrown when fails to make API call
/// Creates a new ship call. **Do not** provide id parameter.
/// Index associated with the operation.
- ///
- public void ShipcallsPost(Shipcall shipcall, int operationIndex = 0)
+ /// Id
+ public Id ShipcallsPost(Shipcall shipcall, int operationIndex = 0)
{
- ShipcallsPostWithHttpInfo(shipcall);
+ BreCalClient.misc.Client.ApiResponse localVarResponse = ShipcallsPostWithHttpInfo(shipcall);
+ return localVarResponse.Data;
}
///
- /// Create a new ship call
+ /// Create a new ship call
///
/// Thrown when fails to make API call
/// Creates a new ship call. **Do not** provide id parameter.
/// Index associated with the operation.
- /// ApiResponse of Object(void)
- public BreCalClient.misc.Client.ApiResponse ShipcallsPostWithHttpInfo(Shipcall shipcall, int operationIndex = 0)
+ /// ApiResponse of Id
+ public BreCalClient.misc.Client.ApiResponse ShipcallsPostWithHttpInfo(Shipcall shipcall, int operationIndex = 0)
{
// verify the required parameter 'shipcall' is set
if (shipcall == null)
@@ -1376,7 +1394,7 @@ namespace BreCalClient.misc.Api
localVarRequestOptions.HeaderParameters.Add("Authorization", this.Configuration.GetApiKeyWithPrefix("Authorization"));
}
// make the HTTP request
- var localVarResponse = this.Client.Post("/shipcalls", localVarRequestOptions, this.Configuration);
+ var localVarResponse = this.Client.Post("/shipcalls", localVarRequestOptions, this.Configuration);
if (this.ExceptionFactory != null)
{
Exception _exception = this.ExceptionFactory("ShipcallsPost", localVarResponse);
@@ -1388,26 +1406,27 @@ namespace BreCalClient.misc.Api
return localVarResponse;
}
///
- /// Create a new ship call
+ /// Create a new ship call
///
/// Thrown when fails to make API call
/// Creates a new ship call. **Do not** provide id parameter.
/// Index associated with the operation.
/// Cancellation Token to cancel the request.
- /// Task of void
- public async System.Threading.Tasks.Task ShipcallsPostAsync(Shipcall shipcall, int operationIndex = 0, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken))
+ /// Task of Id
+ public async System.Threading.Tasks.Task ShipcallsPostAsync(Shipcall shipcall, int operationIndex = 0, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken))
{
- await ShipcallsPostWithHttpInfoAsync(shipcall, operationIndex, cancellationToken).ConfigureAwait(false);
+ BreCalClient.misc.Client.ApiResponse localVarResponse = await ShipcallsPostWithHttpInfoAsync(shipcall, operationIndex, cancellationToken).ConfigureAwait(false);
+ return localVarResponse.Data;
}
///
- /// Create a new ship call
+ /// Create a new ship call
///
/// Thrown when fails to make API call
/// Creates a new ship call. **Do not** provide id parameter.
/// Index associated with the operation.
/// Cancellation Token to cancel the request.
- /// Task of ApiResponse
- public async System.Threading.Tasks.Task> ShipcallsPostWithHttpInfoAsync(Shipcall shipcall, int operationIndex = 0, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken))
+ /// Task of ApiResponse (Id)
+ public async System.Threading.Tasks.Task> ShipcallsPostWithHttpInfoAsync(Shipcall shipcall, int operationIndex = 0, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken))
{
// verify the required parameter 'shipcall' is set
if (shipcall == null)
@@ -1441,7 +1460,7 @@ namespace BreCalClient.misc.Api
localVarRequestOptions.HeaderParameters.Add("Authorization", this.Configuration.GetApiKeyWithPrefix("Authorization"));
}
// make the HTTP request
- var localVarResponse = await this.AsynchronousClient.PostAsync("/shipcalls", localVarRequestOptions, this.Configuration, cancellationToken).ConfigureAwait(false);
+ var localVarResponse = await this.AsynchronousClient.PostAsync("/shipcalls", localVarRequestOptions, this.Configuration, cancellationToken).ConfigureAwait(false);
if (this.ExceptionFactory != null)
{
Exception _exception = this.ExceptionFactory("ShipcallsPost", localVarResponse);
@@ -1453,24 +1472,25 @@ namespace BreCalClient.misc.Api
return localVarResponse;
}
///
- /// Updates a ship call
+ /// Updates a ship call
///
/// Thrown when fails to make API call
/// Creates a new ship call. The id parameter is **required**.
/// Index associated with the operation.
- ///
- public void ShipcallsPut(Shipcall shipcall, int operationIndex = 0)
+ /// Id
+ public Id ShipcallsPut(Shipcall shipcall, int operationIndex = 0)
{
- ShipcallsPutWithHttpInfo(shipcall);
+ BreCalClient.misc.Client.ApiResponse localVarResponse = ShipcallsPutWithHttpInfo(shipcall);
+ return localVarResponse.Data;
}
///
- /// Updates a ship call
+ /// Updates a ship call
///
/// Thrown when fails to make API call
/// Creates a new ship call. The id parameter is **required**.
/// Index associated with the operation.
- /// ApiResponse of Object(void)
- public BreCalClient.misc.Client.ApiResponse ShipcallsPutWithHttpInfo(Shipcall shipcall, int operationIndex = 0)
+ /// ApiResponse of Id
+ public BreCalClient.misc.Client.ApiResponse ShipcallsPutWithHttpInfo(Shipcall shipcall, int operationIndex = 0)
{
// verify the required parameter 'shipcall' is set
if (shipcall == null)
@@ -1504,7 +1524,7 @@ namespace BreCalClient.misc.Api
localVarRequestOptions.HeaderParameters.Add("Authorization", this.Configuration.GetApiKeyWithPrefix("Authorization"));
}
// make the HTTP request
- var localVarResponse = this.Client.Put("/shipcalls", localVarRequestOptions, this.Configuration);
+ var localVarResponse = this.Client.Put("/shipcalls", localVarRequestOptions, this.Configuration);
if (this.ExceptionFactory != null)
{
Exception _exception = this.ExceptionFactory("ShipcallsPut", localVarResponse);
@@ -1516,26 +1536,27 @@ namespace BreCalClient.misc.Api
return localVarResponse;
}
///
- /// Updates a ship call
+ /// Updates a ship call
///
/// Thrown when fails to make API call
/// Creates a new ship call. The id parameter is **required**.
/// Index associated with the operation.
/// Cancellation Token to cancel the request.
- /// Task of void
- public async System.Threading.Tasks.Task ShipcallsPutAsync(Shipcall shipcall, int operationIndex = 0, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken))
+ /// Task of Id
+ public async System.Threading.Tasks.Task ShipcallsPutAsync(Shipcall shipcall, int operationIndex = 0, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken))
{
- await ShipcallsPutWithHttpInfoAsync(shipcall, operationIndex, cancellationToken).ConfigureAwait(false);
+ BreCalClient.misc.Client.ApiResponse localVarResponse = await ShipcallsPutWithHttpInfoAsync(shipcall, operationIndex, cancellationToken).ConfigureAwait(false);
+ return localVarResponse.Data;
}
///
- /// Updates a ship call
+ /// Updates a ship call
///
/// Thrown when fails to make API call
/// Creates a new ship call. The id parameter is **required**.
/// Index associated with the operation.
/// Cancellation Token to cancel the request.
- /// Task of ApiResponse
- public async System.Threading.Tasks.Task> ShipcallsPutWithHttpInfoAsync(Shipcall shipcall, int operationIndex = 0, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken))
+ /// Task of ApiResponse (Id)
+ public async System.Threading.Tasks.Task> ShipcallsPutWithHttpInfoAsync(Shipcall shipcall, int operationIndex = 0, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken))
{
// verify the required parameter 'shipcall' is set
if (shipcall == null)
@@ -1569,7 +1590,7 @@ namespace BreCalClient.misc.Api
localVarRequestOptions.HeaderParameters.Add("Authorization", this.Configuration.GetApiKeyWithPrefix("Authorization"));
}
// make the HTTP request
- var localVarResponse = await this.AsynchronousClient.PutAsync("/shipcalls", localVarRequestOptions, this.Configuration, cancellationToken).ConfigureAwait(false);
+ var localVarResponse = await this.AsynchronousClient.PutAsync("/shipcalls", localVarRequestOptions, this.Configuration, cancellationToken).ConfigureAwait(false);
if (this.ExceptionFactory != null)
{
Exception _exception = this.ExceptionFactory("ShipcallsPut", localVarResponse);
@@ -1581,7 +1602,7 @@ namespace BreCalClient.misc.Api
return localVarResponse;
}
///
- /// gets a list of registered shipcalls
+ /// gets a list of registered shipcalls
///
/// Thrown when fails to make API call
/// Index associated with the operation.
@@ -1592,7 +1613,7 @@ namespace BreCalClient.misc.Api
return localVarResponse.Data;
}
///
- /// gets a list of registered shipcalls
+ /// gets a list of registered shipcalls
///
/// Thrown when fails to make API call
/// Index associated with the operation.
@@ -1636,7 +1657,7 @@ namespace BreCalClient.misc.Api
return localVarResponse;
}
///
- /// gets a list of registered shipcalls
+ /// gets a list of registered shipcalls
///
/// Thrown when fails to make API call
/// Index associated with the operation.
@@ -1648,7 +1669,7 @@ namespace BreCalClient.misc.Api
return localVarResponse.Data;
}
///
- /// gets a list of registered shipcalls
+ /// gets a list of registered shipcalls
///
/// Thrown when fails to make API call
/// Index associated with the operation.
@@ -1693,7 +1714,7 @@ namespace BreCalClient.misc.Api
return localVarResponse;
}
///
- /// Delete a times entry for a ship call.
+ /// Delete a times entry for a ship call.
///
/// Thrown when fails to make API call
///
@@ -1704,7 +1725,7 @@ namespace BreCalClient.misc.Api
TimesDeleteWithHttpInfo(id);
}
///
- /// Delete a times entry for a ship call.
+ /// Delete a times entry for a ship call.
///
/// Thrown when fails to make API call
///
@@ -1750,7 +1771,7 @@ namespace BreCalClient.misc.Api
return localVarResponse;
}
///
- /// Delete a times entry for a ship call.
+ /// Delete a times entry for a ship call.
///
/// Thrown when fails to make API call
///
@@ -1762,7 +1783,7 @@ namespace BreCalClient.misc.Api
await TimesDeleteWithHttpInfoAsync(id, operationIndex, cancellationToken).ConfigureAwait(false);
}
///
- /// Delete a times entry for a ship call.
+ /// Delete a times entry for a ship call.
///
/// Thrown when fails to make API call
///
@@ -1809,7 +1830,7 @@ namespace BreCalClient.misc.Api
return localVarResponse;
}
///
- /// Get all recorded times for a a ship call
+ /// Get all recorded times for a a ship call
///
/// Thrown when fails to make API call
/// **Id**. *Example: 42*. Id of referenced ship call. (optional)
@@ -1821,7 +1842,7 @@ namespace BreCalClient.misc.Api
return localVarResponse.Data;
}
///
- /// Get all recorded times for a a ship call
+ /// Get all recorded times for a a ship call
///
/// Thrown when fails to make API call
/// **Id**. *Example: 42*. Id of referenced ship call. (optional)
@@ -1870,7 +1891,7 @@ namespace BreCalClient.misc.Api
return localVarResponse;
}
///
- /// Get all recorded times for a a ship call
+ /// Get all recorded times for a a ship call
///
/// Thrown when fails to make API call
/// **Id**. *Example: 42*. Id of referenced ship call. (optional)
@@ -1883,7 +1904,7 @@ namespace BreCalClient.misc.Api
return localVarResponse.Data;
}
///
- /// Get all recorded times for a a ship call
+ /// Get all recorded times for a a ship call
///
/// Thrown when fails to make API call
/// **Id**. *Example: 42*. Id of referenced ship call. (optional)
@@ -1933,24 +1954,25 @@ namespace BreCalClient.misc.Api
return localVarResponse;
}
///
- /// Create a new times entry for a ship call
+ /// Create a new times entry for a ship call
///
/// Thrown when fails to make API call
/// Times entry that will be added to the ship call. **Do not** provide id parameter.
/// Index associated with the operation.
- ///
- public void TimesPost(Times times, int operationIndex = 0)
+ /// Id
+ public Id TimesPost(Times times, int operationIndex = 0)
{
- TimesPostWithHttpInfo(times);
+ BreCalClient.misc.Client.ApiResponse localVarResponse = TimesPostWithHttpInfo(times);
+ return localVarResponse.Data;
}
///
- /// Create a new times entry for a ship call
+ /// Create a new times entry for a ship call
///
/// Thrown when fails to make API call
/// Times entry that will be added to the ship call. **Do not** provide id parameter.
/// Index associated with the operation.
- /// ApiResponse of Object(void)
- public BreCalClient.misc.Client.ApiResponse TimesPostWithHttpInfo(Times times, int operationIndex = 0)
+ /// ApiResponse of Id
+ public BreCalClient.misc.Client.ApiResponse TimesPostWithHttpInfo(Times times, int operationIndex = 0)
{
// verify the required parameter 'times' is set
if (times == null)
@@ -1984,7 +2006,7 @@ namespace BreCalClient.misc.Api
localVarRequestOptions.HeaderParameters.Add("Authorization", this.Configuration.GetApiKeyWithPrefix("Authorization"));
}
// make the HTTP request
- var localVarResponse = this.Client.Post("/times", localVarRequestOptions, this.Configuration);
+ var localVarResponse = this.Client.Post("/times", localVarRequestOptions, this.Configuration);
if (this.ExceptionFactory != null)
{
Exception _exception = this.ExceptionFactory("TimesPost", localVarResponse);
@@ -1996,26 +2018,27 @@ namespace BreCalClient.misc.Api
return localVarResponse;
}
///
- /// Create a new times entry for a ship call
+ /// Create a new times entry for a ship call
///
/// Thrown when fails to make API call
/// Times entry that will be added to the ship call. **Do not** provide id parameter.
/// Index associated with the operation.
/// Cancellation Token to cancel the request.
- /// Task of void
- public async System.Threading.Tasks.Task TimesPostAsync(Times times, int operationIndex = 0, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken))
+ /// Task of Id
+ public async System.Threading.Tasks.Task TimesPostAsync(Times times, int operationIndex = 0, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken))
{
- await TimesPostWithHttpInfoAsync(times, operationIndex, cancellationToken).ConfigureAwait(false);
+ BreCalClient.misc.Client.ApiResponse localVarResponse = await TimesPostWithHttpInfoAsync(times, operationIndex, cancellationToken).ConfigureAwait(false);
+ return localVarResponse.Data;
}
///
- /// Create a new times entry for a ship call
+ /// Create a new times entry for a ship call
///
/// Thrown when fails to make API call
/// Times entry that will be added to the ship call. **Do not** provide id parameter.
/// Index associated with the operation.
/// Cancellation Token to cancel the request.
- /// Task of ApiResponse
- public async System.Threading.Tasks.Task> TimesPostWithHttpInfoAsync(Times times, int operationIndex = 0, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken))
+ /// Task of ApiResponse (Id)
+ public async System.Threading.Tasks.Task> TimesPostWithHttpInfoAsync(Times times, int operationIndex = 0, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken))
{
// verify the required parameter 'times' is set
if (times == null)
@@ -2049,7 +2072,7 @@ namespace BreCalClient.misc.Api
localVarRequestOptions.HeaderParameters.Add("Authorization", this.Configuration.GetApiKeyWithPrefix("Authorization"));
}
// make the HTTP request
- var localVarResponse = await this.AsynchronousClient.PostAsync("/times", localVarRequestOptions, this.Configuration, cancellationToken).ConfigureAwait(false);
+ var localVarResponse = await this.AsynchronousClient.PostAsync("/times", localVarRequestOptions, this.Configuration, cancellationToken).ConfigureAwait(false);
if (this.ExceptionFactory != null)
{
Exception _exception = this.ExceptionFactory("TimesPost", localVarResponse);
@@ -2061,24 +2084,25 @@ namespace BreCalClient.misc.Api
return localVarResponse;
}
///
- /// Update a times entry for a ship call
+ /// Update a times entry for a ship call
///
/// Thrown when fails to make API call
/// Times entry that will be added to the ship call. The id parameter is **required**.
/// Index associated with the operation.
- ///
- public void TimesPut(Times times, int operationIndex = 0)
+ /// Id
+ public Id TimesPut(Times times, int operationIndex = 0)
{
- TimesPutWithHttpInfo(times);
+ BreCalClient.misc.Client.ApiResponse localVarResponse = TimesPutWithHttpInfo(times);
+ return localVarResponse.Data;
}
///
- /// Update a times entry for a ship call
+ /// Update a times entry for a ship call
///
/// Thrown when fails to make API call
/// Times entry that will be added to the ship call. The id parameter is **required**.
/// Index associated with the operation.
- /// ApiResponse of Object(void)
- public BreCalClient.misc.Client.ApiResponse TimesPutWithHttpInfo(Times times, int operationIndex = 0)
+ /// ApiResponse of Id
+ public BreCalClient.misc.Client.ApiResponse TimesPutWithHttpInfo(Times times, int operationIndex = 0)
{
// verify the required parameter 'times' is set
if (times == null)
@@ -2112,7 +2136,7 @@ namespace BreCalClient.misc.Api
localVarRequestOptions.HeaderParameters.Add("Authorization", this.Configuration.GetApiKeyWithPrefix("Authorization"));
}
// make the HTTP request
- var localVarResponse = this.Client.Put("/times", localVarRequestOptions, this.Configuration);
+ var localVarResponse = this.Client.Put("/times", localVarRequestOptions, this.Configuration);
if (this.ExceptionFactory != null)
{
Exception _exception = this.ExceptionFactory("TimesPut", localVarResponse);
@@ -2124,26 +2148,27 @@ namespace BreCalClient.misc.Api
return localVarResponse;
}
///
- /// Update a times entry for a ship call
+ /// Update a times entry for a ship call
///
/// Thrown when fails to make API call
/// Times entry that will be added to the ship call. The id parameter is **required**.
/// Index associated with the operation.
/// Cancellation Token to cancel the request.
- /// Task of void
- public async System.Threading.Tasks.Task TimesPutAsync(Times times, int operationIndex = 0, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken))
+ /// Task of Id
+ public async System.Threading.Tasks.Task TimesPutAsync(Times times, int operationIndex = 0, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken))
{
- await TimesPutWithHttpInfoAsync(times, operationIndex, cancellationToken).ConfigureAwait(false);
+ BreCalClient.misc.Client.ApiResponse localVarResponse = await TimesPutWithHttpInfoAsync(times, operationIndex, cancellationToken).ConfigureAwait(false);
+ return localVarResponse.Data;
}
///
- /// Update a times entry for a ship call
+ /// Update a times entry for a ship call
///
/// Thrown when fails to make API call
/// Times entry that will be added to the ship call. The id parameter is **required**.
/// Index associated with the operation.
/// Cancellation Token to cancel the request.
- /// Task of ApiResponse
- public async System.Threading.Tasks.Task> TimesPutWithHttpInfoAsync(Times times, int operationIndex = 0, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken))
+ /// Task of ApiResponse (Id)
+ public async System.Threading.Tasks.Task> TimesPutWithHttpInfoAsync(Times times, int operationIndex = 0, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken))
{
// verify the required parameter 'times' is set
if (times == null)
@@ -2177,7 +2202,7 @@ namespace BreCalClient.misc.Api
localVarRequestOptions.HeaderParameters.Add("Authorization", this.Configuration.GetApiKeyWithPrefix("Authorization"));
}
// make the HTTP request
- var localVarResponse = await this.AsynchronousClient.PutAsync("/times", localVarRequestOptions, this.Configuration, cancellationToken).ConfigureAwait(false);
+ var localVarResponse = await this.AsynchronousClient.PutAsync("/times", localVarRequestOptions, this.Configuration, cancellationToken).ConfigureAwait(false);
if (this.ExceptionFactory != null)
{
Exception _exception = this.ExceptionFactory("TimesPut", localVarResponse);
@@ -2189,7 +2214,7 @@ namespace BreCalClient.misc.Api
return localVarResponse;
}
///
- /// Update user details (first/last name, phone, password)
+ /// Update user details (first/last name, phone, password)
///
/// Thrown when fails to make API call
/// User details
@@ -2200,7 +2225,7 @@ namespace BreCalClient.misc.Api
UserPutWithHttpInfo(userDetails);
}
///
- /// Update user details (first/last name, phone, password)
+ /// Update user details (first/last name, phone, password)
///
/// Thrown when fails to make API call
/// User details
@@ -2252,7 +2277,7 @@ namespace BreCalClient.misc.Api
return localVarResponse;
}
///
- /// Update user details (first/last name, phone, password)
+ /// Update user details (first/last name, phone, password)
///
/// Thrown when fails to make API call
/// User details
@@ -2264,7 +2289,7 @@ namespace BreCalClient.misc.Api
await UserPutWithHttpInfoAsync(userDetails, operationIndex, cancellationToken).ConfigureAwait(false);
}
///
- /// Update user details (first/last name, phone, password)
+ /// Update user details (first/last name, phone, password)
///
/// Thrown when fails to make API call
/// User details
@@ -3557,7 +3582,7 @@ namespace BreCalClient.misc.Client
{
Proxy = null;
UserAgent = WebUtility.UrlEncode("OpenAPI-Generator/1.0.0/csharp");
- BasePath = "https://brecaltest.bsmd-emswe.eu";
+ BasePath = "https://brecal.bsmd-emswe.eu";
DefaultHeaders = new ConcurrentDictionary();
ApiKey = new ConcurrentDictionary();
ApiKeyPrefix = new ConcurrentDictionary();
@@ -3565,7 +3590,7 @@ namespace BreCalClient.misc.Client
{
{
new Dictionary {
- {"url", "https://brecaltest.bsmd-emswe.eu"},
+ {"url", "https://brecal.bsmd-emswe.eu"},
{"description", "Test server hosted on vcup"},
}
}
@@ -3584,7 +3609,7 @@ namespace BreCalClient.misc.Client
IDictionary defaultHeaders,
IDictionary apiKey,
IDictionary apiKeyPrefix,
- string basePath = "https://brecaltest.bsmd-emswe.eu") : this()
+ string basePath = "https://brecal.bsmd-emswe.eu") : this()
{
if (string.IsNullOrWhiteSpace(basePath))
throw new ArgumentException("The provided basePath is invalid.", "basePath");
@@ -3613,7 +3638,7 @@ namespace BreCalClient.misc.Client
///
/// Gets or sets the base path for API access.
///
- public virtual string BasePath
+ public virtual string BasePath
{
get { return _basePath; }
set { _basePath = value; }
@@ -3760,7 +3785,7 @@ namespace BreCalClient.misc.Client
///
/// ApiKeyPrefix["Authorization"] = "Bearer";
///
- /// … where ApiKey["Authorization"] would then be used to set the value of your bearer token.
+ /// � where ApiKey["Authorization"] would then be used to set the value of your bearer token.
///
///
/// OAuth2 workflows should set tokens via AccessToken.
@@ -4903,16 +4928,18 @@ namespace BreCalClient.misc.Model
///
/// id.
/// name.
- /// participantId.
+ /// ownerId.
+ /// authorityId.
/// varLock.
/// created.
/// modified.
/// deleted (default to false).
- public Berth(int id = default(int), string name = default(string), int? participantId = default(int?), bool? varLock = default(bool?), DateTime created = default(DateTime), DateTime? modified = default(DateTime?), bool deleted = false)
+ public Berth(int id = default(int), string name = default(string), int? ownerId = default(int?), int? authorityId = default(int?), bool? varLock = default(bool?), DateTime created = default(DateTime), DateTime? modified = default(DateTime?), bool deleted = false)
{
this.Id = id;
this.Name = name;
- this.ParticipantId = participantId;
+ this.OwnerId = ownerId;
+ this.AuthorityId = authorityId;
this.VarLock = varLock;
this.Created = created;
this.Modified = modified;
@@ -4929,10 +4956,15 @@ namespace BreCalClient.misc.Model
[DataMember(Name = "name", EmitDefaultValue = true)]
public string Name { get; set; }
///
- /// Gets or Sets ParticipantId
+ /// Gets or Sets OwnerId
///
- [DataMember(Name = "participant_id", EmitDefaultValue = true)]
- public int? ParticipantId { get; set; }
+ [DataMember(Name = "owner_id", EmitDefaultValue = true)]
+ public int? OwnerId { get; set; }
+ ///
+ /// Gets or Sets AuthorityId
+ ///
+ [DataMember(Name = "authority_id", EmitDefaultValue = true)]
+ public int? AuthorityId { get; set; }
///
/// Gets or Sets VarLock
///
@@ -4963,7 +4995,8 @@ namespace BreCalClient.misc.Model
sb.Append("class Berth {\n");
sb.Append(" Id: ").Append(Id).Append("\n");
sb.Append(" Name: ").Append(Name).Append("\n");
- sb.Append(" ParticipantId: ").Append(ParticipantId).Append("\n");
+ sb.Append(" OwnerId: ").Append(OwnerId).Append("\n");
+ sb.Append(" AuthorityId: ").Append(AuthorityId).Append("\n");
sb.Append(" VarLock: ").Append(VarLock).Append("\n");
sb.Append(" Created: ").Append(Created).Append("\n");
sb.Append(" Modified: ").Append(Modified).Append("\n");
@@ -4999,37 +5032,41 @@ namespace BreCalClient.misc.Model
{
return false;
}
-
- return
+ return
(
this.Id == input.Id ||
this.Id.Equals(input.Id)
- ) &&
+ ) &&
(
this.Name == input.Name ||
(this.Name != null &&
this.Name.Equals(input.Name))
- ) &&
+ ) &&
(
- this.ParticipantId == input.ParticipantId ||
- (this.ParticipantId != null &&
- this.ParticipantId.Equals(input.ParticipantId))
- ) &&
+ this.OwnerId == input.OwnerId ||
+ (this.OwnerId != null &&
+ this.OwnerId.Equals(input.OwnerId))
+ ) &&
+ (
+ this.AuthorityId == input.AuthorityId ||
+ (this.AuthorityId != null &&
+ this.AuthorityId.Equals(input.AuthorityId))
+ ) &&
(
this.VarLock == input.VarLock ||
(this.VarLock != null &&
this.VarLock.Equals(input.VarLock))
- ) &&
+ ) &&
(
this.Created == input.Created ||
(this.Created != null &&
this.Created.Equals(input.Created))
- ) &&
+ ) &&
(
this.Modified == input.Modified ||
(this.Modified != null &&
this.Modified.Equals(input.Modified))
- ) &&
+ ) &&
(
this.Deleted == input.Deleted ||
this.Deleted.Equals(input.Deleted)
@@ -5050,9 +5087,13 @@ namespace BreCalClient.misc.Model
{
hashCode = (hashCode * 59) + this.Name.GetHashCode();
}
- if (this.ParticipantId != null)
+ if (this.OwnerId != null)
{
- hashCode = (hashCode * 59) + this.ParticipantId.GetHashCode();
+ hashCode = (hashCode * 59) + this.OwnerId.GetHashCode();
+ }
+ if (this.AuthorityId != null)
+ {
+ hashCode = (hashCode * 59) + this.AuthorityId.GetHashCode();
}
if (this.VarLock != null)
{
@@ -5180,12 +5221,12 @@ namespace BreCalClient.misc.Model
{
return false;
}
- return
+ return
(
this.Username == input.Username ||
(this.Username != null &&
this.Username.Equals(input.Username))
- ) &&
+ ) &&
(
this.Password == input.Password ||
(this.Password != null &&
@@ -5305,7 +5346,7 @@ namespace BreCalClient.misc.Model
{
return false;
}
- return
+ return
(
this.Message == input.Message ||
(this.Message != null &&
@@ -5340,6 +5381,107 @@ namespace BreCalClient.misc.Model
}
}
+/*
+ * Bremen calling API
+ *
+ * Administer DEBRE ship calls, times and notifications
+ *
+ * The version of the OpenAPI document: 0.6.0
+ * Contact: info@textbausteine.net
+ * Generated by: https://github.com/openapitools/openapi-generator.git
+ */
+namespace BreCalClient.misc.Model
+{
+ ///
+ /// A unique identifier for an entity
+ ///
+ [DataContract(Name = "Id")]
+ public partial class Id : IEquatable, IValidatableObject
+ {
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// varId.
+ public Id(int varId = default(int))
+ {
+ this.VarId = varId;
+ }
+ ///
+ /// Gets or Sets VarId
+ ///
+ [DataMember(Name = "id", EmitDefaultValue = true)]
+ public int VarId { get; set; }
+ ///
+ /// Returns the string presentation of the object
+ ///
+ /// String presentation of the object
+ public override string ToString()
+ {
+ StringBuilder sb = new StringBuilder();
+ sb.Append("class Id {\n");
+ sb.Append(" VarId: ").Append(VarId).Append("\n");
+ sb.Append("}\n");
+ return sb.ToString();
+ }
+ ///
+ /// Returns the JSON string presentation of the object
+ ///
+ /// JSON string presentation of the object
+ public virtual string ToJson()
+ {
+ return Newtonsoft.Json.JsonConvert.SerializeObject(this, Newtonsoft.Json.Formatting.Indented);
+ }
+ ///
+ /// Returns true if objects are equal
+ ///
+ /// Object to be compared
+ /// Boolean
+ public override bool Equals(object input)
+ {
+ return this.Equals(input as Id);
+ }
+ ///
+ /// Returns true if Id instances are equal
+ ///
+ /// Instance of Id to be compared
+ /// Boolean
+ public bool Equals(Id input)
+ {
+ if (input == null)
+ {
+ return false;
+ }
+ return
+ (
+ this.VarId == input.VarId ||
+ this.VarId.Equals(input.VarId)
+ );
+ }
+ ///
+ /// Gets the hash code
+ ///
+ /// Hash code
+ public override int GetHashCode()
+ {
+ unchecked // Overflow is fine, just wrap
+ {
+ int hashCode = 41;
+ hashCode = (hashCode * 59) + this.VarId.GetHashCode();
+ return hashCode;
+ }
+ }
+ ///
+ /// To validate all properties of the instance
+ ///
+ /// Validation context
+ /// Validation Result
+ IEnumerable IValidatableObject.Validate(ValidationContext validationContext)
+ {
+ yield break;
+ }
+ }
+}
+
/*
* Bremen calling API
*
@@ -5366,9 +5508,10 @@ namespace BreCalClient.misc.Model
/// lastName.
/// userName.
/// userPhone.
+ /// userEmail.
/// exp.
/// token.
- public LoginResult(int id = default(int), int participantId = default(int), string firstName = default(string), string lastName = default(string), string userName = default(string), string userPhone = default(string), float exp = default(float), string token = default(string))
+ public LoginResult(int id = default(int), int participantId = default(int), string firstName = default(string), string lastName = default(string), string userName = default(string), string userPhone = default(string), string userEmail = default(string), float exp = default(float), string token = default(string))
{
this.Id = id;
this.ParticipantId = participantId;
@@ -5376,6 +5519,7 @@ namespace BreCalClient.misc.Model
this.LastName = lastName;
this.UserName = userName;
this.UserPhone = userPhone;
+ this.UserEmail = userEmail;
this.Exp = exp;
this.Token = token;
}
@@ -5410,6 +5554,11 @@ namespace BreCalClient.misc.Model
[DataMember(Name = "user_phone", EmitDefaultValue = true)]
public string UserPhone { get; set; }
///
+ /// Gets or Sets UserEmail
+ ///
+ [DataMember(Name = "user_email", EmitDefaultValue = true)]
+ public string UserEmail { get; set; }
+ ///
/// Gets or Sets Exp
///
[DataMember(Name = "exp", EmitDefaultValue = true)]
@@ -5433,6 +5582,7 @@ namespace BreCalClient.misc.Model
sb.Append(" LastName: ").Append(LastName).Append("\n");
sb.Append(" UserName: ").Append(UserName).Append("\n");
sb.Append(" UserPhone: ").Append(UserPhone).Append("\n");
+ sb.Append(" UserEmail: ").Append(UserEmail).Append("\n");
sb.Append(" Exp: ").Append(Exp).Append("\n");
sb.Append(" Token: ").Append(Token).Append("\n");
sb.Append("}\n");
@@ -5466,39 +5616,44 @@ namespace BreCalClient.misc.Model
{
return false;
}
- return
+ return
(
this.Id == input.Id ||
this.Id.Equals(input.Id)
- ) &&
+ ) &&
(
this.ParticipantId == input.ParticipantId ||
this.ParticipantId.Equals(input.ParticipantId)
- ) &&
+ ) &&
(
this.FirstName == input.FirstName ||
(this.FirstName != null &&
this.FirstName.Equals(input.FirstName))
- ) &&
+ ) &&
(
this.LastName == input.LastName ||
(this.LastName != null &&
this.LastName.Equals(input.LastName))
- ) &&
+ ) &&
(
this.UserName == input.UserName ||
(this.UserName != null &&
this.UserName.Equals(input.UserName))
- ) &&
+ ) &&
(
this.UserPhone == input.UserPhone ||
(this.UserPhone != null &&
this.UserPhone.Equals(input.UserPhone))
- ) &&
+ ) &&
+ (
+ this.UserEmail == input.UserEmail ||
+ (this.UserEmail != null &&
+ this.UserEmail.Equals(input.UserEmail))
+ ) &&
(
this.Exp == input.Exp ||
this.Exp.Equals(input.Exp)
- ) &&
+ ) &&
(
this.Token == input.Token ||
(this.Token != null &&
@@ -5532,6 +5687,10 @@ namespace BreCalClient.misc.Model
{
hashCode = (hashCode * 59) + this.UserPhone.GetHashCode();
}
+ if (this.UserEmail != null)
+ {
+ hashCode = (hashCode * 59) + this.UserEmail.GetHashCode();
+ }
hashCode = (hashCode * 59) + this.Exp.GetHashCode();
if (this.Token != null)
{
@@ -5700,37 +5859,37 @@ namespace BreCalClient.misc.Model
{
return false;
}
- return
+ return
(
this.Id == input.Id ||
this.Id.Equals(input.Id)
- ) &&
+ ) &&
(
this.TimesId == input.TimesId ||
this.TimesId.Equals(input.TimesId)
- ) &&
+ ) &&
(
this.ParticipantId == input.ParticipantId ||
this.ParticipantId.Equals(input.ParticipantId)
- ) &&
+ ) &&
(
this.NotificationType == input.NotificationType ||
this.NotificationType.Equals(input.NotificationType)
- ) &&
+ ) &&
(
this.Timestamp == input.Timestamp ||
(this.Timestamp != null &&
this.Timestamp.Equals(input.Timestamp))
- ) &&
+ ) &&
(
this.Acknowledged == input.Acknowledged ||
this.Acknowledged.Equals(input.Acknowledged)
- ) &&
+ ) &&
(
this.Created == input.Created ||
(this.Created != null &&
this.Created.Equals(input.Created))
- ) &&
+ ) &&
(
this.Modified == input.Modified ||
(this.Modified != null &&
@@ -5920,50 +6079,50 @@ namespace BreCalClient.misc.Model
{
return false;
}
- return
+ return
(
this.Id == input.Id ||
this.Id.Equals(input.Id)
- ) &&
+ ) &&
(
this.Name == input.Name ||
(this.Name != null &&
this.Name.Equals(input.Name))
- ) &&
+ ) &&
(
this.Street == input.Street ||
(this.Street != null &&
this.Street.Equals(input.Street))
- ) &&
+ ) &&
(
this.PostalCode == input.PostalCode ||
(this.PostalCode != null &&
this.PostalCode.Equals(input.PostalCode))
- ) &&
+ ) &&
(
this.City == input.City ||
(this.City != null &&
this.City.Equals(input.City))
- ) &&
+ ) &&
(
this.Type == input.Type ||
this.Type.Equals(input.Type)
- ) &&
+ ) &&
(
this.Flags == input.Flags ||
(this.Flags != null &&
this.Flags.Equals(input.Flags))
- ) &&
+ ) &&
(
this.Created == input.Created ||
(this.Created != null &&
this.Created.Equals(input.Created))
- ) &&
+ ) &&
(
this.Modified == input.Modified ||
(this.Modified != null &&
this.Modified.Equals(input.Modified))
- ) &&
+ ) &&
(
this.Deleted == input.Deleted ||
this.Deleted.Equals(input.Deleted)
@@ -6044,6 +6203,125 @@ namespace BreCalClient.misc.Model
}
}
+/*
+ * Bremen calling API
+ *
+ * Administer DEBRE ship calls, times and notifications
+ *
+ * The version of the OpenAPI document: 0.6.0
+ * Contact: info@textbausteine.net
+ * Generated by: https://github.com/openapitools/openapi-generator.git
+ */
+namespace BreCalClient.misc.Model
+{
+ ///
+ /// Participant assigned to a shipcall with a given role (type)
+ ///
+ [DataContract(Name = "participant_assignment")]
+ public partial class ParticipantAssignment : IEquatable, IValidatableObject
+ {
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ [JsonConstructorAttribute]
+ protected ParticipantAssignment() { }
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// participantId (required).
+ /// type (required).
+ public ParticipantAssignment(int participantId = default(int), int type = default(int))
+ {
+ this.ParticipantId = participantId;
+ this.Type = type;
+ }
+ ///
+ /// Gets or Sets ParticipantId
+ ///
+ [DataMember(Name = "participant_id", IsRequired = true, EmitDefaultValue = true)]
+ public int ParticipantId { get; set; }
+ ///
+ /// Gets or Sets Type
+ ///
+ [DataMember(Name = "type", IsRequired = true, EmitDefaultValue = true)]
+ public int Type { get; set; }
+ ///
+ /// Returns the string presentation of the object
+ ///
+ /// String presentation of the object
+ public override string ToString()
+ {
+ StringBuilder sb = new StringBuilder();
+ sb.Append("class ParticipantAssignment {\n");
+ sb.Append(" ParticipantId: ").Append(ParticipantId).Append("\n");
+ sb.Append(" Type: ").Append(Type).Append("\n");
+ sb.Append("}\n");
+ return sb.ToString();
+ }
+ ///
+ /// Returns the JSON string presentation of the object
+ ///
+ /// JSON string presentation of the object
+ public virtual string ToJson()
+ {
+ return Newtonsoft.Json.JsonConvert.SerializeObject(this, Newtonsoft.Json.Formatting.Indented);
+ }
+ ///
+ /// Returns true if objects are equal
+ ///
+ /// Object to be compared
+ /// Boolean
+ public override bool Equals(object input)
+ {
+ return this.Equals(input as ParticipantAssignment);
+ }
+ ///
+ /// Returns true if ParticipantAssignment instances are equal
+ ///
+ /// Instance of ParticipantAssignment to be compared
+ /// Boolean
+ public bool Equals(ParticipantAssignment input)
+ {
+ if (input == null)
+ {
+ return false;
+ }
+ return
+ (
+ this.ParticipantId == input.ParticipantId ||
+ this.ParticipantId.Equals(input.ParticipantId)
+ ) &&
+ (
+ this.Type == input.Type ||
+ this.Type.Equals(input.Type)
+ );
+ }
+ ///
+ /// Gets the hash code
+ ///
+ /// Hash code
+ public override int GetHashCode()
+ {
+ unchecked // Overflow is fine, just wrap
+ {
+ int hashCode = 41;
+ hashCode = (hashCode * 59) + this.ParticipantId.GetHashCode();
+ hashCode = (hashCode * 59) + this.Type.GetHashCode();
+ return hashCode;
+ }
+ }
+ ///
+ /// To validate all properties of the instance
+ ///
+ /// Validation context
+ /// Validation Result
+ IEnumerable IValidatableObject.Validate(ValidationContext validationContext)
+ {
+ yield break;
+ }
+ }
+}
+
/*
* Bremen calling API
*
@@ -6210,65 +6488,65 @@ namespace BreCalClient.misc.Model
{
return false;
}
- return
+ return
(
this.Id == input.Id ||
this.Id.Equals(input.Id)
- ) &&
+ ) &&
(
this.Name == input.Name ||
(this.Name != null &&
this.Name.Equals(input.Name))
- ) &&
+ ) &&
(
this.Imo == input.Imo ||
(this.Imo != null &&
this.Imo.Equals(input.Imo))
- ) &&
+ ) &&
(
this.Callsign == input.Callsign ||
(this.Callsign != null &&
this.Callsign.Equals(input.Callsign))
- ) &&
+ ) &&
(
this.ParticipantId == input.ParticipantId ||
(this.ParticipantId != null &&
this.ParticipantId.Equals(input.ParticipantId))
- ) &&
+ ) &&
(
this.Length == input.Length ||
(this.Length != null &&
this.Length.Equals(input.Length))
- ) &&
+ ) &&
(
this.Width == input.Width ||
(this.Width != null &&
this.Width.Equals(input.Width))
- ) &&
+ ) &&
(
this.IsTug == input.IsTug ||
this.IsTug.Equals(input.IsTug)
- ) &&
+ ) &&
(
this.BollardPull == input.BollardPull ||
(this.BollardPull != null &&
this.BollardPull.Equals(input.BollardPull))
- ) &&
+ ) &&
(
this.Eni == input.Eni ||
(this.Eni != null &&
this.Eni.Equals(input.Eni))
- ) &&
+ ) &&
(
this.Created == input.Created ||
(this.Created != null &&
this.Created.Equals(input.Created))
- ) &&
+ ) &&
(
this.Modified == input.Modified ||
(this.Modified != null &&
this.Modified.Equals(input.Modified))
- ) &&
+ ) &&
(
this.Deleted == input.Deleted ||
this.Deleted.Equals(input.Deleted)
@@ -6379,7 +6657,7 @@ namespace BreCalClient.misc.Model
/// The unique identifier of a ship call (required).
/// shipId (required).
/// type (required).
- /// eta (required).
+ /// eta.
/// voyage.
/// etd.
/// arrivalBerthId.
@@ -6399,10 +6677,12 @@ namespace BreCalClient.misc.Model
/// anchored.
/// mooredLock.
/// canceled.
+ /// evaluation.
+ /// evaluationMessage.
/// participants.
/// created.
/// modified.
- public Shipcall(int id = default(int), int shipId = default(int), int type = default(int), DateTime eta = default(DateTime), string voyage = default(string), DateTime? etd = default(DateTime?), int? arrivalBerthId = default(int?), int? departureBerthId = default(int?), bool? tugRequired = default(bool?), bool? pilotRequired = default(bool?), int? flags = default(int?), bool? pierSide = default(bool?), bool? bunkering = default(bool?), bool? replenishingTerminal = default(bool?), bool? replenishingLock = default(bool?), float? draft = default(float?), DateTime? tidalWindowFrom = default(DateTime?), DateTime? tidalWindowTo = default(DateTime?), bool? rainSensitiveCargo = default(bool?), int? recommendedTugs = default(int?), bool? anchored = default(bool?), bool? mooredLock = default(bool?), bool? canceled = default(bool?), List participants = default(List), DateTime created = default(DateTime), DateTime? modified = default(DateTime?))
+ public Shipcall(int id = default(int), int shipId = default(int), int type = default(int), DateTime? eta = default(DateTime?), string voyage = default(string), DateTime? etd = default(DateTime?), int? arrivalBerthId = default(int?), int? departureBerthId = default(int?), bool? tugRequired = default(bool?), bool? pilotRequired = default(bool?), int? flags = default(int?), bool? pierSide = default(bool?), bool? bunkering = default(bool?), bool? replenishingTerminal = default(bool?), bool? replenishingLock = default(bool?), float? draft = default(float?), DateTime? tidalWindowFrom = default(DateTime?), DateTime? tidalWindowTo = default(DateTime?), bool? rainSensitiveCargo = default(bool?), int? recommendedTugs = default(int?), bool? anchored = default(bool?), bool? mooredLock = default(bool?), bool? canceled = default(bool?), int? evaluation = default(int?), string evaluationMessage = default(string), List participants = default(List), DateTime created = default(DateTime), DateTime? modified = default(DateTime?))
{
this.Id = id;
this.ShipId = shipId;
@@ -6427,6 +6707,8 @@ namespace BreCalClient.misc.Model
this.Anchored = anchored;
this.MooredLock = mooredLock;
this.Canceled = canceled;
+ this.Evaluation = evaluation;
+ this.EvaluationMessage = evaluationMessage;
this.Participants = participants;
this.Created = created;
this.Modified = modified;
@@ -6450,8 +6732,8 @@ namespace BreCalClient.misc.Model
///
/// Gets or Sets Eta
///
- [DataMember(Name = "eta", IsRequired = true, EmitDefaultValue = true)]
- public DateTime Eta { get; set; }
+ [DataMember(Name = "eta", EmitDefaultValue = true)]
+ public DateTime? Eta { get; set; }
///
/// Gets or Sets Voyage
///
@@ -6548,11 +6830,20 @@ namespace BreCalClient.misc.Model
[DataMember(Name = "canceled", EmitDefaultValue = true)]
public bool? Canceled { get; set; }
///
+ /// Gets or Sets Evaluation
+ ///
+ [DataMember(Name = "evaluation", EmitDefaultValue = true)]
+ public int? Evaluation { get; set; }
+ ///
+ /// Gets or Sets EvaluationMessage
+ ///
+ [DataMember(Name = "evaluation_message", EmitDefaultValue = true)]
+ public string EvaluationMessage { get; set; }
+ ///
/// Gets or Sets Participants
///
- /// [1,5,7]
[DataMember(Name = "participants", EmitDefaultValue = true)]
- public List Participants { get; set; }
+ public List Participants { get; set; }
///
/// Gets or Sets Created
///
@@ -6594,6 +6885,8 @@ namespace BreCalClient.misc.Model
sb.Append(" Anchored: ").Append(Anchored).Append("\n");
sb.Append(" MooredLock: ").Append(MooredLock).Append("\n");
sb.Append(" Canceled: ").Append(Canceled).Append("\n");
+ sb.Append(" Evaluation: ").Append(Evaluation).Append("\n");
+ sb.Append(" EvaluationMessage: ").Append(EvaluationMessage).Append("\n");
sb.Append(" Participants: ").Append(Participants).Append("\n");
sb.Append(" Created: ").Append(Created).Append("\n");
sb.Append(" Modified: ").Append(Modified).Append("\n");
@@ -6628,130 +6921,140 @@ namespace BreCalClient.misc.Model
{
return false;
}
- return
+ return
(
this.Id == input.Id ||
this.Id.Equals(input.Id)
- ) &&
+ ) &&
(
this.ShipId == input.ShipId ||
this.ShipId.Equals(input.ShipId)
- ) &&
+ ) &&
(
this.Type == input.Type ||
this.Type.Equals(input.Type)
- ) &&
+ ) &&
(
this.Eta == input.Eta ||
(this.Eta != null &&
this.Eta.Equals(input.Eta))
- ) &&
+ ) &&
(
this.Voyage == input.Voyage ||
(this.Voyage != null &&
this.Voyage.Equals(input.Voyage))
- ) &&
+ ) &&
(
this.Etd == input.Etd ||
(this.Etd != null &&
this.Etd.Equals(input.Etd))
- ) &&
+ ) &&
(
this.ArrivalBerthId == input.ArrivalBerthId ||
(this.ArrivalBerthId != null &&
this.ArrivalBerthId.Equals(input.ArrivalBerthId))
- ) &&
+ ) &&
(
this.DepartureBerthId == input.DepartureBerthId ||
(this.DepartureBerthId != null &&
this.DepartureBerthId.Equals(input.DepartureBerthId))
- ) &&
+ ) &&
(
this.TugRequired == input.TugRequired ||
(this.TugRequired != null &&
this.TugRequired.Equals(input.TugRequired))
- ) &&
+ ) &&
(
this.PilotRequired == input.PilotRequired ||
(this.PilotRequired != null &&
this.PilotRequired.Equals(input.PilotRequired))
- ) &&
+ ) &&
(
this.Flags == input.Flags ||
(this.Flags != null &&
this.Flags.Equals(input.Flags))
- ) &&
+ ) &&
(
this.PierSide == input.PierSide ||
(this.PierSide != null &&
this.PierSide.Equals(input.PierSide))
- ) &&
+ ) &&
(
this.Bunkering == input.Bunkering ||
(this.Bunkering != null &&
this.Bunkering.Equals(input.Bunkering))
- ) &&
+ ) &&
(
this.ReplenishingTerminal == input.ReplenishingTerminal ||
(this.ReplenishingTerminal != null &&
this.ReplenishingTerminal.Equals(input.ReplenishingTerminal))
- ) &&
+ ) &&
(
this.ReplenishingLock == input.ReplenishingLock ||
(this.ReplenishingLock != null &&
this.ReplenishingLock.Equals(input.ReplenishingLock))
- ) &&
+ ) &&
(
this.Draft == input.Draft ||
(this.Draft != null &&
this.Draft.Equals(input.Draft))
- ) &&
+ ) &&
(
this.TidalWindowFrom == input.TidalWindowFrom ||
(this.TidalWindowFrom != null &&
this.TidalWindowFrom.Equals(input.TidalWindowFrom))
- ) &&
+ ) &&
(
this.TidalWindowTo == input.TidalWindowTo ||
(this.TidalWindowTo != null &&
this.TidalWindowTo.Equals(input.TidalWindowTo))
- ) &&
+ ) &&
(
this.RainSensitiveCargo == input.RainSensitiveCargo ||
(this.RainSensitiveCargo != null &&
this.RainSensitiveCargo.Equals(input.RainSensitiveCargo))
- ) &&
+ ) &&
(
this.RecommendedTugs == input.RecommendedTugs ||
(this.RecommendedTugs != null &&
this.RecommendedTugs.Equals(input.RecommendedTugs))
- ) &&
+ ) &&
(
this.Anchored == input.Anchored ||
(this.Anchored != null &&
this.Anchored.Equals(input.Anchored))
- ) &&
+ ) &&
(
this.MooredLock == input.MooredLock ||
(this.MooredLock != null &&
this.MooredLock.Equals(input.MooredLock))
- ) &&
+ ) &&
(
this.Canceled == input.Canceled ||
(this.Canceled != null &&
this.Canceled.Equals(input.Canceled))
- ) &&
+ ) &&
+ (
+ this.Evaluation == input.Evaluation ||
+ (this.Evaluation != null &&
+ this.Evaluation.Equals(input.Evaluation))
+ ) &&
+ (
+ this.EvaluationMessage == input.EvaluationMessage ||
+ (this.EvaluationMessage != null &&
+ this.EvaluationMessage.Equals(input.EvaluationMessage))
+ ) &&
(
this.Participants == input.Participants ||
this.Participants != null &&
input.Participants != null &&
this.Participants.SequenceEqual(input.Participants)
- ) &&
+ ) &&
(
this.Created == input.Created ||
(this.Created != null &&
this.Created.Equals(input.Created))
- ) &&
+ ) &&
(
this.Modified == input.Modified ||
(this.Modified != null &&
@@ -6850,6 +7153,14 @@ namespace BreCalClient.misc.Model
{
hashCode = (hashCode * 59) + this.Canceled.GetHashCode();
}
+ if (this.Evaluation != null)
+ {
+ hashCode = (hashCode * 59) + this.Evaluation.GetHashCode();
+ }
+ if (this.EvaluationMessage != null)
+ {
+ hashCode = (hashCode * 59) + this.EvaluationMessage.GetHashCode();
+ }
if (this.Participants != null)
{
hashCode = (hashCode * 59) + this.Participants.GetHashCode();
@@ -7109,99 +7420,99 @@ namespace BreCalClient.misc.Model
{
return false;
}
- return
+ return
(
this.Id == input.Id ||
this.Id.Equals(input.Id)
- ) &&
+ ) &&
(
this.EtaBerth == input.EtaBerth ||
(this.EtaBerth != null &&
this.EtaBerth.Equals(input.EtaBerth))
- ) &&
+ ) &&
(
this.EtaBerthFixed == input.EtaBerthFixed ||
(this.EtaBerthFixed != null &&
this.EtaBerthFixed.Equals(input.EtaBerthFixed))
- ) &&
+ ) &&
(
this.EtdBerth == input.EtdBerth ||
(this.EtdBerth != null &&
this.EtdBerth.Equals(input.EtdBerth))
- ) &&
+ ) &&
(
this.EtdBerthFixed == input.EtdBerthFixed ||
(this.EtdBerthFixed != null &&
this.EtdBerthFixed.Equals(input.EtdBerthFixed))
- ) &&
+ ) &&
(
this.LockTime == input.LockTime ||
(this.LockTime != null &&
this.LockTime.Equals(input.LockTime))
- ) &&
+ ) &&
(
this.LockTimeFixed == input.LockTimeFixed ||
(this.LockTimeFixed != null &&
this.LockTimeFixed.Equals(input.LockTimeFixed))
- ) &&
+ ) &&
(
this.ZoneEntry == input.ZoneEntry ||
(this.ZoneEntry != null &&
this.ZoneEntry.Equals(input.ZoneEntry))
- ) &&
+ ) &&
(
this.ZoneEntryFixed == input.ZoneEntryFixed ||
(this.ZoneEntryFixed != null &&
this.ZoneEntryFixed.Equals(input.ZoneEntryFixed))
- ) &&
+ ) &&
(
this.OperationsStart == input.OperationsStart ||
(this.OperationsStart != null &&
this.OperationsStart.Equals(input.OperationsStart))
- ) &&
+ ) &&
(
this.OperationsEnd == input.OperationsEnd ||
(this.OperationsEnd != null &&
this.OperationsEnd.Equals(input.OperationsEnd))
- ) &&
+ ) &&
(
this.Remarks == input.Remarks ||
(this.Remarks != null &&
this.Remarks.Equals(input.Remarks))
- ) &&
+ ) &&
(
this.ShipcallId == input.ShipcallId ||
this.ShipcallId.Equals(input.ShipcallId)
- ) &&
+ ) &&
(
this.ParticipantId == input.ParticipantId ||
this.ParticipantId.Equals(input.ParticipantId)
- ) &&
+ ) &&
(
this.BerthId == input.BerthId ||
(this.BerthId != null &&
this.BerthId.Equals(input.BerthId))
- ) &&
+ ) &&
(
this.BerthInfo == input.BerthInfo ||
(this.BerthInfo != null &&
this.BerthInfo.Equals(input.BerthInfo))
- ) &&
+ ) &&
(
this.PierSide == input.PierSide ||
(this.PierSide != null &&
this.PierSide.Equals(input.PierSide))
- ) &&
+ ) &&
(
this.ParticipantType == input.ParticipantType ||
(this.ParticipantType != null &&
this.ParticipantType.Equals(input.ParticipantType))
- ) &&
+ ) &&
(
this.Created == input.Created ||
(this.Created != null &&
this.Created.Equals(input.Created))
- ) &&
+ ) &&
(
this.Modified == input.Modified ||
(this.Modified != null &&
@@ -7334,7 +7645,8 @@ namespace BreCalClient.misc.Model
/// firstName.
/// lastName.
/// userPhone.
- public UserDetails(int id = default(int), string oldPassword = default(string), string newPassword = default(string), string firstName = default(string), string lastName = default(string), string userPhone = default(string))
+ /// userEmail.
+ public UserDetails(int id = default(int), string oldPassword = default(string), string newPassword = default(string), string firstName = default(string), string lastName = default(string), string userPhone = default(string), string userEmail = default(string))
{
this.Id = id;
this.OldPassword = oldPassword;
@@ -7342,6 +7654,7 @@ namespace BreCalClient.misc.Model
this.FirstName = firstName;
this.LastName = lastName;
this.UserPhone = userPhone;
+ this.UserEmail = userEmail;
}
///
/// Gets or Sets Id
@@ -7374,6 +7687,11 @@ namespace BreCalClient.misc.Model
[DataMember(Name = "user_phone", EmitDefaultValue = true)]
public string UserPhone { get; set; }
///
+ /// Gets or Sets UserEmail
+ ///
+ [DataMember(Name = "user_email", EmitDefaultValue = true)]
+ public string UserEmail { get; set; }
+ ///
/// Returns the string presentation of the object
///
/// String presentation of the object
@@ -7387,6 +7705,7 @@ namespace BreCalClient.misc.Model
sb.Append(" FirstName: ").Append(FirstName).Append("\n");
sb.Append(" LastName: ").Append(LastName).Append("\n");
sb.Append(" UserPhone: ").Append(UserPhone).Append("\n");
+ sb.Append(" UserEmail: ").Append(UserEmail).Append("\n");
sb.Append("}\n");
return sb.ToString();
}
@@ -7418,35 +7737,40 @@ namespace BreCalClient.misc.Model
{
return false;
}
- return
+ return
(
this.Id == input.Id ||
this.Id.Equals(input.Id)
- ) &&
+ ) &&
(
this.OldPassword == input.OldPassword ||
(this.OldPassword != null &&
this.OldPassword.Equals(input.OldPassword))
- ) &&
+ ) &&
(
this.NewPassword == input.NewPassword ||
(this.NewPassword != null &&
this.NewPassword.Equals(input.NewPassword))
- ) &&
+ ) &&
(
this.FirstName == input.FirstName ||
(this.FirstName != null &&
this.FirstName.Equals(input.FirstName))
- ) &&
+ ) &&
(
this.LastName == input.LastName ||
(this.LastName != null &&
this.LastName.Equals(input.LastName))
- ) &&
+ ) &&
(
this.UserPhone == input.UserPhone ||
(this.UserPhone != null &&
this.UserPhone.Equals(input.UserPhone))
+ ) &&
+ (
+ this.UserEmail == input.UserEmail ||
+ (this.UserEmail != null &&
+ this.UserEmail.Equals(input.UserEmail))
);
}
///
@@ -7479,6 +7803,10 @@ namespace BreCalClient.misc.Model
{
hashCode = (hashCode * 59) + this.UserPhone.GetHashCode();
}
+ if (this.UserEmail != null)
+ {
+ hashCode = (hashCode * 59) + this.UserEmail.GetHashCode();
+ }
return hashCode;
}
}
diff --git a/misc/BreCalApi.yaml b/misc/BreCalApi.yaml
index cb8acfc..917cd3a 100644
--- a/misc/BreCalApi.yaml
+++ b/misc/BreCalApi.yaml
@@ -14,7 +14,7 @@ info:
servers:
# tutorial: https://idratherbewriting.com/learnapidoc/pubapis_openapi_step3_servers_object.html
- - url: "https://brecaltest.bsmd-emswe.eu/"
+ - url: "https://brecal.bsmd-emswe.eu/"
description: "Test server hosted on vcup"
paths:
@@ -68,13 +68,13 @@ paths:
/shipcalls:
get:
summary: Gets a list of ship calls
- #parameters:
- # - name: participant_id
- # in: query
- # required: true
- # description: "**Id of participant**. *Example: 2*. Id of participant entity requesting ship calls"
- # schema:
- # type: integer
+ parameters:
+ - name: past_days
+ in: query
+ required: false
+ description: "number of days in the past to include in the result. *Example: 7*."
+ schema:
+ type: integer
responses:
200:
description: ship call list
@@ -100,6 +100,8 @@ paths:
schema:
$ref: "#/components/schemas/shipcall"
responses:
+ 201:
+ $ref: "#/components/responses/201"
400:
$ref: "#/components/responses/400"
401:
@@ -119,6 +121,8 @@ paths:
schema:
$ref: "#/components/schemas/shipcall"
responses:
+ 200:
+ $ref: "#/components/responses/200"
400:
$ref: "#/components/responses/400"
401:
@@ -210,6 +214,8 @@ paths:
schema:
$ref: "#/components/schemas/times"
responses:
+ 201:
+ $ref: "#/components/responses/201"
400:
$ref: "#/components/responses/400"
401:
@@ -229,6 +235,8 @@ paths:
schema:
$ref: "#/components/schemas/times"
responses:
+ 200:
+ $ref: "#/components/responses/200"
400:
$ref: "#/components/responses/400"
401:
@@ -324,13 +332,23 @@ components:
shipcallId:
description: The unique identifier of a ship call
type: integer
+ participant_assignment:
+ description: Participant assigned to a shipcall with a given role (type)
+ type: object
+ required:
+ - participant_id
+ - type
+ properties:
+ participant_id:
+ type: integer
+ type:
+ type: integer
shipcall:
type: object
required:
- id
- ship_id
- type
- - eta
properties:
id:
$ref: "#/components/schemas/shipcallId"
@@ -342,6 +360,7 @@ components:
eta:
type: string
format: date-time
+ nullable: true
voyage:
type: string
maxLength: 16
@@ -404,11 +423,16 @@ components:
canceled:
type: boolean
nullable: true
+ evaluation:
+ type: integer
+ nullable: true
+ evaluation_message:
+ type: string
+ nullable: true
participants:
type: array
items:
- type: integer
- example: [1, 5, 7]
+ $ref: "#/components/schemas/participant_assignment"
created:
type: string
format: date-time
@@ -509,7 +533,10 @@ components:
name:
type: string
maxLength: 128
- participant_id:
+ owner_id:
+ type: integer
+ nullable: true
+ authority_id:
type: integer
nullable: true
lock:
@@ -669,6 +696,8 @@ components:
type: string
user_phone:
type: string
+ user_email:
+ type: string
exp:
type: number
format: float
@@ -696,7 +725,15 @@ components:
user_phone:
type: string
nullable: true
-
+ user_email:
+ type: string
+ nullable: true
+ Id:
+ type: object
+ description: A unique identifier for an entity
+ properties:
+ id:
+ type: integer
Error:
type: object
required:
@@ -712,6 +749,18 @@ components:
in: header
name: Authorization
responses:
+ 200:
+ description: OK
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/Id"
+ 201:
+ description: Created
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/Id"
400:
description: Invalid input
content:
diff --git a/misc/Deployment.md b/misc/Deployment.md
new file mode 100644
index 0000000..21ee272
--- /dev/null
+++ b/misc/Deployment.md
@@ -0,0 +1,110 @@
+# System deployment
+
+___
+
+## Prerequisites
+
+## Client
+
+## Database
+
+## Backend / Flask app
+
+In order to not have complicated and error-prone copying manoevers a direct deployment from the repo is used using git.
+
+### File structure
+
+### Steps
+
+1) Created a ssh-key for the user that does the installation on the server following the Github [instructions](https://docs.github.com/en/authentication/connecting-to-github-with-ssh/generating-a-new-ssh-key-and-adding-it-to-the-ssh-agent).
+2) Deploy generated key to the Github user account.
+3) In the shell, activate ssh-agent and add the key. For example:
+
+```bash
+eval ($ssh-agent)
+ssh-add ~/.ssh/od_ed25519
+```
+
+4) Change to deployment folder
+
+```bash
+cd /var/www/brecal_test
+```
+
+5) Perform sparse checkout on the Flask server subtree
+
+```bash
+git clone -n git@github.com:puls200/brecal.git
+cd
+git sparse-checkout set --no-cone src/server
+git checkout
+```
+
+6) Database credentials are stored outside the web root, we are using /var/www/secure. Here the file ```connection_data.json``` is placed, a different named copy for each instance.
+
+
+### Installing Requirements
+Python 3.11 & Pip3.11 installation (linux), virtualenv package
+
+Optional, Step 0: Python source installation
+Windows (untested):
+ Python 3.11: https://www.geeksforgeeks.org/download-and-install-python-3-latest-version/
+ PIP package manager (in command window): py -m ensurepip --upgrade
+ Virtual Environment 'virtualenv': https://mothergeo-py.readthedocs.io/en/latest/development/how-to/venv-win.html
+
+Linux:
+ Python 3.11 & the PIP package manager: https://tecadmin.net/how-to-install-python-3-11-on-ubuntu-22-04/
+
+Virtual Environment 'virtualenv'
+
+### Building the Virtual Environment
+Create a virtualenv called '.venv' with a specified python version, such as python3.11
+All python packages will be installed in the virtual environment. Upon running the application,
+make sure to activate the virtual environment before starting it.
+
+Windows: # on windows, provide the full path, as obtained by "where python"
+1.) Relocate to the 'brecal' directory
+ cd brecal
+
+2.) create a virtual environment with the name '.venv'
+ where python
+ virtualenv --python {python_path} .venv
+
+3.) activate the virtual environment and install
+ .venv\Scripts\activate
+ cd ./src/server
+ pip install -r requirements.txt
+
+
+Linux:
+1.) Relocate to the 'brecal' directory
+ cd brecal
+2.) create a virtual environment with the name '.venv'
+ virtualenv --python python311 .venv
+3.) activate the virtual environment and install
+ source .venv/bin/activate
+ cd ./src/server
+ pip install -r requirements.txt
+
+
+### Testing (using 'pytest')
+All tests in the directory brecal/src/server/tests can be run automatically with the 'pytest' module It recognizes any function within these
+scripts, as these use 'test_'-prefixes. The module can be used to run the tests or even to create coverage reports, which show, what portions
+of the directory are still untested. When the pytest module is installed, one can use a single line of code to run all tests.
+
+1.) Relocate to the application's directory
+ cd brecal/src/server
+2.) activate the virtual environment
+Windows:
+ source .venv\Scripts\activate
+Linux:
+ source .venv\bin\activate
+3.) run the tests
+ option1: run pytest as a standalone
+ pytest tests/
+
+ option2: run pytest & coverage report (inspects coverage for the folder 'BreCal' by running each test in 'tests/'
+ this creates a folder with the name 'coverage_reports', where .html files are created and can be observed by a developer.
+ the coverage files are typically ignored by .gitignore
+ pytest --cov BreCal tests/
+
diff --git a/misc/create_schema.sql b/misc/create_schema.sql
index dfa0cf1..adbe508 100644
--- a/misc/create_schema.sql
+++ b/misc/create_schema.sql
@@ -1,8 +1,6 @@
-CREATE DATABASE IF NOT EXISTS `bremen_calling` /*!40100 DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci */ /*!80016 DEFAULT ENCRYPTION='N' */;
-USE `bremen_calling`;
-- MySQL dump 10.13 Distrib 8.0.33, for Win64 (x86_64)
--
--- Host: localhost Database: bremen_calling
+-- Host: localhost Database: bremen_calling_test
-- ------------------------------------------------------
-- Server version 8.0.34-0ubuntu0.22.04.1
@@ -27,14 +25,17 @@ DROP TABLE IF EXISTS `berth`;
CREATE TABLE `berth` (
`id` int unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(128) DEFAULT NULL COMMENT 'Descriptive name',
- `participant_id` int unsigned DEFAULT NULL COMMENT 'If berth belongs to a participant, reference it here',
`lock` bit(1) DEFAULT NULL COMMENT 'The lock must be used',
+ `owner_id` int unsigned DEFAULT NULL,
+ `authority_id` int unsigned DEFAULT NULL,
`created` datetime DEFAULT CURRENT_TIMESTAMP,
`modified` datetime DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP,
`deleted` bit(1) DEFAULT b'0',
PRIMARY KEY (`id`),
- KEY `FK_BERTH_PART` (`participant_id`),
- CONSTRAINT `FK_BERTH_PART` FOREIGN KEY (`participant_id`) REFERENCES `participant` (`id`)
+ KEY `FK_OWNER_PART_idx` (`owner_id`),
+ KEY `FK_AUTHORITY_PART_idx` (`authority_id`),
+ CONSTRAINT `FK_AUTHORITY_PART` FOREIGN KEY (`authority_id`) REFERENCES `participant` (`id`),
+ CONSTRAINT `FK_OWNER_PART` FOREIGN KEY (`owner_id`) REFERENCES `participant` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=195 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='Berth of ship for a ship call';
/*!40101 SET character_set_client = @saved_cs_client */;
@@ -82,7 +83,7 @@ CREATE TABLE `participant` (
`modified` datetime DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP,
`deleted` bit(1) DEFAULT b'0',
PRIMARY KEY (`id`)
-) ENGINE=InnoDB AUTO_INCREMENT=136 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='An organization taking part';
+) ENGINE=InnoDB AUTO_INCREMENT=137 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='An organization taking part';
/*!40101 SET character_set_client = @saved_cs_client */;
--
@@ -165,7 +166,7 @@ CREATE TABLE `ship` (
PRIMARY KEY (`id`),
KEY `FK_SHIP_PARTICIPANT` (`participant_id`),
CONSTRAINT `FK_SHIP_PARTICIPANT` FOREIGN KEY (`participant_id`) REFERENCES `participant` (`id`)
-) ENGINE=InnoDB AUTO_INCREMENT=13 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
+) ENGINE=InnoDB AUTO_INCREMENT=14 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
/*!40101 SET character_set_client = @saved_cs_client */;
--
@@ -199,6 +200,8 @@ CREATE TABLE `shipcall` (
`anchored` bit(1) DEFAULT NULL,
`moored_lock` bit(1) DEFAULT NULL,
`canceled` bit(1) DEFAULT NULL,
+ `evaluation` int unsigned DEFAULT NULL,
+ `evaluation_message` varchar(512) DEFAULT NULL,
`created` datetime DEFAULT CURRENT_TIMESTAMP,
`modified` datetime DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
@@ -208,7 +211,7 @@ CREATE TABLE `shipcall` (
CONSTRAINT `FK_SHIPCALL_BERTH_ARRIVAL` FOREIGN KEY (`arrival_berth_id`) REFERENCES `berth` (`id`),
CONSTRAINT `FK_SHIPCALL_BERTH_DEPARTURE` FOREIGN KEY (`departure_berth_id`) REFERENCES `berth` (`id`),
CONSTRAINT `FK_SHIPCALL_SHIP` FOREIGN KEY (`ship_id`) REFERENCES `ship` (`id`)
-) ENGINE=InnoDB AUTO_INCREMENT=19 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='Incoming, outgoing or moving to another berth';
+) ENGINE=InnoDB AUTO_INCREMENT=23 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='Incoming, outgoing or moving to another berth';
/*!40101 SET character_set_client = @saved_cs_client */;
--
@@ -222,6 +225,7 @@ CREATE TABLE `shipcall_participant_map` (
`id` int NOT NULL AUTO_INCREMENT,
`shipcall_id` int unsigned DEFAULT NULL,
`participant_id` int unsigned DEFAULT NULL,
+ `type` int unsigned DEFAULT NULL COMMENT 'Type of participant role',
`created` datetime DEFAULT CURRENT_TIMESTAMP,
`modified` datetime DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
@@ -229,7 +233,7 @@ CREATE TABLE `shipcall_participant_map` (
KEY `FK_MAP_SHIPCALL_PARTICIPANT` (`participant_id`),
CONSTRAINT `FK_MAP_PARTICIPANT_SHIPCALL` FOREIGN KEY (`shipcall_id`) REFERENCES `shipcall` (`id`),
CONSTRAINT `FK_MAP_SHIPCALL_PARTICIPANT` FOREIGN KEY (`participant_id`) REFERENCES `participant` (`id`)
-) ENGINE=InnoDB AUTO_INCREMENT=82 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='Associates a participant with a shipcall';
+) ENGINE=InnoDB AUTO_INCREMENT=128 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='Associates a participant with a shipcall';
/*!40101 SET character_set_client = @saved_cs_client */;
--
@@ -287,7 +291,7 @@ CREATE TABLE `times` (
KEY `FK_TIME_BERTH` (`berth_id`) /*!80000 INVISIBLE */,
CONSTRAINT `FK_TIME_BERTH` FOREIGN KEY (`berth_id`) REFERENCES `berth` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT,
CONSTRAINT `FK_TIME_PART` FOREIGN KEY (`participant_id`) REFERENCES `participant` (`id`)
-) ENGINE=InnoDB AUTO_INCREMENT=28 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='the planned time for the participants work';
+) ENGINE=InnoDB AUTO_INCREMENT=44 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='the planned time for the participants work';
/*!40101 SET character_set_client = @saved_cs_client */;
--
@@ -312,7 +316,7 @@ CREATE TABLE `user` (
PRIMARY KEY (`id`),
KEY `FK_USER_PART` (`participant_id`),
CONSTRAINT `FK_USER_PART` FOREIGN KEY (`participant_id`) REFERENCES `participant` (`id`)
-) ENGINE=InnoDB AUTO_INCREMENT=28 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='member of a participant';
+) ENGINE=InnoDB AUTO_INCREMENT=30 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='member of a participant';
/*!40101 SET character_set_client = @saved_cs_client */;
--
@@ -345,4 +349,4 @@ CREATE TABLE `user_role_map` (
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
--- Dump completed on 2023-09-05 10:36:12
+-- Dump completed on 2023-10-06 14:52:04
diff --git a/misc/sample_data.sql b/misc/sample_data.sql
index b17697e..97c278a 100644
--- a/misc/sample_data.sql
+++ b/misc/sample_data.sql
@@ -1,8 +1,6 @@
-CREATE DATABASE IF NOT EXISTS `bremen_calling` /*!40100 DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci */ /*!80016 DEFAULT ENCRYPTION='N' */;
-USE `bremen_calling`;
-- MySQL dump 10.13 Distrib 8.0.33, for Win64 (x86_64)
--
--- Host: localhost Database: bremen_calling
+-- Host: localhost Database: bremen_calling_test
-- ------------------------------------------------------
-- Server version 8.0.34-0ubuntu0.22.04.1
@@ -23,7 +21,7 @@ USE `bremen_calling`;
LOCK TABLES `berth` WRITE;
/*!40000 ALTER TABLE `berth` DISABLE KEYS */;
-INSERT INTO `berth` VALUES (1,'Roland Mühle',NULL,NULL,'2023-06-26 14:01:40',NULL,_binary '\0'),(2,'Stahlwerk',NULL,NULL,'2023-06-26 14:01:40',NULL,_binary '\0'),(3,'Kellogs',NULL,NULL,'2023-06-26 14:01:40',NULL,_binary '\0'),(139,'Avangard Dalben',110,NULL,'2023-08-21 08:23:35',NULL,_binary '\0'),(140,'Avangard Kaje',110,NULL,'2023-08-21 08:23:35',NULL,_binary '\0'),(141,'Baustelle 2',111,NULL,'2023-08-21 08:23:35',NULL,_binary '\0'),(142,'BHW',112,NULL,'2023-08-21 08:23:36',NULL,_binary '\0'),(143,'Dalben 2',111,NULL,'2023-08-21 08:23:36',NULL,_binary '\0'),(144,'Dalben 3',111,NULL,'2023-08-21 08:23:36',NULL,_binary '\0'),(145,'Egerland Kaje',113,NULL,'2023-08-21 08:23:36',NULL,_binary '\0'),(146,'Getreideanlage Pier A',114,NULL,'2023-08-21 08:23:37',NULL,_binary '\0'),(147,'Getreideanlage Pier D',114,NULL,'2023-08-21 08:23:37',NULL,_binary '\0'),(148,'Griepe, Bnp Paribas',115,NULL,'2023-08-21 08:23:37',NULL,_binary '\0'),(149,'Hafen F',116,NULL,'2023-08-21 08:23:37',NULL,_binary '\0'),(150,'Hansa Landhandel',117,NULL,'2023-08-21 08:23:38',NULL,_binary '\0'),(151,'Hansa Melasse',118,NULL,'2023-08-21 08:23:38',NULL,_binary '\0'),(152,'Hansa-Mühle',119,NULL,'2023-08-21 08:23:38',NULL,_binary '\0'),(153,'Heidelberger Sand',120,NULL,'2023-08-21 08:23:38',NULL,_binary '\0'),(154,'HGM Bunkerstation',121,NULL,'2023-08-21 08:23:39',NULL,_binary '\0'),(155,'HGM Tanklager',121,NULL,'2023-08-21 08:23:39',NULL,_binary '\0'),(156,'Kap Horn Innen',122,NULL,'2023-08-21 08:23:39',NULL,_binary '\0'),(157,'Kap Horn Weser',122,NULL,'2023-08-21 08:23:39',NULL,_binary '\0'),(158,'Kap Horn Weser Bremer Recycling',123,NULL,'2023-08-21 08:23:40',NULL,_binary '\0'),(159,'Kap Horn Weser -GHK-',124,NULL,'2023-08-21 08:23:40',NULL,_binary '\0'),(160,'Kohlenhafen 2',111,NULL,'2023-08-21 08:23:40',NULL,_binary '\0'),(161,'Kraftwerk Farge',125,NULL,'2023-08-21 08:23:40',NULL,_binary '\0'),(162,'Kraftwerk Industriehafen',126,NULL,'2023-08-21 08:23:41',NULL,_binary '\0'),(163,'Lankenau B',111,NULL,'2023-08-21 08:23:41',NULL,_binary '\0'),(164,'Mibau, Bnp Paribas',127,NULL,'2023-08-21 08:23:41',NULL,_binary '\0'),(165,'Müller Weser',114,NULL,'2023-08-21 08:23:41',NULL,_binary '\0'),(166,'Osterort 5 Aussen',111,NULL,'2023-08-21 08:23:41',NULL,_binary '\0'),(167,'Pier 2 Anleger',128,NULL,'2023-08-21 08:23:42',NULL,_binary '\0'),(168,'Pier III',129,NULL,'2023-08-21 08:23:42',NULL,_binary '\0'),(169,'Plump',130,NULL,'2023-08-21 08:23:42',NULL,_binary '\0'),(170,'Rolandmühle',131,NULL,'2023-08-21 08:23:42',NULL,_binary '\0'),(171,'Schleusenvorhafen Nord',111,NULL,'2023-08-21 08:23:43',NULL,_binary '\0'),(172,'Schrägpier',4,NULL,'2023-08-21 08:23:43',NULL,_binary '\0'),(173,'Schuppen 19',132,NULL,'2023-08-21 08:23:43',NULL,_binary '\0'),(174,'Schuppen 20',4,NULL,'2023-08-21 08:23:43',NULL,_binary '\0'),(175,'Schuppen 21',4,NULL,'2023-08-21 08:23:43',NULL,_binary '\0'),(176,'Schuppen 22',4,NULL,'2023-08-21 08:23:43',NULL,_binary '\0'),(177,'Schuppen 23',4,NULL,'2023-08-21 08:23:44',NULL,_binary '\0'),(178,'Schuppen 24',4,NULL,'2023-08-21 08:23:44',NULL,_binary '\0'),(179,'Seedalben Dlg-Seite',111,NULL,'2023-08-21 08:23:44',NULL,_binary '\0'),(180,'Seedalben Kw-Seite',111,NULL,'2023-08-21 08:23:44',NULL,_binary '\0'),(181,'Seehausen Spüler',111,NULL,'2023-08-21 08:23:44',NULL,_binary '\0'),(182,'Tankschiffliegeplatz 1',111,NULL,'2023-08-21 08:23:44',NULL,_binary '\0'),(183,'Tankschiffliegeplatz 2',111,NULL,'2023-08-21 08:23:44',NULL,_binary '\0'),(184,'Terminal 1',10,NULL,'2023-08-21 08:23:44',NULL,_binary '\0'),(185,'Terminal 2',10,NULL,'2023-08-21 08:23:45',NULL,_binary '\0'),(186,'Terminal 3',10,NULL,'2023-08-21 08:23:45',NULL,_binary '\0'),(187,'Terminal 4',10,NULL,'2023-08-21 08:23:45',NULL,_binary '\0'),(188,'TSR Recycling',133,NULL,'2023-08-21 08:23:45',NULL,_binary '\0'),(189,'Viehbrücke',111,NULL,'2023-08-21 08:23:45',NULL,_binary '\0'),(190,'Vulkan Industriegebiet',120,NULL,'2023-08-21 08:23:46',NULL,_binary '\0'),(191,'Weserbahnhof',132,NULL,'2023-08-21 08:23:46',NULL,_binary '\0'),(192,'Weser-Petrol Holzhafen',134,NULL,'2023-08-21 08:23:46',NULL,_binary '\0'),(193,'Weser-Petrol Kalihafen',134,NULL,'2023-08-21 08:23:46',NULL,_binary '\0'),(194,'Wesertanking',135,NULL,'2023-08-21 08:23:46',NULL,_binary '\0');
+INSERT INTO `berth` VALUES (1,'Roland Mühle',NULL,NULL,NULL,11,'2023-06-26 14:01:40','2023-10-06 15:04:08',_binary ''),(2,'Stahlwerk',NULL,NULL,NULL,11,'2023-06-26 14:01:40','2023-10-06 15:04:08',_binary ''),(3,'Kellogs',NULL,NULL,NULL,11,'2023-06-26 14:01:40','2023-10-06 15:04:08',_binary ''),(139,'Avangard Dalben',110,NULL,110,11,'2023-08-21 08:23:35','2023-10-06 15:04:08',_binary '\0'),(140,'Avangard Kaje',110,NULL,110,11,'2023-08-21 08:23:35','2023-10-06 15:04:08',_binary '\0'),(141,'Baustelle 2',111,NULL,111,11,'2023-08-21 08:23:35','2023-10-06 15:04:08',_binary '\0'),(142,'BHW',112,NULL,112,11,'2023-08-21 08:23:36','2023-10-06 15:04:08',_binary '\0'),(143,'Dalben 2',111,NULL,111,11,'2023-08-21 08:23:36','2023-10-06 15:04:08',_binary '\0'),(144,'Dalben 3',111,NULL,111,11,'2023-08-21 08:23:36','2023-10-06 15:04:08',_binary '\0'),(145,'Egerland Kaje',113,NULL,113,11,'2023-08-21 08:23:36','2023-10-06 15:04:08',_binary '\0'),(146,'Getreideanlage Pier A',114,NULL,114,11,'2023-08-21 08:23:37','2023-10-06 15:04:08',_binary '\0'),(147,'Getreideanlage Pier D',114,NULL,114,11,'2023-08-21 08:23:37','2023-10-06 15:04:08',_binary '\0'),(148,'Griepe, Bnp Paribas',115,NULL,115,11,'2023-08-21 08:23:37','2023-10-06 15:04:08',_binary '\0'),(149,'Hafen F',116,NULL,116,11,'2023-08-21 08:23:37','2023-10-06 15:04:08',_binary '\0'),(150,'Hansa Landhandel',117,NULL,117,11,'2023-08-21 08:23:38','2023-10-06 15:04:08',_binary '\0'),(151,'Hansa Melasse',118,NULL,118,11,'2023-08-21 08:23:38','2023-10-06 15:04:08',_binary '\0'),(152,'Hansa-Mühle',119,NULL,119,11,'2023-08-21 08:23:38','2023-10-06 15:04:08',_binary '\0'),(153,'Heidelberger Sand',120,NULL,120,11,'2023-08-21 08:23:38','2023-10-06 15:04:08',_binary '\0'),(154,'HGM Bunkerstation',121,NULL,121,11,'2023-08-21 08:23:39','2023-10-06 15:04:08',_binary '\0'),(155,'HGM Tanklager',121,NULL,121,11,'2023-08-21 08:23:39','2023-10-06 15:04:08',_binary '\0'),(156,'Kap Horn Innen',122,NULL,122,11,'2023-08-21 08:23:39','2023-10-06 15:04:08',_binary '\0'),(157,'Kap Horn Weser',122,NULL,122,11,'2023-08-21 08:23:39','2023-10-06 15:04:08',_binary '\0'),(158,'Kap Horn Weser Bremer Recycling',123,NULL,123,11,'2023-08-21 08:23:40','2023-10-06 15:04:08',_binary '\0'),(159,'Kap Horn Weser -GHK-',124,NULL,124,11,'2023-08-21 08:23:40','2023-10-06 15:04:08',_binary '\0'),(160,'Kohlenhafen 2',111,NULL,111,11,'2023-08-21 08:23:40','2023-10-06 15:04:08',_binary '\0'),(161,'Kraftwerk Farge',125,NULL,125,11,'2023-08-21 08:23:40','2023-10-06 15:04:08',_binary '\0'),(162,'Kraftwerk Industriehafen',126,NULL,126,11,'2023-08-21 08:23:41','2023-10-06 15:04:08',_binary '\0'),(163,'Lankenau B',111,NULL,111,11,'2023-08-21 08:23:41','2023-10-06 15:04:08',_binary '\0'),(164,'Mibau, Bnp Paribas',127,NULL,127,11,'2023-08-21 08:23:41','2023-10-06 15:04:08',_binary '\0'),(165,'Müller Weser',114,NULL,114,11,'2023-08-21 08:23:41','2023-10-06 15:04:08',_binary '\0'),(166,'Osterort 5 Aussen',111,NULL,111,11,'2023-08-21 08:23:41','2023-10-06 15:04:08',_binary '\0'),(167,'Pier 2 Anleger',128,NULL,128,11,'2023-08-21 08:23:42','2023-10-06 15:04:08',_binary '\0'),(168,'Pier III',129,NULL,129,11,'2023-08-21 08:23:42','2023-10-06 15:04:08',_binary '\0'),(169,'Plump',130,NULL,130,11,'2023-08-21 08:23:42','2023-10-06 15:04:08',_binary '\0'),(170,'Rolandmühle',131,NULL,131,11,'2023-08-21 08:23:42','2023-10-06 15:04:08',_binary '\0'),(171,'Schleusenvorhafen Nord',111,NULL,111,11,'2023-08-21 08:23:43','2023-10-06 15:04:08',_binary '\0'),(172,'Schrägpier',4,NULL,4,11,'2023-08-21 08:23:43','2023-10-06 15:04:08',_binary '\0'),(173,'Schuppen 19',132,NULL,132,11,'2023-08-21 08:23:43','2023-10-06 15:04:08',_binary '\0'),(174,'Schuppen 20',4,NULL,4,11,'2023-08-21 08:23:43','2023-10-06 15:04:08',_binary '\0'),(175,'Schuppen 21',4,NULL,4,11,'2023-08-21 08:23:43','2023-10-06 15:04:08',_binary '\0'),(176,'Schuppen 22',4,NULL,4,11,'2023-08-21 08:23:43','2023-10-06 15:04:08',_binary '\0'),(177,'Schuppen 23',4,NULL,4,11,'2023-08-21 08:23:44','2023-10-06 15:04:08',_binary '\0'),(178,'Schuppen 24',4,NULL,4,11,'2023-08-21 08:23:44','2023-10-06 15:04:08',_binary '\0'),(179,'Seedalben Dlg-Seite',111,NULL,111,11,'2023-08-21 08:23:44','2023-10-06 15:04:08',_binary '\0'),(180,'Seedalben Kw-Seite',111,NULL,111,11,'2023-08-21 08:23:44','2023-10-06 15:04:08',_binary '\0'),(181,'Seehausen Spüler',111,NULL,111,11,'2023-08-21 08:23:44','2023-10-06 15:04:08',_binary '\0'),(182,'Tankschiffliegeplatz 1',111,NULL,111,11,'2023-08-21 08:23:44','2023-10-06 15:04:08',_binary '\0'),(183,'Tankschiffliegeplatz 2',111,NULL,111,11,'2023-08-21 08:23:44','2023-10-06 15:04:08',_binary '\0'),(184,'Terminal 1',10,NULL,10,11,'2023-08-21 08:23:44','2023-10-06 15:04:08',_binary '\0'),(185,'Terminal 2',10,NULL,10,11,'2023-08-21 08:23:45','2023-10-06 15:04:08',_binary '\0'),(186,'Terminal 3',10,NULL,10,11,'2023-08-21 08:23:45','2023-10-06 15:04:08',_binary '\0'),(187,'Terminal 4',10,NULL,10,11,'2023-08-21 08:23:45','2023-10-06 15:04:08',_binary '\0'),(188,'TSR Recycling',133,NULL,133,11,'2023-08-21 08:23:45','2023-10-06 15:04:08',_binary '\0'),(189,'Viehbrücke',111,NULL,111,11,'2023-08-21 08:23:45','2023-10-06 15:04:08',_binary '\0'),(190,'Vulkan Industriegebiet',120,NULL,120,11,'2023-08-21 08:23:46','2023-10-06 15:04:08',_binary '\0'),(191,'Weserbahnhof',132,NULL,132,11,'2023-08-21 08:23:46','2023-10-06 15:04:08',_binary '\0'),(192,'Weser-Petrol Holzhafen',134,NULL,134,11,'2023-08-21 08:23:46','2023-10-06 15:04:08',_binary '\0'),(193,'Weser-Petrol Kalihafen',134,NULL,134,11,'2023-08-21 08:23:46','2023-10-06 15:04:08',_binary '\0'),(194,'Wesertanking',135,NULL,135,11,'2023-08-21 08:23:46','2023-10-06 15:04:08',_binary '\0');
/*!40000 ALTER TABLE `berth` ENABLE KEYS */;
UNLOCK TABLES;
@@ -42,7 +40,7 @@ UNLOCK TABLES;
LOCK TABLES `participant` WRITE;
/*!40000 ALTER TABLE `participant` DISABLE KEYS */;
-INSERT INTO `participant` VALUES (1,'Schick Informatik','Gottlieb-Daimler-Str. 8','73614','Schorndorf',1,42,'2023-04-17 07:18:19','2023-08-24 07:07:02',_binary '\0'),(2,'Lotsenbrüderschaft Weser 1','','','',4,0,'2023-08-10 07:07:41',NULL,_binary '\0'),(3,'Bremer Schiffsmeldedienst','Hafenkopf II / Überseetor 20','28217','Bremen',1,0,'2023-08-10 07:11:10',NULL,_binary '\0'),(4,'BLG Cargo Logistics GmbH','','','',2,0,'2023-08-10 07:14:40',NULL,_binary '\0'),(5,'Schiffsmakler-Verband für Küsten und Seeschiffsbefrachter e.V.','','','',8,0,'2023-08-10 07:15:56',NULL,_binary '\0'),(6,'RMS Rhenus Maritime Services GmbH','','','',8,0,'2023-08-10 07:19:29',NULL,_binary '\0'),(7,'J.MÜLLER Weser GmbH & Co. KG','','','',10,0,'2023-08-10 07:21:43','2023-08-10 08:47:59',_binary '\0'),(8,'Schiffahrtskontor Detra GmbH & Co.KG','','','',8,0,'2023-08-10 07:23:04',NULL,_binary '\0'),(9,'Boluda Deutschland GmbH','','','',64,0,'2023-08-10 07:24:18',NULL,_binary '\0'),(10,'Weserport GmbH','','','',10,0,'2023-08-10 07:26:42','2023-08-10 08:48:19',_binary '\0'),(11,'Port Authority Bremen','','','',32,0,'2023-08-10 07:28:11',NULL,_binary '\0'),(12,'Nordenia Frachtkontor GmbH','','','',8,0,'2023-08-21 06:52:04',NULL,_binary '\0'),(15,'Extern','','','',0,0,'2023-08-21 06:55:18',NULL,_binary '\0'),(16,'FESTMA Vertäugesellschaft mbH','','','',16,0,'2023-08-21 06:57:23',NULL,_binary '\0'),(110,'Avangard',NULL,NULL,NULL,2,0,'2023-08-21 08:23:35','2023-08-21 10:04:21',_binary '\0'),(111,'Bremenports',NULL,NULL,NULL,2,0,'2023-08-21 08:23:35','2023-08-21 10:04:21',_binary '\0'),(112,'Bremer Holzwerke',NULL,NULL,NULL,2,0,'2023-08-21 08:23:36','2023-08-21 10:04:21',_binary '\0'),(113,'Egerland',NULL,NULL,NULL,2,0,'2023-08-21 08:23:36','2023-08-21 10:04:21',_binary '\0'),(114,'Müller J. Bremen',NULL,NULL,NULL,2,0,'2023-08-21 08:23:37','2023-08-21 10:04:21',_binary '\0'),(115,'Griepe',NULL,NULL,NULL,2,0,'2023-08-21 08:23:37','2023-08-21 10:04:21',_binary '\0'),(116,'Mseven Real Estate',NULL,NULL,NULL,2,0,'2023-08-21 08:23:37','2023-08-21 10:04:21',_binary '\0'),(117,'Hansa Landhandel',NULL,NULL,NULL,2,0,'2023-08-21 08:23:38','2023-08-21 10:04:21',_binary '\0'),(118,'Hansa Melasse',NULL,NULL,NULL,2,0,'2023-08-21 08:23:38','2023-08-21 10:04:21',_binary '\0'),(119,'Hansa-Mühle',NULL,NULL,NULL,2,0,'2023-08-21 08:23:38','2023-08-21 10:04:21',_binary '\0'),(120,'Heidelberger Sand Und Kies Gmbh',NULL,NULL,NULL,2,0,'2023-08-21 08:23:38','2023-08-21 10:04:21',_binary '\0'),(121,'HGM',NULL,NULL,NULL,2,0,'2023-08-21 08:23:39','2023-08-21 10:04:21',_binary '\0'),(122,'Kap-Horn Logistics Gmbh',NULL,NULL,NULL,2,0,'2023-08-21 08:23:39','2023-08-21 10:04:21',_binary '\0'),(123,'Bremer Recycling Kontor',NULL,NULL,NULL,2,0,'2023-08-21 08:23:39','2023-08-21 10:04:21',_binary '\0'),(124,'GHK',NULL,NULL,NULL,2,0,'2023-08-21 08:23:40','2023-08-21 10:04:21',_binary '\0'),(125,'Kraftwerk Farge Engie Gmbh & Co. KG',NULL,NULL,NULL,2,0,'2023-08-21 08:23:40','2023-08-21 10:04:21',_binary '\0'),(126,'Swb Erzeugung',NULL,NULL,NULL,2,0,'2023-08-21 08:23:40','2023-08-21 10:04:21',_binary '\0'),(127,'Mibau',NULL,NULL,NULL,2,0,'2023-08-21 08:23:41','2023-08-21 10:04:21',_binary '\0'),(128,'SWG',NULL,NULL,NULL,2,0,'2023-08-21 08:23:41','2023-08-21 10:04:21',_binary '\0'),(129,'Umweltschutz Nord Ganderkesee',NULL,NULL,NULL,2,0,'2023-08-21 08:23:42','2023-08-21 10:04:21',_binary '\0'),(130,'Nehlsen Industrieservice Gmbh & Co. KG',NULL,NULL,NULL,2,0,'2023-08-21 08:23:42','2023-08-21 10:04:21',_binary '\0'),(131,'Rolandmühle',NULL,NULL,NULL,2,0,'2023-08-21 08:23:42','2023-08-21 10:04:21',_binary '\0'),(132,'Wfb',NULL,NULL,NULL,2,0,'2023-08-21 08:23:43','2023-08-21 10:04:21',_binary '\0'),(133,'TSR',NULL,NULL,NULL,2,0,'2023-08-21 08:23:45','2023-08-21 10:04:21',_binary '\0'),(134,'Weser-Petrol',NULL,NULL,NULL,2,0,'2023-08-21 08:23:46','2023-08-21 10:04:21',_binary '\0'),(135,'Wesertanking',NULL,NULL,NULL,2,0,'2023-08-21 08:23:46','2023-08-21 10:04:21',_binary '\0');
+INSERT INTO `participant` VALUES (1,'Schick Informatik','Gottlieb-Daimler-Str. 8','73614','Schorndorf',1,42,'2023-04-17 07:18:19','2023-08-24 07:07:02',_binary '\0'),(2,'Lotsenbrüderschaft Weser 1','','','',4,0,'2023-08-10 07:07:41',NULL,_binary '\0'),(3,'Bremer Schiffsmeldedienst','Hafenkopf II / Überseetor 20','28217','Bremen',1,0,'2023-08-10 07:11:10',NULL,_binary '\0'),(4,'BLG Cargo Logistics GmbH','','','',2,0,'2023-08-10 07:14:40',NULL,_binary '\0'),(5,'Schiffsmakler-Verband für Küsten und Seeschiffsbefrachter e.V.','','','',8,0,'2023-08-10 07:15:56',NULL,_binary '\0'),(6,'RMS Rhenus Maritime Services GmbH','','','',8,1,'2023-08-10 07:19:29','2023-09-06 09:02:53',_binary '\0'),(7,'J.MÜLLER Weser GmbH & Co. KG','','','',10,0,'2023-08-10 07:21:43','2023-08-10 08:47:59',_binary '\0'),(8,'Schiffahrtskontor Detra GmbH & Co.KG','','','',8,0,'2023-08-10 07:23:04',NULL,_binary '\0'),(9,'Boluda Deutschland GmbH','','','',64,0,'2023-08-10 07:24:18',NULL,_binary '\0'),(10,'Weserport GmbH','','','',10,0,'2023-08-10 07:26:42','2023-08-10 08:48:19',_binary '\0'),(11,'Port Authority Bremen','','','',32,0,'2023-08-10 07:28:11',NULL,_binary '\0'),(12,'Nordenia Frachtkontor GmbH','','','',8,0,'2023-08-21 06:52:04',NULL,_binary '\0'),(15,'Extern','','','',0,0,'2023-08-21 06:55:18',NULL,_binary '\0'),(16,'FESTMA Vertäugesellschaft mbH','','','',16,0,'2023-08-21 06:57:23',NULL,_binary '\0'),(110,'Avangard',NULL,NULL,NULL,2,0,'2023-08-21 08:23:35','2023-08-21 10:04:21',_binary '\0'),(111,'Bremenports',NULL,NULL,NULL,2,0,'2023-08-21 08:23:35','2023-08-21 10:04:21',_binary '\0'),(112,'Bremer Holzwerke',NULL,NULL,NULL,2,0,'2023-08-21 08:23:36','2023-08-21 10:04:21',_binary '\0'),(113,'Egerland',NULL,NULL,NULL,2,0,'2023-08-21 08:23:36','2023-08-21 10:04:21',_binary '\0'),(114,'Müller J. Bremen',NULL,NULL,NULL,2,0,'2023-08-21 08:23:37','2023-08-21 10:04:21',_binary '\0'),(115,'Griepe',NULL,NULL,NULL,2,0,'2023-08-21 08:23:37','2023-08-21 10:04:21',_binary '\0'),(116,'Mseven Real Estate',NULL,NULL,NULL,2,0,'2023-08-21 08:23:37','2023-08-21 10:04:21',_binary '\0'),(117,'Hansa Landhandel',NULL,NULL,NULL,2,0,'2023-08-21 08:23:38','2023-08-21 10:04:21',_binary '\0'),(118,'Hansa Melasse',NULL,NULL,NULL,2,0,'2023-08-21 08:23:38','2023-08-21 10:04:21',_binary '\0'),(119,'Hansa-Mühle',NULL,NULL,NULL,2,0,'2023-08-21 08:23:38','2023-08-21 10:04:21',_binary '\0'),(120,'Heidelberger Sand Und Kies Gmbh',NULL,NULL,NULL,2,0,'2023-08-21 08:23:38','2023-08-21 10:04:21',_binary '\0'),(121,'HGM',NULL,NULL,NULL,2,0,'2023-08-21 08:23:39','2023-08-21 10:04:21',_binary '\0'),(122,'Kap-Horn Logistics Gmbh',NULL,NULL,NULL,2,0,'2023-08-21 08:23:39','2023-08-21 10:04:21',_binary '\0'),(123,'Bremer Recycling Kontor',NULL,NULL,NULL,2,0,'2023-08-21 08:23:39','2023-08-21 10:04:21',_binary '\0'),(124,'GHK',NULL,NULL,NULL,2,0,'2023-08-21 08:23:40','2023-08-21 10:04:21',_binary '\0'),(125,'Kraftwerk Farge Engie Gmbh & Co. KG',NULL,NULL,NULL,2,0,'2023-08-21 08:23:40','2023-08-21 10:04:21',_binary '\0'),(126,'Swb Erzeugung',NULL,NULL,NULL,2,0,'2023-08-21 08:23:40','2023-08-21 10:04:21',_binary '\0'),(127,'Mibau',NULL,NULL,NULL,2,0,'2023-08-21 08:23:41','2023-08-21 10:04:21',_binary '\0'),(128,'SWG',NULL,NULL,NULL,2,0,'2023-08-21 08:23:41','2023-08-21 10:04:21',_binary '\0'),(129,'Umweltschutz Nord Ganderkesee',NULL,NULL,NULL,2,0,'2023-08-21 08:23:42','2023-08-21 10:04:21',_binary '\0'),(130,'Nehlsen Industrieservice Gmbh & Co. KG',NULL,NULL,NULL,2,0,'2023-08-21 08:23:42','2023-08-21 10:04:21',_binary '\0'),(131,'Rolandmühle',NULL,NULL,NULL,2,0,'2023-08-21 08:23:42','2023-08-21 10:04:21',_binary '\0'),(132,'Wfb',NULL,NULL,NULL,2,0,'2023-08-21 08:23:43','2023-08-21 10:04:21',_binary '\0'),(133,'TSR',NULL,NULL,NULL,2,0,'2023-08-21 08:23:45','2023-08-21 10:04:21',_binary '\0'),(134,'Weser-Petrol',NULL,NULL,NULL,2,0,'2023-08-21 08:23:46','2023-08-21 10:04:21',_binary '\0'),(135,'Wesertanking',NULL,NULL,NULL,2,0,'2023-08-21 08:23:46','2023-08-21 10:04:21',_binary '\0'),(136,'TEST_BSMD','Überseetor 20','28217','Bremen',127,0,'2023-10-04 11:54:36',NULL,_binary '\0');
/*!40000 ALTER TABLE `participant` ENABLE KEYS */;
UNLOCK TABLES;
@@ -81,7 +79,7 @@ UNLOCK TABLES;
LOCK TABLES `ship` WRITE;
/*!40000 ALTER TABLE `ship` DISABLE KEYS */;
-INSERT INTO `ship` VALUES (1,'Dicke Berta',1234567,'DEBE',1,100,20,_binary '\0',NULL,NULL,'2023-06-27 10:43:02',NULL,_binary '\0'),(2,'Maersk Neston',9632167,'9V3532',1,210.07,30.2,_binary '\0',NULL,NULL,'2023-07-27 12:34:13',NULL,_binary '\0'),(3,'AFRICAN HALCYON',9343613,NULL,NULL,177.13,28.4,_binary '\0',NULL,NULL,'2023-08-24 10:41:56',NULL,_binary '\0'),(4,'AMIKO',9125669,NULL,NULL,99.98,16.5,_binary '\0',NULL,NULL,'2023-08-24 10:42:17',NULL,_binary '\0'),(5,'ARKLOW BEACON',9638795,NULL,NULL,119.49,14.99,_binary '\0',NULL,NULL,'2023-08-24 10:42:17',NULL,_binary '\0'),(6,'FWN ATLANTIDE',9535620,NULL,NULL,145.65,18.25,_binary '\0',NULL,NULL,'2023-08-24 10:42:17',NULL,_binary '\0'),(7,'IONIAN SPIRIT',9747235,NULL,NULL,179.9,30,_binary '\0',NULL,NULL,'2023-08-24 10:42:17',NULL,_binary '\0'),(8,'IRMA',9180396,NULL,NULL,199.9,23.6,_binary '\0',NULL,NULL,'2023-08-24 10:42:17',NULL,_binary '\0'),(9,'JANA',9330185,NULL,NULL,69.34,12,_binary '\0',NULL,NULL,'2023-08-24 10:42:18',NULL,_binary '\0'),(10,'MEDI PERTH',9804552,NULL,NULL,199.99,32.24,_binary '\0',NULL,NULL,'2023-08-24 10:42:18',NULL,_binary '\0'),(11,'S NEPTUNE',9634892,NULL,NULL,169.99,27,_binary '\0',NULL,NULL,'2023-08-24 10:42:18',NULL,_binary '\0'),(12,'WESER STAHL',9186687,NULL,NULL,192,32.26,_binary '\0',NULL,NULL,'2023-08-24 10:42:18',NULL,_binary '\0');
+INSERT INTO `ship` VALUES (1,'Dicke Berta',1234567,'DEBE',1,100,20,_binary '\0',NULL,NULL,'2023-06-27 10:43:02',NULL,_binary '\0'),(2,'Maersk Neston',9632167,'9V3532',1,210.07,30.2,_binary '\0',NULL,NULL,'2023-07-27 12:34:13',NULL,_binary '\0'),(3,'AFRICAN HALCYON',9343613,NULL,NULL,177.13,28.4,_binary '\0',NULL,NULL,'2023-08-24 10:41:56',NULL,_binary '\0'),(4,'AMIKO',9125669,NULL,NULL,99.98,16.5,_binary '\0',NULL,NULL,'2023-08-24 10:42:17',NULL,_binary '\0'),(5,'ARKLOW BEACON',9638795,NULL,NULL,119.49,14.99,_binary '\0',NULL,NULL,'2023-08-24 10:42:17',NULL,_binary '\0'),(6,'FWN ATLANTIDE',9535620,NULL,NULL,145.65,18.25,_binary '\0',NULL,NULL,'2023-08-24 10:42:17',NULL,_binary '\0'),(7,'IONIAN SPIRIT',9747235,NULL,NULL,179.9,30,_binary '\0',NULL,NULL,'2023-08-24 10:42:17',NULL,_binary '\0'),(8,'IRMA',9180396,NULL,NULL,199.9,23.6,_binary '\0',NULL,NULL,'2023-08-24 10:42:17',NULL,_binary '\0'),(9,'JANA',9330185,NULL,NULL,69.34,12,_binary '\0',NULL,NULL,'2023-08-24 10:42:18',NULL,_binary '\0'),(10,'MEDI PERTH',9804552,NULL,NULL,199.99,32.24,_binary '\0',NULL,NULL,'2023-08-24 10:42:18',NULL,_binary '\0'),(11,'S NEPTUNE',9634892,NULL,NULL,169.99,27,_binary '\0',NULL,NULL,'2023-08-24 10:42:18',NULL,_binary '\0'),(12,'WESER STAHL',9186687,NULL,NULL,192,32.26,_binary '\0',NULL,NULL,'2023-08-24 10:42:18',NULL,_binary '\0'),(13,'BOTHNIABORG',9267728,'PBIO',NULL,153.05,21.8,_binary '\0',NULL,NULL,'2023-10-04 11:52:32',NULL,_binary '\0');
/*!40000 ALTER TABLE `ship` ENABLE KEYS */;
UNLOCK TABLES;
@@ -91,7 +89,7 @@ UNLOCK TABLES;
LOCK TABLES `shipcall` WRITE;
/*!40000 ALTER TABLE `shipcall` DISABLE KEYS */;
-INSERT INTO `shipcall` VALUES (3,7,1,'2023-09-21 03:00:00','43B','2023-08-25 12:17:16',177,177,_binary '',_binary '',0,_binary '\0',_binary '',_binary '',_binary '',7.5,NULL,NULL,_binary '\0',3,_binary '',_binary '\0',_binary '\0','2023-06-27 11:03:28','2023-09-04 08:13:15'),(4,3,2,'2023-09-24 12:22:20','43','2023-09-01 02:00:00',184,184,_binary '',_binary '',2,_binary '\0',_binary '\0',_binary '\0',_binary '\0',6.35,NULL,NULL,_binary '\0',1,_binary '\0',_binary '',_binary '\0','2023-07-27 12:36:49','2023-09-04 08:13:15'),(5,1,1,'2023-07-23 07:18:19','43B',NULL,NULL,NULL,_binary '\0',_binary '',0,_binary '\0',_binary '',NULL,NULL,NULL,NULL,NULL,_binary '\0',2,NULL,NULL,NULL,'2023-08-11 15:11:50',NULL),(6,1,1,'2023-07-23 07:18:19','43B',NULL,NULL,NULL,_binary '\0',_binary '',0,_binary '\0',_binary '',NULL,NULL,NULL,NULL,NULL,_binary '\0',2,NULL,NULL,NULL,'2023-08-11 15:11:53',NULL),(7,1,1,'2023-07-23 07:18:19','43B',NULL,NULL,NULL,_binary '\0',_binary '',0,_binary '\0',_binary '',NULL,NULL,NULL,NULL,NULL,_binary '\0',2,NULL,NULL,NULL,'2023-08-13 12:12:34',NULL),(8,1,1,'2023-07-23 07:18:19','43B',NULL,NULL,NULL,_binary '\0',_binary '',0,_binary '\0',_binary '',NULL,NULL,NULL,NULL,NULL,_binary '\0',2,NULL,NULL,NULL,'2023-08-13 12:14:52',NULL),(9,1,1,'2023-07-23 07:18:19','43B',NULL,NULL,NULL,_binary '\0',_binary '',0,_binary '\0',_binary '',NULL,NULL,NULL,NULL,NULL,_binary '\0',2,NULL,NULL,NULL,'2023-08-13 12:17:09',NULL),(10,4,1,'2023-09-11 10:00:00','43B','2023-08-25 12:26:14',146,146,_binary '\0',_binary '',0,_binary '\0',_binary '\0',_binary '',_binary '\0',4.4,NULL,NULL,_binary '',3,_binary '\0',_binary '\0',_binary '\0','2023-08-14 07:55:48','2023-09-04 08:14:36'),(11,1,1,'2023-07-23 07:18:19','43B',NULL,NULL,NULL,_binary '\0',_binary '',0,_binary '\0',_binary '',NULL,NULL,NULL,NULL,NULL,_binary '\0',2,NULL,NULL,NULL,'2023-08-18 09:14:13',NULL),(12,1,1,'2023-07-23 07:18:19','43B',NULL,NULL,NULL,_binary '\0',_binary '',0,_binary '\0',_binary '',NULL,NULL,NULL,NULL,NULL,_binary '\0',2,NULL,NULL,NULL,'2023-08-18 09:14:20',NULL),(13,1,1,'2023-07-23 07:18:19','43B',NULL,NULL,NULL,_binary '\0',_binary '',0,_binary '\0',_binary '',NULL,NULL,NULL,NULL,NULL,_binary '\0',2,NULL,NULL,NULL,'2023-08-18 09:14:45',NULL),(14,1,1,'2023-07-23 07:18:19','43B',NULL,NULL,NULL,_binary '\0',_binary '',0,_binary '\0',_binary '',NULL,NULL,NULL,NULL,NULL,_binary '\0',2,NULL,NULL,NULL,'2023-08-18 09:17:42',NULL),(15,1,1,'2023-07-23 07:18:19','43B',NULL,NULL,NULL,_binary '\0',_binary '',0,_binary '\0',_binary '',NULL,NULL,NULL,NULL,NULL,_binary '\0',2,NULL,NULL,NULL,'2023-08-18 09:17:51',NULL),(16,1,3,'2023-09-21 16:19:14','Test','2023-08-26 16:18:54',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,4,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'0001-01-01 00:00:00','2023-09-04 13:05:33'),(17,7,1,'2023-09-01 03:00:01','','2023-08-25 12:20:05',177,177,_binary '',_binary '',NULL,_binary '',_binary '\0',_binary '\0',_binary '\0',7.5,'2023-08-31 23:00:01','2023-09-01 05:00:01',_binary '\0',2,_binary '\0',_binary '\0',_binary '\0','2023-08-24 12:20:04',NULL),(18,3,2,'2023-09-25 20:44:21','','2023-09-01 03:00:28',184,184,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'2023-08-27 20:45:06','2023-09-04 08:14:35');
+INSERT INTO `shipcall` VALUES (3,7,1,'2023-11-21 03:00:00','43B','2023-08-25 12:17:16',178,177,_binary '',_binary '',0,_binary '\0',_binary '',_binary '',_binary '',7.5,NULL,NULL,_binary '\0',3,_binary '',_binary '\0',_binary '\0',NULL,NULL,'2023-06-27 11:03:28','2023-10-04 10:33:14'),(4,3,2,'2023-11-25 12:22:20','43','2023-10-02 02:00:00',2,181,_binary '',_binary '',2,_binary '\0',_binary '\0',_binary '\0',_binary '\0',6.35,NULL,NULL,_binary '\0',1,_binary '\0',_binary '',_binary '\0',NULL,NULL,'2023-07-27 12:36:49','2023-10-06 12:57:36'),(5,1,1,'2023-07-23 07:18:19','43B',NULL,NULL,NULL,_binary '\0',_binary '',0,_binary '\0',_binary '',NULL,NULL,NULL,NULL,NULL,_binary '\0',2,NULL,NULL,NULL,NULL,NULL,'2023-08-11 15:11:50',NULL),(6,1,1,'2023-07-23 07:18:19','43B',NULL,NULL,NULL,_binary '\0',_binary '',0,_binary '\0',_binary '',NULL,NULL,NULL,NULL,NULL,_binary '\0',2,NULL,NULL,NULL,NULL,NULL,'2023-08-11 15:11:53',NULL),(7,1,1,'2023-07-23 07:18:19','43B',NULL,NULL,NULL,_binary '\0',_binary '',0,_binary '\0',_binary '',NULL,NULL,NULL,NULL,NULL,_binary '\0',2,NULL,NULL,NULL,NULL,NULL,'2023-08-13 12:12:34',NULL),(8,1,1,'2023-07-23 07:18:19','43B',NULL,NULL,NULL,_binary '\0',_binary '',0,_binary '\0',_binary '',NULL,NULL,NULL,NULL,NULL,_binary '\0',2,NULL,NULL,NULL,NULL,NULL,'2023-08-13 12:14:52',NULL),(9,1,1,'2023-07-23 07:18:19','43B',NULL,NULL,NULL,_binary '\0',_binary '',0,_binary '\0',_binary '',NULL,NULL,NULL,NULL,NULL,_binary '\0',2,NULL,NULL,NULL,NULL,NULL,'2023-08-13 12:17:09',NULL),(10,4,1,'2023-09-11 10:00:00','43B','2023-08-25 12:26:14',146,146,_binary '\0',_binary '',0,_binary '\0',_binary '\0',_binary '',_binary '\0',4.4,NULL,NULL,_binary '',3,_binary '\0',_binary '\0',_binary '\0',NULL,NULL,'2023-08-14 07:55:48','2023-09-04 08:14:36'),(11,1,1,'2023-07-23 07:18:19','43B',NULL,NULL,NULL,_binary '\0',_binary '',0,_binary '\0',_binary '',NULL,NULL,NULL,NULL,NULL,_binary '\0',2,NULL,NULL,NULL,NULL,NULL,'2023-08-18 09:14:13',NULL),(12,1,1,'2023-07-23 07:18:19','43B',NULL,NULL,NULL,_binary '\0',_binary '',0,_binary '\0',_binary '',NULL,NULL,NULL,NULL,NULL,_binary '\0',2,NULL,NULL,NULL,NULL,NULL,'2023-08-18 09:14:20',NULL),(13,1,1,'2023-07-23 07:18:19','43B',NULL,NULL,NULL,_binary '\0',_binary '',0,_binary '\0',_binary '',NULL,NULL,NULL,NULL,NULL,_binary '\0',2,NULL,NULL,NULL,NULL,NULL,'2023-08-18 09:14:45',NULL),(14,1,1,'2023-07-23 07:18:19','43B',NULL,NULL,NULL,_binary '\0',_binary '',0,_binary '\0',_binary '',NULL,NULL,NULL,NULL,NULL,_binary '\0',2,NULL,NULL,NULL,NULL,NULL,'2023-08-18 09:17:42',NULL),(15,1,1,'2023-07-23 07:18:19','43B',NULL,NULL,NULL,_binary '\0',_binary '',0,_binary '\0',_binary '',NULL,NULL,NULL,NULL,NULL,_binary '\0',2,NULL,NULL,NULL,NULL,NULL,'2023-08-18 09:17:51',NULL),(16,1,3,'2023-10-21 16:19:14','Test','2023-08-26 16:18:54',145,143,_binary '',_binary '',NULL,_binary '',NULL,_binary '',NULL,4,NULL,NULL,_binary '',2,NULL,_binary '',NULL,NULL,NULL,'0001-01-01 00:00:00','2023-10-04 08:53:44'),(17,7,1,'2023-10-01 03:00:01','','2023-08-25 12:20:05',177,177,_binary '',_binary '',NULL,_binary '',_binary '\0',_binary '\0',_binary '\0',7.5,'2023-08-31 23:00:01','2023-09-01 05:00:01',_binary '\0',2,_binary '\0',_binary '\0',_binary '\0',NULL,NULL,'2023-08-24 12:20:04','2023-09-28 08:59:19'),(18,3,2,'2023-10-25 20:44:21','','2023-11-01 03:00:28',184,184,_binary '',_binary '',NULL,_binary '\0',NULL,NULL,NULL,2,NULL,NULL,NULL,NULL,NULL,_binary '\0',NULL,NULL,NULL,'2023-08-27 20:45:06','2023-10-04 12:27:56'),(19,5,1,'2023-09-30 16:01:21','','2023-09-23 16:01:44',146,146,NULL,NULL,NULL,NULL,NULL,NULL,NULL,8.5,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'2023-09-22 16:01:53',NULL),(20,9,1,'2023-10-20 07:52:45',NULL,'2023-10-07 07:52:56',140,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'2023-10-06 07:52:56',NULL),(21,13,1,'2023-10-13 10:00:24',NULL,'2023-10-07 13:36:56',176,176,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'2023-10-06 13:36:55',NULL),(22,13,2,'2023-10-06 13:37:42',NULL,'2023-10-20 11:11:28',176,176,_binary '',_binary '\0',NULL,_binary '',NULL,NULL,NULL,5,'2023-10-20 09:00:03','2023-10-20 13:00:10',_binary '',2,NULL,_binary '',_binary '\0',NULL,NULL,'2023-10-06 13:37:42','2023-10-06 13:54:43');
/*!40000 ALTER TABLE `shipcall` ENABLE KEYS */;
UNLOCK TABLES;
@@ -101,7 +99,7 @@ UNLOCK TABLES;
LOCK TABLES `shipcall_participant_map` WRITE;
/*!40000 ALTER TABLE `shipcall_participant_map` DISABLE KEYS */;
-INSERT INTO `shipcall_participant_map` VALUES (1,3,2,'2023-08-11 15:01:23',NULL),(3,9,2,'2023-08-13 12:17:17',NULL),(4,9,4,'2023-08-13 12:17:18',NULL),(24,10,3,'2023-08-14 08:48:30',NULL),(26,10,9,'2023-08-14 09:03:29',NULL),(28,10,7,'2023-08-21 14:36:44',NULL),(29,10,16,'2023-08-21 14:36:44',NULL),(30,10,2,'2023-08-21 14:36:44',NULL),(32,10,11,'2023-08-21 14:36:44',NULL),(33,10,1,'2023-08-21 14:36:44',NULL),(34,3,3,'2023-08-21 14:45:52',NULL),(35,3,11,'2023-08-21 14:45:52',NULL),(43,16,3,'2023-08-21 16:19:13',NULL),(44,16,11,'2023-08-21 16:19:13',NULL),(45,16,1,'2023-08-21 16:19:13',NULL),(48,3,16,'2023-08-23 16:58:54',NULL),(49,3,9,'2023-08-23 16:58:54',NULL),(50,4,10,'2023-08-24 10:01:40',NULL),(51,4,16,'2023-08-24 10:01:40',NULL),(52,4,2,'2023-08-24 10:01:40',NULL),(53,4,10,'2023-08-24 10:01:40',NULL),(54,4,9,'2023-08-24 10:01:40',NULL),(55,4,3,'2023-08-24 10:01:40',NULL),(56,4,11,'2023-08-24 10:01:40',NULL),(57,4,1,'2023-08-24 10:01:40',NULL),(58,3,1,'2023-08-24 10:42:56',NULL),(59,3,4,'2023-08-24 12:17:16',NULL),(60,17,12,'2023-08-24 12:20:04',NULL),(61,17,16,'2023-08-24 12:20:04',NULL),(62,17,2,'2023-08-24 12:20:04',NULL),(63,17,4,'2023-08-24 12:20:04',NULL),(64,17,9,'2023-08-24 12:20:04',NULL),(65,17,3,'2023-08-24 12:20:04',NULL),(66,17,11,'2023-08-24 12:20:04',NULL),(67,17,1,'2023-08-24 12:20:04',NULL),(68,18,10,'2023-08-27 20:45:06',NULL),(69,18,16,'2023-08-27 20:45:06',NULL),(70,18,2,'2023-08-27 20:45:06',NULL),(71,18,10,'2023-08-27 20:45:06',NULL),(72,18,9,'2023-08-27 20:45:06',NULL),(73,18,3,'2023-08-27 20:45:06',NULL),(74,18,11,'2023-08-27 20:45:06',NULL),(75,18,1,'2023-08-27 20:45:06',NULL),(79,16,2,'2023-09-04 10:31:45',NULL),(81,3,7,'2023-09-04 11:45:26',NULL);
+INSERT INTO `shipcall_participant_map` VALUES (3,9,2,'2023-08-13 12:17:17',NULL),(4,9,4,'2023-08-13 12:17:18',NULL),(24,10,3,'2023-08-14 08:48:30',NULL),(26,10,9,'2023-08-14 09:03:29',NULL),(28,10,7,'2023-08-21 14:36:44',NULL),(29,10,16,'2023-08-21 14:36:44',NULL),(30,10,2,'2023-08-21 14:36:44',NULL),(32,10,11,'2023-08-21 14:36:44',NULL),(33,10,1,'2023-08-21 14:36:44',NULL),(34,3,3,'2023-08-21 14:45:52',NULL),(35,3,11,'2023-08-21 14:45:52',NULL),(43,16,3,'2023-08-21 16:19:13',NULL),(44,16,11,'2023-08-21 16:19:13',NULL),(45,16,1,'2023-08-21 16:19:13',NULL),(55,4,3,'2023-08-24 10:01:40',NULL),(56,4,11,'2023-08-24 10:01:40',NULL),(57,4,1,'2023-08-24 10:01:40',NULL),(58,3,1,'2023-08-24 10:42:56',NULL),(65,17,3,'2023-08-24 12:20:04',NULL),(66,17,11,'2023-08-24 12:20:04',NULL),(67,17,1,'2023-08-24 12:20:04',NULL),(73,18,3,'2023-08-27 20:45:06',NULL),(74,18,11,'2023-08-27 20:45:06',NULL),(75,18,1,'2023-08-27 20:45:06',NULL),(79,16,2,'2023-09-04 10:31:45',NULL),(82,16,6,'2023-09-21 09:23:18',NULL),(83,19,12,'2023-09-22 16:01:53',NULL),(84,19,3,'2023-09-22 16:01:53',NULL),(85,19,11,'2023-09-22 16:01:53',NULL),(86,19,1,'2023-09-22 16:01:53',NULL),(96,4,10,'2023-09-25 11:41:42',NULL),(97,16,16,'2023-09-28 15:06:26',NULL),(98,16,115,'2023-09-28 15:06:26',NULL),(99,16,9,'2023-09-28 15:06:26',NULL),(100,17,6,'2023-09-29 12:56:53',NULL),(106,3,6,'2023-10-04 10:23:22',NULL),(107,18,136,'2023-10-04 12:27:28',NULL),(108,18,136,'2023-10-04 12:27:28',NULL),(110,18,136,'2023-10-04 12:27:28',NULL),(111,18,16,'2023-10-04 12:28:30',NULL),(112,18,2,'2023-10-04 12:28:30',NULL),(113,18,128,'2023-10-04 12:28:30',NULL),(114,18,9,'2023-10-04 12:28:30',NULL),(115,20,8,'2023-10-06 07:52:56',NULL),(116,20,3,'2023-10-06 07:52:56',NULL),(117,20,11,'2023-10-06 07:52:56',NULL),(118,20,1,'2023-10-06 07:52:56',NULL),(120,21,3,'2023-10-06 13:36:55',NULL),(121,21,11,'2023-10-06 13:36:55',NULL),(122,21,1,'2023-10-06 13:36:55',NULL),(123,22,136,'2023-10-06 13:37:42',NULL),(124,22,3,'2023-10-06 13:37:42',NULL),(125,22,11,'2023-10-06 13:37:42',NULL),(126,22,1,'2023-10-06 13:37:42',NULL),(127,21,10,'2023-10-06 13:45:22',NULL);
/*!40000 ALTER TABLE `shipcall_participant_map` ENABLE KEYS */;
UNLOCK TABLES;
@@ -120,7 +118,7 @@ UNLOCK TABLES;
LOCK TABLES `times` WRITE;
/*!40000 ALTER TABLE `times` DISABLE KEYS */;
-INSERT INTO `times` VALUES (1,'2023-05-18 07:18:19',NULL,'2023-05-18 09:18:19',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,3,1,'2023-06-27 11:05:01','2023-06-27 11:05:30',NULL,NULL,NULL),(2,'2023-08-23 09:26:22',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'test',16,1,'0001-01-01 00:00:00',NULL,NULL,NULL,NULL),(3,NULL,NULL,NULL,NULL,'2023-08-24 09:32:18',NULL,NULL,NULL,NULL,NULL,'',16,1,'2023-08-23 09:32:21',NULL,NULL,NULL,NULL),(4,'2023-08-19 07:05:29',NULL,'2023-09-07 09:00:00',NULL,NULL,NULL,NULL,NULL,NULL,NULL,'Lotsenbemerkung von M.B.',3,2,'2023-08-24 07:05:39','2023-09-04 10:30:58',NULL,NULL,NULL),(5,'2023-08-19 08:30:30',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'früher wird das nichts',3,16,'2023-08-24 07:10:43','2023-08-24 07:11:04',NULL,NULL,NULL),(6,NULL,NULL,'2023-09-01 02:00:00',NULL,NULL,NULL,NULL,NULL,NULL,NULL,'VB Blumenthal',4,9,'2023-08-24 12:29:48','2023-08-24 12:52:43',NULL,NULL,NULL),(7,'2023-09-01 03:30:00',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'VB Blexen, VB Blumenthal, \r\nFrüher geht es nicht',17,9,'2023-08-24 12:53:40','2023-08-24 12:55:20',NULL,NULL,NULL),(8,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'Keine Schlepporder',10,9,'2023-08-24 12:58:18',NULL,NULL,NULL,NULL),(9,NULL,NULL,'2023-09-01 02:00:01',NULL,NULL,NULL,NULL,NULL,NULL,NULL,'',4,16,'2023-08-24 13:00:16',NULL,NULL,NULL,NULL),(10,'2023-09-01 10:00:32',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'',10,16,'2023-08-24 13:00:39',NULL,NULL,NULL,NULL),(11,NULL,NULL,'2023-09-01 02:00:39',NULL,NULL,NULL,NULL,NULL,NULL,NULL,'',4,2,'2023-08-24 13:01:45',NULL,NULL,NULL,NULL),(12,'2023-09-01 03:00:52',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'',17,2,'2023-08-24 13:01:59',NULL,NULL,NULL,NULL),(13,'2023-09-01 10:00:10',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'',10,2,'2023-08-24 13:02:16','2023-09-04 09:11:45',NULL,NULL,NULL),(14,NULL,NULL,'2023-09-01 02:00:07',NULL,NULL,NULL,NULL,NULL,NULL,NULL,'',4,11,'2023-08-24 13:03:14',NULL,NULL,NULL,NULL),(15,'2023-09-01 03:00:20',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'',17,11,'2023-08-24 13:03:27',NULL,NULL,NULL,NULL),(16,'2023-09-01 10:00:34',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'',10,11,'2023-08-24 13:03:39',NULL,NULL,NULL,NULL),(17,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'',17,4,'2023-08-24 13:05:11','2023-08-24 13:05:57',NULL,NULL,NULL),(18,'2023-09-01 02:00:35',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'',4,10,'2023-08-24 13:06:45',NULL,NULL,NULL,NULL),(19,'2023-09-01 03:00:41',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'',17,10,'2023-08-24 13:07:48',NULL,NULL,NULL,NULL),(20,NULL,NULL,'2023-09-01 02:00:02',NULL,NULL,NULL,NULL,NULL,NULL,NULL,'',4,10,'2023-08-24 13:08:10',NULL,NULL,NULL,NULL),(21,'2023-09-01 10:00:17',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'',10,10,'2023-08-24 13:08:24',NULL,NULL,NULL,NULL),(22,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'Klärung abwarten => 0300/0330?',17,16,'2023-08-24 13:08:53','2023-08-24 13:09:33',NULL,NULL,NULL),(23,NULL,NULL,'2023-09-01 03:00:43',NULL,NULL,NULL,NULL,NULL,NULL,NULL,'',18,11,'2023-08-27 20:45:49',NULL,NULL,NULL,NULL),(24,NULL,NULL,'2023-09-01 03:00:21',NULL,NULL,NULL,NULL,NULL,NULL,NULL,'',18,10,'2023-08-27 20:46:25',NULL,NULL,NULL,NULL),(25,'2023-09-01 13:23:12',_binary '','2023-09-03 03:00:51',NULL,NULL,NULL,NULL,NULL,NULL,NULL,'es geht nicht früher!',18,2,'2023-08-27 20:46:54','2023-09-01 13:25:39',NULL,NULL,NULL),(26,NULL,NULL,'2023-09-01 03:00:34',NULL,NULL,NULL,NULL,NULL,NULL,NULL,'',18,9,'2023-08-27 20:47:40',NULL,NULL,NULL,NULL),(27,NULL,NULL,'2023-09-01 03:00:00',NULL,NULL,NULL,NULL,NULL,NULL,NULL,'',18,16,'2023-08-27 20:48:05',NULL,NULL,NULL,NULL);
+INSERT INTO `times` VALUES (29,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'2023-10-01 07:30:15','2023-10-01 13:00:00','Bemerkung Terminal',4,10,'2023-09-21 07:30:22','2023-10-04 10:58:14',150,'Liegeplatz Info 1',_binary '\0',2),(30,'2023-09-22 08:18:49',NULL,'2023-09-23 11:18:56',NULL,NULL,NULL,'2023-09-21 06:00:00',_binary '',NULL,NULL,'2 tugs needed',4,2,'2023-09-21 08:19:39','2023-09-21 08:20:22',NULL,NULL,NULL,4),(32,'2023-09-28 14:57:43',NULL,NULL,NULL,NULL,NULL,'2023-09-28 14:57:47',NULL,NULL,NULL,'Test',17,2,'2023-09-28 14:57:53',NULL,NULL,NULL,NULL,4),(35,'2023-10-21 16:19:14',NULL,'2023-08-26 16:18:54',NULL,NULL,NULL,NULL,NULL,NULL,NULL,'Bemerkungen XX',16,1,'2023-09-28 15:06:42','2023-10-04 09:28:16',146,'XXXCXC',NULL,8),(36,'2023-11-02 03:00:28',NULL,'2023-11-05 04:00:28',NULL,NULL,NULL,NULL,NULL,NULL,NULL,'Abgehende Bemerkungen. \r\nMan kann inzwischen return drücken um in die nächste Zeile zu kommen.',18,1,'2023-09-29 12:57:39','2023-10-04 10:33:34',185,'Test',NULL,8),(38,'2023-11-21 03:00:00',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'Incoming info',3,1,'2023-10-04 10:23:46',NULL,NULL,'Test Liegeplatz info Incoming',NULL,8),(39,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'Kurze Info: nix',18,2,'2023-10-04 10:45:05',NULL,NULL,NULL,NULL,4),(40,NULL,NULL,'2023-10-02 02:00:00',NULL,NULL,NULL,NULL,NULL,NULL,NULL,'Test Terminal als Agentur normale info',4,10,'2023-10-04 10:59:08',NULL,150,'Test Terminal als Agentur Liegeplatz info',NULL,8),(41,NULL,NULL,'2023-11-01 03:00:28',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,18,136,'2023-10-04 12:27:28',NULL,184,'',NULL,8),(42,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'',18,136,'2023-10-05 09:01:48',NULL,140,'Test',_binary '',2),(43,NULL,NULL,'2023-10-20 11:11:28',NULL,NULL,NULL,NULL,NULL,NULL,NULL,'Test',22,136,'2023-10-06 13:54:43',NULL,NULL,'100-300',NULL,8);
/*!40000 ALTER TABLE `times` ENABLE KEYS */;
UNLOCK TABLES;
@@ -130,7 +128,7 @@ UNLOCK TABLES;
LOCK TABLES `user` WRITE;
/*!40000 ALTER TABLE `user` DISABLE KEYS */;
-INSERT INTO `user` VALUES (1,1,'Daniel','Schick','dani',NULL,NULL,'$2b$12$qfjw4b3XvGuu0t6HR8OYGOzF5b8gmC6PyIIBNbIXMXEayJunEEKmi','0815','2023-04-17 07:15:41','2023-08-11 11:11:34'),(2,1,'Londo','Mollari','Londo','l.mollari@centauri.gov','+01 555 324 2313','$2b$12$P7MkcbOzmp7Wxsl8Ip5tg.KvMlvQEdFZN6AoM1Ze54.kvjYZxSizy',NULL,'2023-06-27 08:34:55','2023-09-04 13:36:34'),(3,2,'Maik','Baudeck','maikb',NULL,NULL,'$2b$12$4SxGRlinOrpEVvqDZcE.wOusMZYsepdc6vj1vDpNhbPtApxU8VGPi','','2023-08-10 07:09:35','2023-08-11 11:11:55'),(4,3,'Christin','Hollmann','christinh',NULL,NULL,'$2b$12$ul0QJmcuUhktDYDjcyEpx.6yY1ieLdaCxZ6a3SFSuTq94IqK4Y/re','','2023-08-10 07:12:05','2023-08-11 11:10:33'),(5,3,'Bastian','Güttner','bastiang',NULL,NULL,'$2b$12$0oCX3c2WyMykmxMoLqmpNubke713xhYlEEQgnxBV6Fj/TaUn.3/U6','','2023-08-10 07:12:26','2023-08-11 11:11:13'),(6,3,'Benjamin','Wiese','benjaminw',NULL,NULL,'$2b$12$RRj32KdLIf3D7z7cVWFqa.yZM5.ODOS0HqU3rdCuFrJS8HJ/rtqwy','','2023-08-10 07:13:01','2023-08-11 11:11:16'),(7,1,'Sladjan','Veselinovic','sladjanv',NULL,NULL,'$2b$12$4DctoCbZwxTvE39lXNRzneQ2kb/lXlJ5wEZ1CGbbw.rGM3nuAYjpa','','2023-08-10 07:13:39','2023-08-11 11:11:45'),(8,1,'Kersten','Gevers','kersteng',NULL,NULL,'$2b$12$zKX8iLPnXRmp5wD1Yp8P7e..U9R0A4ytbiMjd.l.IGkMzahcHPNWq','','2023-08-10 07:13:59','2023-08-11 11:11:49'),(9,4,'Dirk','Brunnert','dirkb',NULL,NULL,'$2b$12$HTeq/Fdfse6oElk7DLsQae5dtvWJloee.VtBH.THsj2kdcxxBkCDW','','2023-08-10 07:15:01','2023-08-11 11:12:01'),(10,5,'Thorsten','Fischer','thorstenf',NULL,NULL,'$2b$12$NHEpTNHuKU4ruPRIfd9yc.yv5faHGemFfRI3TISniqM7QNqHiyZpK','','2023-08-10 07:16:20','2023-08-11 11:12:07'),(11,6,'Lisa','Friedhoff','lisaf',NULL,NULL,'$2b$12$DJKJHGrQwfY9pwzgFfPds.DHGsygHyV3KDs38Hq4AUHPPs3jBPH3y','','2023-08-10 07:19:52','2023-08-11 11:12:12'),(12,6,'Dario','Fritschi','dariof',NULL,NULL,'$2b$12$MwCVTMQkN6zCAzCsE572Ye.M0nRDQNld4AgorLVyWq.DcQEmAy5lu','','2023-08-10 07:20:11','2023-08-11 11:12:15'),(13,7,'Hergen','Hanke','hergenh',NULL,NULL,'$2b$12$MKb6BDRrTbNd0qg5BdAS.upzlqxcWOgU/VEafJKSuzE9JLIWCimq6','','2023-08-10 07:22:09','2023-08-11 11:12:24'),(14,8,'Hardy','Paasch','hardyp',NULL,NULL,'$2b$12$l1lE/UqnYnOvci.N4j3zBOz6HC0z87ovnO0n6BIZYO7VN8gj.qGey','','2023-08-10 07:23:25','2023-08-11 11:12:28'),(15,8,'Marc','Pagel','marcp',NULL,NULL,'$2b$12$UCVJKzqX92Z8xZJ4kK0BRuFXMRdqcaXaGmBrqnYWARdKlPvZvLUZq','','2023-08-10 07:23:41','2023-08-11 11:12:30'),(16,9,'Andreas','Peukert','andreasp',NULL,NULL,'$2b$12$jNmciJAVR6p0IflvAthmk.j0SoOBvFHwDiEDKUHfwJq7baRsKg/LG','','2023-08-10 07:24:37','2023-08-11 11:12:45'),(17,8,'Christina','Rachiele','christinar',NULL,NULL,'$2b$12$BCsVgPRuIWPuuor07lprF.klQxvF901O3AXUhRrBJoEvYIjNQ.HKS','','2023-08-10 07:25:05','2023-08-11 11:12:33'),(18,9,'Sonia','Rekawek','soniar',NULL,NULL,'$2b$12$uHCkH6gu13yqllXBibLFIOWOpvctMC7NmojtXqDd6xsLq7bmvNOMu','','2023-08-10 07:25:27','2023-08-11 11:12:48'),(19,6,'Frank','Roelfs','frankr',NULL,NULL,'$2b$12$cEQAhUe9VJV6uTkfOY6/R.oAVfmFZQ4vS5G6BqoNEyaVHtFRDtB56','','2023-08-10 07:26:04','2023-08-11 11:12:19'),(20,10,'Vera','Schliedermann','veras',NULL,NULL,'$2b$12$FKcitW6W1HPwd.cdkZLGLeTFuzjsEIrbiKInysAKN.RibZ4gVLZHi','','2023-08-10 07:27:01','2023-08-11 11:12:54'),(21,8,'Michael','Strudthoff','michaels',NULL,NULL,'$2b$12$doTiywWpkso1UWB5eiAW1eoACP6rN4UDVt7qFFdRFvhhWUXikCmS2','','2023-08-10 07:27:27','2023-08-11 11:12:37'),(22,4,'Volker','Viohl','volkerv',NULL,NULL,'$2b$12$.YavQbWNE4eJDQA.ZNSKROYvMPWifBXyMX0IL0H2z50M720fpfTJW','','2023-08-10 07:27:50','2023-08-11 11:12:04'),(23,11,'Frauke','Zabel','fraukez',NULL,NULL,'$2b$12$rawQg6Cjl1yECGm9DOG8degdWdD.nZjEgGp8eXO98nh11QV1sEEEO','','2023-08-10 07:28:33','2023-08-11 11:12:58'),(24,8,'Jan','Zierow','janz',NULL,NULL,'$2b$12$CbnjUT42cf0mkIAqAURg3OksP9G3brmsE2GQTECTZ4.cVuhPn5D2G','','2023-08-10 07:28:55','2023-08-11 11:12:39'),(25,12,'Berit','Güstrau','beritg',NULL,NULL,'$2b$12$g8WJTEWwsrtMyqpVW/GFVuzyRjB2/n0YJJyvBx.3l51YiVEUjEQYy','','2023-08-21 06:52:35',NULL),(26,15,'Ilknur','Colmorn','ilknurc',NULL,NULL,'$2b$12$tpEb0JQ8Li4YkPH28FeYk.1Jt2vK.TFn9SyhBKJ08gn7S5d8WYRlO','','2023-08-21 06:56:42',NULL),(27,16,'Horst','Imgram','horsti',NULL,NULL,'$2b$12$05NFPSaP78puAa8pL39KrOKTafs/TzWwr4YfV4/Vrdu90assvNFZa','','2023-08-21 06:57:58',NULL);
+INSERT INTO `user` VALUES (1,1,'Daniel','Schick','dani',NULL,NULL,'$2b$12$qfjw4b3XvGuu0t6HR8OYGOzF5b8gmC6PyIIBNbIXMXEayJunEEKmi','0815','2023-04-17 07:15:41','2023-08-11 11:11:34'),(2,1,'Londo','Mollari','Londo','l.mollari@centauri.gov','+01 555 324 2313','$2b$12$8r1oGQiWdiuQNoGbzm.z.OoCOc8.4YACN93k7ge7YDWKjQ8tPuTrm',NULL,'2023-06-27 08:34:55','2023-10-03 10:09:13'),(3,2,'Maik','Baudeck','maikb',NULL,NULL,'$2b$12$4SxGRlinOrpEVvqDZcE.wOusMZYsepdc6vj1vDpNhbPtApxU8VGPi','','2023-08-10 07:09:35','2023-08-11 11:11:55'),(4,3,'Christin','Hollmann','christinh',NULL,NULL,'$2b$12$evGJop3j19bNTkdg2GHrIeRedC7LG5SIHm8.hKhdUSrlXsp6sXBDG','','2023-08-10 07:12:05','2023-10-04 11:48:13'),(5,3,'Bastian','Güttner','bastiang',NULL,NULL,'$2b$12$0oCX3c2WyMykmxMoLqmpNubke713xhYlEEQgnxBV6Fj/TaUn.3/U6','','2023-08-10 07:12:26','2023-08-11 11:11:13'),(6,3,'Benjamin','Wiese','benjaminw',NULL,NULL,'$2b$12$RRj32KdLIf3D7z7cVWFqa.yZM5.ODOS0HqU3rdCuFrJS8HJ/rtqwy','','2023-08-10 07:13:01','2023-08-11 11:11:16'),(7,1,'Sladjan','Veselinovic','sladjanv',NULL,NULL,'$2b$12$4DctoCbZwxTvE39lXNRzneQ2kb/lXlJ5wEZ1CGbbw.rGM3nuAYjpa','','2023-08-10 07:13:39','2023-08-11 11:11:45'),(8,1,'Kersten','Gevers','kersteng',NULL,NULL,'$2b$12$zKX8iLPnXRmp5wD1Yp8P7e..U9R0A4ytbiMjd.l.IGkMzahcHPNWq','','2023-08-10 07:13:59','2023-08-11 11:11:49'),(9,4,'Dirk','Brunnert','dirkb',NULL,NULL,'$2b$12$HTeq/Fdfse6oElk7DLsQae5dtvWJloee.VtBH.THsj2kdcxxBkCDW','','2023-08-10 07:15:01','2023-08-11 11:12:01'),(10,5,'Thorsten','Fischer','thorstenf',NULL,NULL,'$2b$12$NHEpTNHuKU4ruPRIfd9yc.yv5faHGemFfRI3TISniqM7QNqHiyZpK','','2023-08-10 07:16:20','2023-08-11 11:12:07'),(11,6,'Lisa','Friedhoff','lisaf',NULL,NULL,'$2b$12$DJKJHGrQwfY9pwzgFfPds.DHGsygHyV3KDs38Hq4AUHPPs3jBPH3y','','2023-08-10 07:19:52','2023-08-11 11:12:12'),(12,6,'Dario','Fritschi','dariof',NULL,NULL,'$2b$12$MwCVTMQkN6zCAzCsE572Ye.M0nRDQNld4AgorLVyWq.DcQEmAy5lu','','2023-08-10 07:20:11','2023-08-11 11:12:15'),(13,7,'Hergen','Hanke','hergenh',NULL,NULL,'$2b$12$MKb6BDRrTbNd0qg5BdAS.upzlqxcWOgU/VEafJKSuzE9JLIWCimq6','','2023-08-10 07:22:09','2023-08-11 11:12:24'),(14,8,'Hardy','Paasch','hardyp',NULL,NULL,'$2b$12$l1lE/UqnYnOvci.N4j3zBOz6HC0z87ovnO0n6BIZYO7VN8gj.qGey','','2023-08-10 07:23:25','2023-08-11 11:12:28'),(15,8,'Marc','Pagel','marcp',NULL,NULL,'$2b$12$UCVJKzqX92Z8xZJ4kK0BRuFXMRdqcaXaGmBrqnYWARdKlPvZvLUZq','','2023-08-10 07:23:41','2023-08-11 11:12:30'),(16,9,'Andreas','Peukert','andreasp',NULL,NULL,'$2b$12$jNmciJAVR6p0IflvAthmk.j0SoOBvFHwDiEDKUHfwJq7baRsKg/LG','','2023-08-10 07:24:37','2023-08-11 11:12:45'),(17,8,'Christina','Rachiele','christinar',NULL,NULL,'$2b$12$BCsVgPRuIWPuuor07lprF.klQxvF901O3AXUhRrBJoEvYIjNQ.HKS','','2023-08-10 07:25:05','2023-08-11 11:12:33'),(18,9,'Sonia','Rekawek','soniar',NULL,NULL,'$2b$12$uHCkH6gu13yqllXBibLFIOWOpvctMC7NmojtXqDd6xsLq7bmvNOMu','','2023-08-10 07:25:27','2023-08-11 11:12:48'),(19,6,'Frank','Roelfs','frankr',NULL,NULL,'$2b$12$cEQAhUe9VJV6uTkfOY6/R.oAVfmFZQ4vS5G6BqoNEyaVHtFRDtB56','','2023-08-10 07:26:04','2023-08-11 11:12:19'),(20,10,'Vera','Schliedermann','veras',NULL,NULL,'$2b$12$FKcitW6W1HPwd.cdkZLGLeTFuzjsEIrbiKInysAKN.RibZ4gVLZHi','','2023-08-10 07:27:01','2023-08-11 11:12:54'),(21,8,'Michael','Strudthoff','michaels',NULL,NULL,'$2b$12$doTiywWpkso1UWB5eiAW1eoACP6rN4UDVt7qFFdRFvhhWUXikCmS2','','2023-08-10 07:27:27','2023-08-11 11:12:37'),(22,4,'Volker','Viohl','volkerv',NULL,NULL,'$2b$12$.YavQbWNE4eJDQA.ZNSKROYvMPWifBXyMX0IL0H2z50M720fpfTJW','','2023-08-10 07:27:50','2023-08-11 11:12:04'),(23,11,'Frauke','Zabel','fraukez',NULL,NULL,'$2b$12$rawQg6Cjl1yECGm9DOG8degdWdD.nZjEgGp8eXO98nh11QV1sEEEO','','2023-08-10 07:28:33','2023-08-11 11:12:58'),(24,8,'Jan','Zierow','janz',NULL,NULL,'$2b$12$CbnjUT42cf0mkIAqAURg3OksP9G3brmsE2GQTECTZ4.cVuhPn5D2G','','2023-08-10 07:28:55','2023-08-11 11:12:39'),(25,12,'Berit','Güstrau','beritg',NULL,NULL,'$2b$12$g8WJTEWwsrtMyqpVW/GFVuzyRjB2/n0YJJyvBx.3l51YiVEUjEQYy','','2023-08-21 06:52:35',NULL),(26,15,'Ilknur','Colmorn','ilknurc',NULL,NULL,'$2b$12$tpEb0JQ8Li4YkPH28FeYk.1Jt2vK.TFn9SyhBKJ08gn7S5d8WYRlO','','2023-08-21 06:56:42',NULL),(27,16,'Horst','Imgram','horsti',NULL,NULL,'$2b$12$05NFPSaP78puAa8pL39KrOKTafs/TzWwr4YfV4/Vrdu90assvNFZa','','2023-08-21 06:57:58',NULL),(28,136,'Christin','Hollmann','chollmann',NULL,NULL,'$2b$12$pb1bWJ7hxOplFoqT/nIhyuRD39dxOpQ9t0LwZUI8CNOkTkE.eXiSO','','2023-10-04 11:55:05',NULL),(29,1,'Max','Metz','maxm',NULL,NULL,'$2b$12$gg2Y51IDqnP3aAPKRzj7d.ZYSxB1pwuqTzwCnkGEfVIcDYRW0OBTS','','2023-10-06 13:02:56',NULL);
/*!40000 ALTER TABLE `user` ENABLE KEYS */;
UNLOCK TABLES;
@@ -152,4 +150,4 @@ UNLOCK TABLES;
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
--- Dump completed on 2023-09-05 10:38:13
+-- Dump completed on 2023-10-06 15:05:55
diff --git a/src/BreCalClient/AboutDialog.xaml b/src/BreCalClient/AboutDialog.xaml
index b14d21f..da82547 100644
--- a/src/BreCalClient/AboutDialog.xaml
+++ b/src/BreCalClient/AboutDialog.xaml
@@ -7,7 +7,7 @@
xmlns:xctk="http://schemas.xceed.com/wpf/xaml/toolkit"
xmlns:p = "clr-namespace:BreCalClient.Resources"
mc:Ignorable="d"
- Title="Help" Height="280" Width="500">
+ Title="Help" Height="374" Width="500" Loaded="Window_Loaded">
@@ -20,6 +20,10 @@
+
+
+
+
@@ -39,14 +43,20 @@
-
-
-
-
-
-
+
+
+
+
+
-
+
+
+
+
+
+
+
+
diff --git a/src/BreCalClient/AboutDialog.xaml.cs b/src/BreCalClient/AboutDialog.xaml.cs
index 61e6154..5347b22 100644
--- a/src/BreCalClient/AboutDialog.xaml.cs
+++ b/src/BreCalClient/AboutDialog.xaml.cs
@@ -2,6 +2,7 @@
// Description: Show about info and allow user detail editing
//
+using BreCalClient.misc.Model;
using System;
using System.Diagnostics;
using System.Windows;
@@ -24,6 +25,12 @@ namespace BreCalClient
#endregion
+ #region Properties
+
+ public LoginResult? LoginResult { get; set; }
+
+ #endregion
+
#region events
public event Action? ChangePasswordRequested;
@@ -39,6 +46,12 @@ namespace BreCalClient
private void buttonChangePassword_Click(object sender, RoutedEventArgs e)
{
+ if (this.LoginResult != null)
+ {
+ this.LoginResult.UserPhone = this.textBoxUserPhone.Text.Trim();
+ this.LoginResult.UserEmail = this.textBoxUserEmail.Text.Trim();
+ }
+
this.ChangePasswordRequested?.Invoke(this.wpBoxOldPassword.Password, this.wpBoxNewPassword.Password);
}
@@ -56,9 +69,17 @@ namespace BreCalClient
(this.wpBoxNewPasswordRepeat.Password.Length > 0) &&
this.wpBoxNewPassword.Password.Equals(this.wpBoxNewPasswordRepeat.Password) &&
(!this.wpBoxNewPassword.Password.Equals(this.wpBoxOldPassword.Password));
+ }
+
+ private void Window_Loaded(object sender, RoutedEventArgs e)
+ {
+ if(LoginResult != null)
+ {
+ this.textBoxUserEmail.Text = LoginResult.UserEmail;
+ this.textBoxUserPhone.Text = LoginResult.UserPhone;
+ }
}
#endregion
-
}
}
diff --git a/src/BreCalClient/App.config b/src/BreCalClient/App.config
index 9b96e2e..9c0e112 100644
--- a/src/BreCalClient/App.config
+++ b/src/BreCalClient/App.config
@@ -14,10 +14,10 @@
https://brecal.bsmd-emswe.eu
- #751D1F
+ #203864
- !!Bremen calling Testversion!!
+ Bremen calling
https://www.textbausteine.net/
diff --git a/src/BreCalClient/BreCalClient.csproj b/src/BreCalClient/BreCalClient.csproj
index 3c6b607..a5d44cc 100644
--- a/src/BreCalClient/BreCalClient.csproj
+++ b/src/BreCalClient/BreCalClient.csproj
@@ -8,12 +8,12 @@
True
BreCalClient.App
..\..\misc\brecal.snk
- 0.6.0.0
- 0.6.0.0
+ 0.9.4.0
+ 0.9.4.0
Bremen calling client
A Windows WPF client for the Bremen calling API.
containership.ico
- BreCalTestClient
+ BreCalClient
@@ -24,14 +24,17 @@
+
+
+
@@ -72,14 +75,17 @@
+
+
+
MSBuild:Compile
diff --git a/src/BreCalClient/BreCalLists.cs b/src/BreCalClient/BreCalLists.cs
new file mode 100644
index 0000000..c8df918
--- /dev/null
+++ b/src/BreCalClient/BreCalLists.cs
@@ -0,0 +1,123 @@
+// Copyright (c) 2023 schick Informatik
+// Description: Static lists used everywhere
+//
+
+using BreCalClient.misc.Model;
+using System.Collections.Concurrent;
+using System.Collections.Generic;
+
+
+namespace BreCalClient
+{
+ public static class BreCalLists
+ {
+
+ #region Fields
+
+ private static readonly List aList = new();
+ private static readonly List mList = new();
+ private static readonly List pList = new();
+ private static readonly List tList = new();
+ private static readonly List terList = new();
+
+ private static List _berths = new();
+ private static List _participants = new();
+ private static List _ships = new();
+
+ private readonly static ConcurrentDictionary _shipLookupDict = new();
+ private readonly static ConcurrentDictionary _berthLookupDict = new();
+ private readonly static Dictionary _participantLookupDict = new();
+
+ #endregion
+
+ #region Properties
+
+ public static ConcurrentDictionary ShipLookupDict { get { return _shipLookupDict; } }
+
+ public static ConcurrentDictionary BerthLookupDict { get { return _berthLookupDict; } }
+
+ public static Dictionary ParticipantLookupDict { get { return _participantLookupDict; } }
+
+ ///
+ /// Participants that are agents
+ ///
+ public static List Participants_Agent { get { return aList; } }
+
+ ///
+ /// Participants that are mooring companies
+ ///
+ public static List Participants_Mooring { get { return mList; } }
+
+ ///
+ /// Participants that are pilots
+ ///
+ public static List Participants_Pilot { get { return pList; } }
+
+ ///
+ /// Participants that are tug shipping companies
+ ///
+ public static List Participants_Tug { get { return tList; } }
+
+ ///
+ /// Participants that are terminals
+ ///
+ public static List Participants_Terminal { get { return terList; } }
+
+ ///
+ /// All participants
+ ///
+ public static List Participants { get { return _participants; } }
+
+ ///
+ /// All berths
+ ///
+ public static List Berths { get { return _berths; } }
+
+ ///
+ /// All ships
+ ///
+ public static List Ships { get { return _ships; } }
+
+ #endregion
+
+ #region methods
+
+ internal static void InitializeParticipants(List participants)
+ {
+ _participants = participants;
+
+ aList.Clear();
+ mList.Clear();
+ pList.Clear();
+ tList.Clear();
+ terList.Clear();
+
+ foreach (Participant p in participants)
+ {
+ _participantLookupDict[p.Id] = p;
+ if (p.IsTypeFlagSet(Extensions.ParticipantType.AGENCY)) aList.Add(p);
+ if (p.IsTypeFlagSet(Extensions.ParticipantType.MOORING)) mList.Add(p);
+ if (p.IsTypeFlagSet(Extensions.ParticipantType.PILOT)) pList.Add(p);
+ if (p.IsTypeFlagSet(Extensions.ParticipantType.TUG)) tList.Add(p);
+ if (p.IsTypeFlagSet(Extensions.ParticipantType.TERMINAL)) terList.Add(p);
+ }
+ }
+
+ internal static void InitializeBerths(List berths)
+ {
+ foreach (var berth in berths)
+ _berthLookupDict[berth.Id] = berth;
+ _berths = berths;
+ }
+
+ internal static void InitializeShips(List ships)
+ {
+ foreach (var ship in ships)
+ _shipLookupDict[ship.Id] = ship;
+ _ships = ships;
+ }
+
+ #endregion
+
+ }
+}
diff --git a/src/BreCalClient/EditShipcallControl.xaml b/src/BreCalClient/EditShipcallControl.xaml
index 7138d90..ffd82ee 100644
--- a/src/BreCalClient/EditShipcallControl.xaml
+++ b/src/BreCalClient/EditShipcallControl.xaml
@@ -8,7 +8,7 @@
xmlns:db="clr-namespace:BreCalClient;assembly=BreCalClient"
xmlns:xctk="http://schemas.xceed.com/wpf/xaml/toolkit"
mc:Ignorable="d"
- Title="{x:Static p:Resources.textEditShipcall}" Height="466" Width="800" Loaded="Window_Loaded" ResizeMode="NoResize" Icon="Resources/containership.ico">
+ Title="{x:Static p:Resources.textEditShipcall}" Height="214" Width="800" Loaded="Window_Loaded" ResizeMode="NoResize" Icon="Resources/containership.ico">
@@ -26,135 +26,73 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/src/BreCalClient/EditShipcallControl.xaml.cs b/src/BreCalClient/EditShipcallControl.xaml.cs
index 62a23c2..365a918 100644
--- a/src/BreCalClient/EditShipcallControl.xaml.cs
+++ b/src/BreCalClient/EditShipcallControl.xaml.cs
@@ -1,6 +1,6 @@
// Copyright (c) 2023 schick Informatik
// Description: Windows dialog to create / edit ship calls
-//
+//
using BreCalClient.misc.Model;
using System;
@@ -27,26 +27,11 @@ namespace BreCalClient
public ShipcallControlModel ShipcallModel { get; set; } = new ();
- ///
- /// All participants
- ///
- public List Participants { get; set; } = new();
-
- ///
- /// All berths
- ///
- public List Berths { get; set; } = new();
-
- ///
- /// All ships
- ///
- public List Ships { get; set; } = new();
-
- public Ship? SelectedShip {
+ public Ship? SelectedShip {
get
{
return this.comboBoxShip.SelectedItem as Ship;
- }
+ }
}
#endregion
@@ -55,32 +40,14 @@ namespace BreCalClient
private void Window_Loaded(object sender, RoutedEventArgs e)
{
- List aList = new();
- List mList = new();
- List pList = new();
- List tList = new();
- List terList = new();
+ this.comboBoxAgency.ItemsSource = BreCalLists.Participants_Agent;
- foreach(Participant p in Participants)
- {
- if (p.IsTypeFlagSet(Extensions.ParticipantType.AGENCY)) aList.Add(p);
- if (p.IsTypeFlagSet(Extensions.ParticipantType.MOORING)) mList.Add(p);
- if (p.IsTypeFlagSet(Extensions.ParticipantType.PILOT)) pList.Add(p);
- if (p.IsTypeFlagSet(Extensions.ParticipantType.TUG)) tList.Add(p);
- if (p.IsTypeFlagSet(Extensions.ParticipantType.TERMINAL)) terList.Add(p);
- }
-
- this.comboBoxAgency.ItemsSource = aList;
- this.comboBoxMooring.ItemsSource = mList;
- this.comboBoxPilot.ItemsSource = pList;
- this.comboBoxTug.ItemsSource = tList;
- this.comboBoxTerminal.ItemsSource = terList;
-
- this.comboBoxShip.ItemsSource = Ships;
- this.comboBoxCategories.ItemsSource = Enum.GetValues(typeof(Extensions.TypeEnum));
- this.comboBoxArrivalBerth.ItemsSource = this.Berths;
- this.comboBoxDepartureBerth.ItemsSource = this.Berths;
+ this.comboBoxShip.ItemsSource = BreCalLists.Ships;
+ this.comboBoxCategories.ItemsSource = Enum.GetValues(typeof(TypeEnum));
+ this.comboBoxArrivalBerth.ItemsSource = BreCalLists.Berths;
+ this.comboBoxDepartureBerth.ItemsSource = BreCalLists.Berths;
+ if (this.ShipcallModel.Shipcall == null) this.ShipcallModel.Shipcall = new();
this.CopyToControls();
this.EnableControls();
@@ -89,19 +56,34 @@ namespace BreCalClient
private void buttonOK_Click(object sender, RoutedEventArgs e)
{
this.CopyToModel();
- this.DialogResult = true;
+ this.DialogResult = true;
this.Close();
}
private void buttonCancel_Click(object sender, RoutedEventArgs e)
{
- this.DialogResult= false;
+ this.DialogResult= false;
this.Close();
}
private void comboBoxShip_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
this.buttonOK.IsEnabled = this.comboBoxShip.SelectedItem != null;
+ if (this.comboBoxShip.SelectedItem != null)
+ {
+ Ship? ship = this.comboBoxShip.SelectedItem as Ship;
+ this.integerUpDownIMO.Value = ship?.Imo;
+ this.textBoxCallsign.Text = ship?.Callsign;
+ this.doubleUpDownLength.Value = ship?.Length;
+ this.doubleUpDownWidth.Value = ship?.Width;
+ }
+ else
+ {
+ this.integerUpDownIMO.Value = null;
+ this.textBoxCallsign.Text = string.Empty;
+ this.doubleUpDownLength.Value = null;
+ this.doubleUpDownWidth.Value = null;
+ }
}
private void comboBoxAgency_SelectionChanged(object sender, SelectionChangedEventArgs e)
@@ -109,6 +91,39 @@ namespace BreCalClient
this.EnableControls();
}
+ private void comboBoxCategories_SelectionChanged(object? sender, SelectionChangedEventArgs? e)
+ {
+ TypeEnum? type = this.comboBoxCategories.SelectedItem as TypeEnum?;
+ if (type != null)
+ {
+ switch (type)
+ {
+ case TypeEnum.Incoming:
+ this.datePickerETA.IsEnabled = true;
+ this.datePickerETD.IsEnabled = false;
+ this.datePickerETD.Value = null;
+ this.comboBoxDepartureBerth.SelectedIndex = -1;
+ this.comboBoxDepartureBerth.IsEnabled = false;
+ this.comboBoxArrivalBerth.IsEnabled = true;
+ break;
+ case TypeEnum.Outgoing:
+ this.datePickerETA.IsEnabled = false;
+ this.datePickerETD.IsEnabled = true;
+ this.datePickerETA.Value = null;
+ this.comboBoxArrivalBerth.SelectedIndex = -1;
+ this.comboBoxArrivalBerth.IsEnabled = false;
+ this.comboBoxDepartureBerth.IsEnabled = true;
+ break;
+ case TypeEnum.Shifting:
+ this.datePickerETA.IsEnabled = true;
+ this.datePickerETD.IsEnabled = true;
+ this.comboBoxArrivalBerth.IsEnabled = true;
+ this.comboBoxDepartureBerth.IsEnabled = true;
+ break;
+ }
+ }
+ }
+
#endregion
#region Context menu handlers
@@ -119,30 +134,6 @@ namespace BreCalClient
this.ShipcallModel.AssignedParticipants.Remove(Extensions.ParticipantType.AGENCY);
}
- private void contextMenuItemClearMooring_Click(object sender, RoutedEventArgs e)
- {
- this.comboBoxMooring.SelectedIndex = -1;
- this.ShipcallModel.AssignedParticipants.Remove(Extensions.ParticipantType.MOORING);
- }
-
- private void contextMenuItemClearPilot_Click(object sender, RoutedEventArgs e)
- {
- this.comboBoxPilot.SelectedIndex = -1;
- this.ShipcallModel.AssignedParticipants.Remove(Extensions.ParticipantType.PILOT);
- }
-
- private void contextMenuItemClearTug_Click(object sender, RoutedEventArgs e)
- {
- this.comboBoxTug.SelectedIndex = -1;
- this.ShipcallModel.AssignedParticipants.Remove(Extensions.ParticipantType.TUG);
- }
-
- private void contextMenuItemClearTerminal_Click(object sender, RoutedEventArgs e)
- {
- this.comboBoxTerminal.SelectedIndex = -1;
- this.ShipcallModel.AssignedParticipants.Remove(Extensions.ParticipantType.TERMINAL);
- }
-
private void contextMenuItemArrivalBerth_Click(object sender, RoutedEventArgs e)
{
this.comboBoxArrivalBerth.SelectedIndex = -1;
@@ -152,7 +143,7 @@ namespace BreCalClient
private void contextMenuItemDepartureBerth_Click(object sender, RoutedEventArgs e)
{
this.comboBoxDepartureBerth.SelectedIndex -= 1;
- }
+ }
#endregion
@@ -163,77 +154,62 @@ namespace BreCalClient
if (this.ShipcallModel.Shipcall != null)
{
this.ShipcallModel.Shipcall.Type = (int)this.comboBoxCategories.SelectedItem;
- this.ShipcallModel.Shipcall.Eta = this.datePickerETA.Value ?? DateTime.Now;
- this.ShipcallModel.Shipcall.Voyage = this.textBoxVoyage.Text.Trim();
- this.ShipcallModel.Shipcall.Etd = this.datePickerETD.Value ?? DateTime.Now.AddDays(1);
- this.ShipcallModel.Shipcall.Anchored = this.checkBoxAnchored.IsChecked;
+ this.ShipcallModel.Shipcall.Eta = this.datePickerETA.Value;
+ this.ShipcallModel.Shipcall.Etd = this.datePickerETD.Value;
+
this.ShipcallModel.Shipcall.ShipId = ((Ship)this.comboBoxShip.SelectedItem).Id;
+ this.ShipcallModel.Ship = (Ship)this.comboBoxShip.SelectedItem;
this.ShipcallModel.Shipcall.ArrivalBerthId = (this.comboBoxArrivalBerth.SelectedItem != null) ? ((Berth)this.comboBoxArrivalBerth.SelectedItem).Id : null;
this.ShipcallModel.Shipcall.DepartureBerthId = (this.comboBoxDepartureBerth.SelectedItem != null) ? ((Berth)this.comboBoxDepartureBerth.SelectedItem).Id : null;
- this.ShipcallModel.Shipcall.Bunkering = this.checkBoxBunkering.IsChecked;
- this.ShipcallModel.Shipcall.Canceled = this.checkBoxCanceled.IsChecked;
- this.ShipcallModel.Shipcall.Draft = (float?)this.doubleUpDownDraft.Value;
- this.ShipcallModel.Shipcall.MooredLock = this.checkBoxMooredLock.IsChecked;
- this.ShipcallModel.Shipcall.RainSensitiveCargo = this.checkBoxRainsensitiveCargo.IsChecked;
- this.ShipcallModel.Shipcall.PilotRequired = this.checkBoxPilotRequired.IsChecked;
- this.ShipcallModel.Shipcall.ReplenishingLock = this.checkBoxReplenishingLock.IsChecked;
- this.ShipcallModel.Shipcall.ReplenishingTerminal = this.checkBoxReplenishingTerminal.IsChecked;
- this.ShipcallModel.Shipcall.RecommendedTugs = this.integerUpDownRecommendedTugs.Value;
- this.ShipcallModel.Shipcall.TidalWindowFrom = this.datePickerTidalWindowFrom.Value;
- this.ShipcallModel.Shipcall.TidalWindowTo = this.datePickerTidalWindowTo.Value;
- this.ShipcallModel.Shipcall.TugRequired = this.checkBoxTugRequired.IsChecked;
- if (this.comboBoxPierside.SelectedIndex >= 0)
- {
- this.ShipcallModel.Shipcall.PierSide = (this.comboBoxPierside.SelectedIndex == 0) ? true : false;
- }
-
- // remove all and add selected participants
- this.ShipcallModel.Shipcall.Participants.Clear();
- this.ShipcallModel.AssignedParticipants.Clear();
+
Participant? participant;
participant = (Participant?)this.comboBoxAgency.SelectedItem;
if (participant != null)
{
- this.ShipcallModel.Shipcall.Participants.Add(participant.Id);
- this.ShipcallModel.AssignedParticipants[Extensions.ParticipantType.AGENCY] = participant;
- }
- participant = (Participant?)this.comboBoxMooring.SelectedItem;
- if (participant != null)
+ ParticipantAssignment pa = new()
+ {
+ ParticipantId = participant.Id,
+ Type = (int)Extensions.ParticipantType.AGENCY
+ };
+ this.ShipcallModel.AssignedParticipants[Extensions.ParticipantType.AGENCY] = pa;
+ }
+ else
{
- this.ShipcallModel.Shipcall.Participants.Add(participant.Id);
- this.ShipcallModel.AssignedParticipants[Extensions.ParticipantType.MOORING] = participant;
- }
- participant = (Participant?)this.comboBoxPilot.SelectedItem;
- if (participant != null)
- {
- this.ShipcallModel.Shipcall.Participants.Add(participant.Id);
- this.ShipcallModel.AssignedParticipants[Extensions.ParticipantType.PILOT] = participant;
- }
- participant = (Participant?)this.comboBoxTerminal.SelectedItem;
- if (participant != null) {
- this.ShipcallModel.Shipcall.Participants.Add(participant.Id);
- this.ShipcallModel.AssignedParticipants[Extensions.ParticipantType.TERMINAL] = participant;
- }
- participant = (Participant?)this.comboBoxTug.SelectedItem;
- if (participant != null) {
- this.ShipcallModel.Shipcall.Participants.Add(participant.Id);
- this.ShipcallModel.AssignedParticipants[Extensions.ParticipantType.TUG] = participant;
+ // AGENCY was set before and now is set to nothing
+ if (this.ShipcallModel.AssignedParticipants.ContainsKey(ParticipantType.AGENCY))
+ this.ShipcallModel.AssignedParticipants.Remove(ParticipantType.AGENCY);
}
// BSMD and port authority are always added
- foreach (Participant p in Participants)
+
+ // get port authority from berth
+
+ int? berthId = this.ShipcallModel.Shipcall.ArrivalBerthId;
+ berthId ??= this.ShipcallModel.Shipcall.DepartureBerthId;
+
+ if (berthId != null)
{
- if (p.Type == (int)Extensions.ParticipantType.PORT_ADMINISTRATION)
+ Berth? selectedBerth = BreCalLists.Berths.Find((x) => x.Id == berthId);
+ if (selectedBerth?.AuthorityId != null)
{
- this.ShipcallModel.Shipcall.Participants.Add(p.Id);
- this.ShipcallModel.AssignedParticipants[Extensions.ParticipantType.PORT_ADMINISTRATION] = p;
+ if (BreCalLists.ParticipantLookupDict.ContainsKey(selectedBerth.AuthorityId.Value))
+ {
+ ParticipantAssignment pab = new()
+ {
+ ParticipantId = selectedBerth.AuthorityId.Value,
+ Type = (int)ParticipantType.PORT_ADMINISTRATION
+ };
+ this.ShipcallModel.AssignedParticipants[ParticipantType.PORT_ADMINISTRATION] = pab;
+ }
}
- if (p.Type == (int)Extensions.ParticipantType.BSMD)
+
+ ParticipantAssignment pa = new()
{
- this.ShipcallModel.Shipcall.Participants.Add(p.Id);
- this.ShipcallModel.AssignedParticipants[Extensions.ParticipantType.BSMD] = p;
- }
+ ParticipantId = App.Participant.Id,
+ Type = (int)ParticipantType.BSMD
+ };
+ this.ShipcallModel.AssignedParticipants[ParticipantType.BSMD] = pa;
}
}
}
@@ -243,54 +219,31 @@ namespace BreCalClient
if (this.ShipcallModel == null) return;
if (this.ShipcallModel.Shipcall != null)
{
- this.comboBoxCategories.SelectedItem = (Extensions.TypeEnum)this.ShipcallModel.Shipcall.Type;
+ this.comboBoxCategories.SelectedItem = (TypeEnum)this.ShipcallModel.Shipcall.Type;
if (this.ShipcallModel.Shipcall.Eta != DateTime.MinValue)
this.datePickerETA.Value = this.ShipcallModel.Shipcall.Eta;
- this.textBoxVoyage.Text = this.ShipcallModel.Shipcall.Voyage;
+ // this.textBoxVoyage.Text = this.ShipcallModel.Shipcall.Voyage;
this.datePickerETD.Value = this.ShipcallModel.Shipcall.Etd;
- this.checkBoxAnchored.IsChecked = this.ShipcallModel.Shipcall.Anchored;
this.comboBoxShip.SelectedValue = this.ShipcallModel.Shipcall.ShipId;
this.comboBoxArrivalBerth.SelectedValue = this.ShipcallModel.Shipcall.ArrivalBerthId;
this.comboBoxDepartureBerth.SelectedValue = this.ShipcallModel.Shipcall.DepartureBerthId;
- this.checkBoxBunkering.IsChecked = this.ShipcallModel.Shipcall.Bunkering;
- this.checkBoxCanceled.IsChecked = this.ShipcallModel.Shipcall.Canceled;
- this.doubleUpDownDraft.Value = this.ShipcallModel.Shipcall.Draft;
- this.checkBoxMooredLock.IsChecked = this.ShipcallModel.Shipcall.MooredLock;
-
- this.checkBoxRainsensitiveCargo.IsChecked = this.ShipcallModel.Shipcall.RainSensitiveCargo;
- this.checkBoxPilotRequired.IsChecked = this.ShipcallModel.Shipcall.PilotRequired;
- this.checkBoxReplenishingLock.IsChecked = this.ShipcallModel.Shipcall.ReplenishingLock;
- this.checkBoxReplenishingTerminal.IsChecked = this.ShipcallModel.Shipcall.ReplenishingTerminal;
- this.integerUpDownRecommendedTugs.Value = this.ShipcallModel.Shipcall.RecommendedTugs;
- this.datePickerTidalWindowFrom.Value = this.ShipcallModel.Shipcall.TidalWindowFrom;
- this.datePickerTidalWindowTo.Value = this.ShipcallModel.Shipcall.TidalWindowTo;
- this.checkBoxTugRequired.IsChecked = this.ShipcallModel.Shipcall.TugRequired;
- if (this.ShipcallModel.Shipcall.PierSide.HasValue)
- {
- if (this.ShipcallModel.Shipcall.PierSide.Value) this.comboBoxPierside.SelectedIndex = 0;
- else this.comboBoxPierside.SelectedIndex = 1;
- }
if (this.ShipcallModel.Shipcall.Participants == null) this.ShipcallModel.Shipcall.Participants = new();
-
- // Hier wird noch ein Problem vergessen: Wenn ein Participant mehrere Types gleichzeitig ist und es einen weitere Participant mit diesem Type gibt
- // müsste der "einzelne" Participant für die Rolle ausgewählt werden. (Angenommen ein Test-Teilnehmer hat "alle" Rollen..)
-
- foreach (int participant_id in this.ShipcallModel.Shipcall.Participants)
+
+ if(this.ShipcallModel.AssignedParticipants.ContainsKey(ParticipantType.AGENCY))
{
- if (((List)this.comboBoxAgency.ItemsSource).Any(x => x.Id == participant_id)) this.comboBoxAgency.SelectedValue = participant_id;
- if (((List)this.comboBoxMooring.ItemsSource).Any(x => x.Id == participant_id)) this.comboBoxMooring.SelectedValue = participant_id;
- if (((List)this.comboBoxPilot.ItemsSource).Any(x => x.Id == participant_id)) this.comboBoxPilot.SelectedValue = participant_id;
- if (((List)this.comboBoxTerminal.ItemsSource).Any(x => x.Id == participant_id)) this.comboBoxTerminal.SelectedValue = participant_id;
- if (((List)this.comboBoxTug.ItemsSource).Any(x => x.Id == participant_id)) this.comboBoxTug.SelectedValue = participant_id;
- }
+ if (BreCalLists.ParticipantLookupDict.ContainsKey(this.ShipcallModel.AssignedParticipants[ParticipantType.AGENCY].ParticipantId))
+ {
+ this.comboBoxAgency.SelectedValue = this.ShipcallModel.AssignedParticipants[ParticipantType.AGENCY].ParticipantId;
+ }
+ }
}
}
private void EnableControls()
{
- bool isBsmd = App.Participant.IsTypeFlagSet(Extensions.ParticipantType.BSMD);
- bool isAgency = App.Participant.IsTypeFlagSet(Extensions.ParticipantType.AGENCY);
+ bool isBsmd = App.Participant.IsTypeFlagSet(ParticipantType.BSMD);
+ bool isAgency = App.Participant.IsTypeFlagSet(ParticipantType.AGENCY);
bool editRightGrantedForBSMD = false;
@@ -298,12 +251,12 @@ namespace BreCalClient
if (this.comboBoxAgency.SelectedIndex >= 0)
{
int agencyParticipantId = (int)this.comboBoxAgency.SelectedValue;
- Participant? p = this.Participants.Find(x => x.Id == agencyParticipantId);
+ Participant? p = BreCalLists.Participants.Find(x => x.Id == agencyParticipantId);
if (p != null)
{
if(p.IsFlagSet(ParticipantFlag.ALLOW_BSMD) && isBsmd)
isAgency = true;
- if(p.IsFlagSet(ParticipantFlag.ALLOW_BSMD))
+ if(p.IsFlagSet(ParticipantFlag.ALLOW_BSMD))
editRightGrantedForBSMD = true;
}
}
@@ -312,34 +265,16 @@ namespace BreCalClient
this.comboBoxArrivalBerth.IsEnabled = isBsmd || isAgency;
this.comboBoxCategories.IsEnabled = isBsmd;
this.comboBoxDepartureBerth.IsEnabled = isBsmd || isAgency;
- this.checkBoxAnchored.IsEnabled = isAgency;
- this.checkBoxBunkering.IsEnabled = isAgency;
- this.checkBoxCanceled.IsEnabled = isBsmd || isAgency;
- this.checkBoxMooredLock.IsEnabled = isAgency;
- this.checkBoxPilotRequired.IsEnabled = isAgency;
- this.checkBoxRainsensitiveCargo.IsEnabled = isAgency;
- this.checkBoxReplenishingLock.IsEnabled = isAgency;
- this.checkBoxReplenishingTerminal.IsEnabled = isAgency;
- this.checkBoxTugRequired.IsEnabled = isAgency;
- this.comboBoxMooring.IsEnabled = isBsmd;
- this.comboBoxPierside.IsEnabled = isAgency;
- this.comboBoxPilot.IsEnabled = isAgency;
this.comboBoxShip.IsEnabled = isBsmd;
- this.comboBoxMooring.IsEnabled = isAgency;
- this.comboBoxTerminal.IsEnabled = isAgency;
- this.comboBoxTug.IsEnabled = isAgency;
this.datePickerETA.IsEnabled = isAgency || isBsmd;
this.datePickerETD.IsEnabled = isAgency;
- this.textBoxVoyage.IsEnabled = isAgency;
- this.datePickerTidalWindowFrom.IsEnabled = isAgency;
- this.datePickerTidalWindowTo.IsEnabled = isAgency;
- this.integerUpDownRecommendedTugs.IsEnabled = isAgency;
- this.doubleUpDownDraft.IsEnabled = isAgency || isBsmd;
this.labelBSMDGranted.Visibility = editRightGrantedForBSMD ? Visibility.Visible : Visibility.Hidden;
+
+ this.comboBoxCategories_SelectionChanged(null, null);
}
#endregion
-
+
}
}
diff --git a/src/BreCalClient/EditTimesAgencyIncomingControl.xaml b/src/BreCalClient/EditTimesAgencyIncomingControl.xaml
new file mode 100644
index 0000000..bf62a09
--- /dev/null
+++ b/src/BreCalClient/EditTimesAgencyIncomingControl.xaml
@@ -0,0 +1,139 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/BreCalClient/EditTimesAgencyIncomingControl.xaml.cs b/src/BreCalClient/EditTimesAgencyIncomingControl.xaml.cs
new file mode 100644
index 0000000..3945882
--- /dev/null
+++ b/src/BreCalClient/EditTimesAgencyIncomingControl.xaml.cs
@@ -0,0 +1,305 @@
+// Copyright (c) 2023 schick Informatik
+// Description: Input control for incoming shipcalls
+//
+
+using BreCalClient.misc.Model;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Windows;
+using static BreCalClient.Extensions;
+
+namespace BreCalClient
+{
+ ///
+ /// Interaction logic for EditTimesAgencyIncomingControl.xaml
+ ///
+ public partial class EditTimesAgencyIncomingControl : Window, IEditShipcallTimesControl
+ {
+ #region Construction
+
+ public EditTimesAgencyIncomingControl()
+ {
+ InitializeComponent();
+ }
+
+ #endregion
+
+ #region Properties
+
+ public ShipcallControlModel ShipcallModel { get; set; } = new();
+
+ public Times Times { get; set; } = new();
+
+ public Extensions.TypeEnum CallType { get; set; }
+
+ #endregion
+
+ #region event handler
+
+ private void Window_Loaded(object sender, RoutedEventArgs e)
+ {
+ this.comboBoxMooring.ItemsSource = BreCalLists.Participants_Mooring;
+ this.comboBoxPilot.ItemsSource = BreCalLists.Participants_Pilot;
+ this.comboBoxTug.ItemsSource = BreCalLists.Participants_Tug;
+ this.comboBoxTerminal.ItemsSource = BreCalLists.Participants_Terminal;
+
+ this.comboBoxArrivalBerth.ItemsSource = BreCalLists.Berths;
+ this.CopyToControls();
+
+
+ Participant? p = null;
+ if(this.ShipcallModel.AssignedParticipants.ContainsKey(ParticipantType.AGENCY))
+ p = BreCalLists.Participants.Find(x => x.Id == this.ShipcallModel.AssignedParticipants[ParticipantType.AGENCY].ParticipantId);
+
+ bool allowBSMD = false;
+ if (p != null)
+ {
+ allowBSMD = p.IsFlagSet(ParticipantFlag.ALLOW_BSMD);
+ }
+
+ bool enableControls = (this.Times.ParticipantId == App.Participant.Id) ||
+ (App.Participant.IsTypeFlagSet(ParticipantType.BSMD) && allowBSMD);
+
+ this.EnableControls(enableControls);
+
+ }
+
+ private void buttonOK_Click(object sender, RoutedEventArgs e)
+ {
+ this.CopyToModel();
+ this.DialogResult = true;
+ this.Close();
+ }
+
+ private void buttonCancel_Click(object sender, RoutedEventArgs e)
+ {
+ this.DialogResult = false;
+ this.Close();
+ }
+
+ #endregion
+
+ #region private methods
+
+ private void CopyToModel()
+ {
+ if (this.ShipcallModel.Shipcall != null)
+ {
+ this.Times.EtaBerth = this.datePickerETA.Value;
+
+ if (this.comboBoxPierside.SelectedIndex >= 0)
+ {
+ this.ShipcallModel.Shipcall.PierSide = (this.comboBoxPierside.SelectedIndex == 0) ? true : false;
+ }
+
+ this.Times.BerthInfo = this.textBoxBerthRemarks.Text.Trim();
+ this.Times.BerthId = (int?)this.comboBoxArrivalBerth.SelectedValue;
+
+ this.ShipcallModel.Shipcall.Draft = (float?)this.doubleUpDownDraft.Value;
+ this.ShipcallModel.Shipcall.TidalWindowFrom = this.datePickerTidalWindowFrom.Value;
+ this.ShipcallModel.Shipcall.TidalWindowTo = this.datePickerTidalWindowTo.Value;
+ this.ShipcallModel.Shipcall.Canceled = this.checkBoxCanceled.IsChecked;
+
+ this.ShipcallModel.Shipcall.Anchored = this.checkBoxAnchored.IsChecked;
+ this.ShipcallModel.Shipcall.TugRequired = this.checkBoxTugRequired.IsChecked;
+ this.ShipcallModel.Shipcall.RecommendedTugs = this.integerUpDownRecommendedTugs.Value;
+ this.ShipcallModel.Shipcall.PilotRequired = this.checkBoxPilotRequired.IsChecked;
+ this.ShipcallModel.Shipcall.MooredLock = this.checkBoxMooredLock.IsChecked;
+ this.ShipcallModel.Shipcall.Bunkering = this.checkBoxBunkering.IsChecked;
+ this.ShipcallModel.Shipcall.ReplenishingTerminal = this.checkBoxReplenishingTerminal.IsChecked;
+ this.ShipcallModel.Shipcall.ReplenishingLock = this.checkBoxReplenishingLock.IsChecked;
+
+ if (!string.IsNullOrEmpty(this.textBoxRemarks.Text.Trim()))
+ this.Times.Remarks = this.textBoxRemarks.Text.Trim();
+
+ Participant? participant = (Participant?)this.comboBoxMooring.SelectedItem;
+ if (participant != null)
+ {
+ ParticipantAssignment participantAssignment = new() {
+ ParticipantId = participant.Id,
+ Type = (int)Extensions.ParticipantType.MOORING
+ };
+ this.ShipcallModel.AssignedParticipants[Extensions.ParticipantType.MOORING] = participantAssignment;
+ }
+
+ participant = (Participant?)this.comboBoxPilot.SelectedItem;
+ if (participant != null)
+ {
+ ParticipantAssignment participantAssignment = new()
+ {
+ ParticipantId = participant.Id,
+ Type = (int)Extensions.ParticipantType.PILOT
+ };
+ this.ShipcallModel.AssignedParticipants[Extensions.ParticipantType.PILOT] = participantAssignment;
+ }
+ participant = (Participant?)this.comboBoxTerminal.SelectedItem;
+ if (participant != null)
+ {
+ ParticipantAssignment participantAssignment = new()
+ {
+ ParticipantId = participant.Id,
+ Type = (int)Extensions.ParticipantType.TERMINAL
+ };
+ this.ShipcallModel.AssignedParticipants[Extensions.ParticipantType.TERMINAL] = participantAssignment;
+ }
+ participant = (Participant?)this.comboBoxTug.SelectedItem;
+ if (participant != null)
+ {
+ ParticipantAssignment participantAssignment = new()
+ {
+ ParticipantId = participant.Id,
+ Type = (int)Extensions.ParticipantType.TUG
+ };
+ this.ShipcallModel.AssignedParticipants[Extensions.ParticipantType.TUG] = participantAssignment;
+ }
+ }
+ }
+
+ private void CopyToControls()
+ {
+ if (this.ShipcallModel == null) return;
+ if (this.ShipcallModel.Shipcall != null)
+ {
+ if(this.Times.EtaBerth.HasValue)
+ {
+ this.datePickerETA.Value = this.Times.EtaBerth.Value;
+ }
+ else
+ {
+ // if not set through times use value of BSMD entry
+ if (this.ShipcallModel.Shipcall.Eta != DateTime.MinValue)
+ this.datePickerETA.Value = this.ShipcallModel.Shipcall.Eta;
+ }
+
+ if (Times.BerthId.HasValue)
+ this.comboBoxArrivalBerth.SelectedValue = Times.BerthId;
+ else if (this.ShipcallModel.Shipcall.ArrivalBerthId.HasValue)
+ this.comboBoxArrivalBerth.SelectedValue = this.ShipcallModel.Shipcall.ArrivalBerthId;
+
+ if (this.ShipcallModel.Shipcall.PierSide.HasValue)
+ {
+ if (this.ShipcallModel.Shipcall.PierSide.Value) this.comboBoxPierside.SelectedIndex = 0;
+ else this.comboBoxPierside.SelectedIndex = 1;
+ }
+ this.textBoxBerthRemarks.Text = this.Times.BerthInfo;
+ this.doubleUpDownDraft.Value = this.ShipcallModel.Shipcall.Draft;
+ this.datePickerTidalWindowFrom.Value = this.ShipcallModel.Shipcall.TidalWindowFrom;
+ this.datePickerTidalWindowTo.Value = this.ShipcallModel.Shipcall.TidalWindowTo;
+ this.checkBoxCanceled.IsChecked = this.ShipcallModel.Shipcall.Canceled ?? false;
+
+ this.checkBoxAnchored.IsChecked = this.ShipcallModel.Shipcall.Anchored ?? false;
+ this.checkBoxTugRequired.IsChecked = this.ShipcallModel.Shipcall.TugRequired ?? false;
+ this.integerUpDownRecommendedTugs.Value = this.ShipcallModel.Shipcall.RecommendedTugs;
+ this.checkBoxPilotRequired.IsChecked = this.ShipcallModel.Shipcall.PilotRequired ?? false;
+
+ this.checkBoxMooredLock.IsChecked = this.ShipcallModel.Shipcall.MooredLock ?? false;
+
+ this.checkBoxBunkering.IsChecked = this.ShipcallModel.Shipcall.Bunkering ?? false;
+ this.checkBoxReplenishingLock.IsChecked = this.ShipcallModel.Shipcall.ReplenishingLock ?? false;
+ this.checkBoxReplenishingTerminal.IsChecked = this.ShipcallModel.Shipcall.ReplenishingTerminal ?? false;
+
+ if(!string.IsNullOrEmpty(this.Times.Remarks))
+ this.textBoxRemarks.Text = this.Times.Remarks;
+
+ if (this.ShipcallModel.AssignedParticipants.ContainsKey(ParticipantType.MOORING))
+ {
+ if (BreCalLists.ParticipantLookupDict.ContainsKey(this.ShipcallModel.AssignedParticipants[ParticipantType.MOORING].ParticipantId))
+ {
+ this.comboBoxMooring.SelectedValue = this.ShipcallModel.AssignedParticipants[ParticipantType.MOORING].ParticipantId;
+ }
+ }
+
+ if (this.ShipcallModel.AssignedParticipants.ContainsKey(ParticipantType.PILOT))
+ {
+ if (BreCalLists.ParticipantLookupDict.ContainsKey(this.ShipcallModel.AssignedParticipants[ParticipantType.PILOT].ParticipantId))
+ {
+ this.comboBoxPilot.SelectedValue = this.ShipcallModel.AssignedParticipants[ParticipantType.PILOT].ParticipantId;
+ }
+ }
+
+ if (this.ShipcallModel.AssignedParticipants.ContainsKey(ParticipantType.TERMINAL))
+ {
+ if (BreCalLists.ParticipantLookupDict.ContainsKey(this.ShipcallModel.AssignedParticipants[ParticipantType.TERMINAL].ParticipantId))
+ {
+ this.comboBoxTerminal.SelectedValue = this.ShipcallModel.AssignedParticipants[ParticipantType.TERMINAL].ParticipantId;
+ }
+ }
+
+ if (this.ShipcallModel.AssignedParticipants.ContainsKey(ParticipantType.TUG))
+ {
+ if (BreCalLists.ParticipantLookupDict.ContainsKey(this.ShipcallModel.AssignedParticipants[ParticipantType.TUG].ParticipantId))
+ {
+ this.comboBoxTug.SelectedValue = this.ShipcallModel.AssignedParticipants[ParticipantType.TUG].ParticipantId;
+ }
+ }
+
+ }
+ }
+
+ private void EnableControls(bool isEnabled)
+ {
+ this.datePickerETA.IsEnabled = isEnabled;
+ this.comboBoxArrivalBerth.IsEnabled = isEnabled;
+ this.comboBoxPierside.IsEnabled = isEnabled;
+ this.textBoxBerthRemarks.IsEnabled = isEnabled;
+ this.doubleUpDownDraft.IsEnabled = isEnabled;
+ this.datePickerTidalWindowFrom.IsEnabled = isEnabled;
+ this.datePickerTidalWindowTo.IsEnabled = isEnabled;
+ this.checkBoxCanceled.IsEnabled = isEnabled;
+
+ this.checkBoxAnchored.IsEnabled = isEnabled;
+ this.checkBoxTugRequired.IsEnabled = isEnabled;
+ this.comboBoxTug.IsEnabled = isEnabled;
+ this.integerUpDownRecommendedTugs.IsEnabled = isEnabled;
+ this.checkBoxPilotRequired.IsEnabled = isEnabled;
+ this.comboBoxPilot.IsEnabled = isEnabled;
+ this.comboBoxMooring.IsEnabled = isEnabled;
+ this.checkBoxMooredLock.IsEnabled = isEnabled;
+ this.comboBoxTerminal.IsEnabled = isEnabled;
+ this.checkBoxBunkering.IsEnabled = isEnabled;
+ this.checkBoxReplenishingTerminal.IsEnabled = isEnabled;
+ this.checkBoxReplenishingLock.IsEnabled = isEnabled;
+ this.textBoxRemarks.IsEnabled = isEnabled;
+
+ this.buttonOK.IsEnabled = isEnabled;
+ }
+
+ #endregion
+
+ #region context menu handlers
+
+ private void contextMenuItemArrivalBerth_Click(object sender, RoutedEventArgs e)
+ {
+ this.comboBoxArrivalBerth.SelectedIndex = -1;
+ this.ShipcallModel.Berth = "";
+ }
+
+ private void contextMenuItemClearTug_Click(object sender, RoutedEventArgs e)
+ {
+ this.comboBoxTug.SelectedIndex = -1;
+ this.ShipcallModel.AssignedParticipants.Remove(Extensions.ParticipantType.TUG);
+ }
+
+ private void contextMenuItemClearPilot_Click(object sender, RoutedEventArgs e)
+ {
+ this.comboBoxPilot.SelectedIndex = -1;
+ this.ShipcallModel.AssignedParticipants.Remove(Extensions.ParticipantType.PILOT);
+ }
+
+ private void contextMenuItemClearMooring_Click(object sender, RoutedEventArgs e)
+ {
+ this.comboBoxMooring.SelectedIndex = -1;
+ this.ShipcallModel.AssignedParticipants.Remove(Extensions.ParticipantType.MOORING);
+ }
+
+ private void contextMenuItemClearTerminal_Click(object sender, RoutedEventArgs e)
+ {
+ this.comboBoxTerminal.SelectedIndex = -1;
+ this.ShipcallModel.AssignedParticipants.Remove(Extensions.ParticipantType.TERMINAL);
+ }
+
+ #endregion
+
+ }
+}
diff --git a/src/BreCalClient/EditTimesAgencyOutgoingControl.xaml b/src/BreCalClient/EditTimesAgencyOutgoingControl.xaml
new file mode 100644
index 0000000..abfc91c
--- /dev/null
+++ b/src/BreCalClient/EditTimesAgencyOutgoingControl.xaml
@@ -0,0 +1,129 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/BreCalClient/EditTimesAgencyOutgoingControl.xaml.cs b/src/BreCalClient/EditTimesAgencyOutgoingControl.xaml.cs
new file mode 100644
index 0000000..652346e
--- /dev/null
+++ b/src/BreCalClient/EditTimesAgencyOutgoingControl.xaml.cs
@@ -0,0 +1,290 @@
+// Copyright (c) 2023 schick Informatik
+// Description: Input control for outgoing shipcalls
+//
+
+using BreCalClient.misc.Model;
+using System;
+using System.Windows;
+using static BreCalClient.Extensions;
+
+namespace BreCalClient
+{
+ ///
+ /// Interaction logic for EditTimesAgencyOutgoingControl.xaml
+ ///
+ public partial class EditTimesAgencyOutgoingControl : Window, IEditShipcallTimesControl
+ {
+
+ #region Construction
+
+ public EditTimesAgencyOutgoingControl()
+ {
+ InitializeComponent();
+ }
+
+ #endregion
+
+ #region Properties
+
+ public ShipcallControlModel ShipcallModel { get; set; } = new();
+
+ public Times Times { get; set; } = new();
+
+ public Extensions.TypeEnum CallType { get; set; }
+
+ #endregion
+
+ #region event handler
+
+ private void Window_Loaded(object sender, RoutedEventArgs e)
+ {
+ this.comboBoxMooring.ItemsSource = BreCalLists.Participants_Mooring;
+ this.comboBoxPilot.ItemsSource = BreCalLists.Participants_Pilot;
+ this.comboBoxTug.ItemsSource = BreCalLists.Participants_Tug;
+ this.comboBoxTerminal.ItemsSource = BreCalLists.Participants_Terminal;
+
+ this.comboBoxDepartureBerth.ItemsSource = BreCalLists.Berths;
+ this.CopyToControls();
+
+ Participant? p = null;
+ if (this.ShipcallModel.AssignedParticipants.ContainsKey(ParticipantType.AGENCY))
+ p = BreCalLists.Participants.Find(x => x.Id == this.ShipcallModel.AssignedParticipants[ParticipantType.AGENCY].ParticipantId);
+
+ bool allowBSMD = false;
+ if (p != null)
+ {
+ allowBSMD = p.IsFlagSet(ParticipantFlag.ALLOW_BSMD);
+ }
+
+ bool enableControls = (this.Times.ParticipantId == App.Participant.Id) ||
+ (App.Participant.IsTypeFlagSet(ParticipantType.BSMD) && allowBSMD);
+
+ this.EnableControls(enableControls);
+
+ }
+
+ private void buttonOK_Click(object sender, RoutedEventArgs e)
+ {
+ this.CopyToModel();
+ this.DialogResult = true;
+ this.Close();
+ }
+
+ private void buttonCancel_Click(object sender, RoutedEventArgs e)
+ {
+ this.DialogResult = false;
+ this.Close();
+ }
+
+ #endregion
+
+ #region private methods
+
+ private void CopyToModel()
+ {
+ if (this.ShipcallModel.Shipcall != null)
+ {
+ this.Times.EtdBerth = this.datePickerETD.Value;
+ if (this.comboBoxPierside.SelectedIndex >= 0)
+ {
+ this.ShipcallModel.Shipcall.PierSide = (this.comboBoxPierside.SelectedIndex == 0) ? true : false;
+ }
+
+ this.Times.BerthId = (int?)this.comboBoxDepartureBerth.SelectedValue;
+
+ this.Times.BerthInfo = this.textBoxBerthRemarks.Text.Trim();
+ this.ShipcallModel.Shipcall.Draft = (float?)this.doubleUpDownDraft.Value;
+ this.ShipcallModel.Shipcall.TidalWindowFrom = this.datePickerTidalWindowFrom.Value;
+ this.ShipcallModel.Shipcall.TidalWindowTo = this.datePickerTidalWindowTo.Value;
+ this.ShipcallModel.Shipcall.Canceled = this.checkBoxCanceled.IsChecked;
+
+ this.ShipcallModel.Shipcall.TugRequired = this.checkBoxTugRequired.IsChecked;
+ this.ShipcallModel.Shipcall.RecommendedTugs = this.integerUpDownRecommendedTugs.Value;
+ this.ShipcallModel.Shipcall.PilotRequired = this.checkBoxPilotRequired.IsChecked;
+ this.ShipcallModel.Shipcall.MooredLock = this.checkBoxMooredLock.IsChecked;
+ this.ShipcallModel.Shipcall.RainSensitiveCargo = this.checkBoxRainsensitiveCargo.IsChecked;
+ if(!string.IsNullOrEmpty(this.textBoxRemarks.Text.Trim()))
+ this.Times.Remarks = this.textBoxRemarks.Text.Trim();
+
+ Participant? participant = (Participant?)this.comboBoxMooring.SelectedItem;
+ if (participant != null)
+ {
+ ParticipantAssignment participantAssignment = new()
+ {
+ ParticipantId = participant.Id,
+ Type = (int)Extensions.ParticipantType.MOORING
+ };
+ this.ShipcallModel.AssignedParticipants[Extensions.ParticipantType.MOORING] = participantAssignment;
+ }
+ participant = (Participant?)this.comboBoxPilot.SelectedItem;
+ if (participant != null)
+ {
+ ParticipantAssignment participantAssignment = new()
+ {
+ ParticipantId = participant.Id,
+ Type = (int)Extensions.ParticipantType.PILOT
+ };
+ this.ShipcallModel.AssignedParticipants[Extensions.ParticipantType.PILOT] = participantAssignment;
+ }
+ participant = (Participant?)this.comboBoxTerminal.SelectedItem;
+ if (participant != null)
+ {
+ ParticipantAssignment participantAssignment = new()
+ {
+ ParticipantId = participant.Id,
+ Type = (int)Extensions.ParticipantType.TERMINAL
+ };
+ this.ShipcallModel.AssignedParticipants[Extensions.ParticipantType.TERMINAL] = participantAssignment;
+ }
+ participant = (Participant?)this.comboBoxTug.SelectedItem;
+ if (participant != null)
+ {
+ ParticipantAssignment participantAssignment = new()
+ {
+ ParticipantId = participant.Id,
+ Type = (int)Extensions.ParticipantType.TUG
+ };
+ this.ShipcallModel.AssignedParticipants[Extensions.ParticipantType.TUG] = participantAssignment;
+ }
+ }
+ }
+
+ private void CopyToControls()
+ {
+ if (this.ShipcallModel == null) return;
+ if (this.ShipcallModel.Shipcall != null)
+ {
+ if (this.Times.EtdBerth.HasValue)
+ {
+ this.datePickerETD.Value = this.Times.EtdBerth.Value;
+ }
+ else
+ {
+ // if not set through times use value of BSMD entry
+ if (this.ShipcallModel.Shipcall.Etd != DateTime.MinValue)
+ this.datePickerETD.Value = this.ShipcallModel.Shipcall.Etd;
+ }
+
+ if (this.Times.BerthId.HasValue)
+ this.comboBoxDepartureBerth.SelectedValue = this.Times.BerthId;
+ else if (this.ShipcallModel.Shipcall.DepartureBerthId.HasValue)
+ this.comboBoxDepartureBerth.SelectedValue = this.ShipcallModel.Shipcall.DepartureBerthId;
+
+ if (this.ShipcallModel.Shipcall.PierSide.HasValue)
+ {
+ if (this.ShipcallModel.Shipcall.PierSide.Value) this.comboBoxPierside.SelectedIndex = 0;
+ else this.comboBoxPierside.SelectedIndex = 1;
+ }
+ this.textBoxBerthRemarks.Text = this.Times.BerthInfo;
+ this.doubleUpDownDraft.Value = this.ShipcallModel.Shipcall.Draft;
+ this.datePickerTidalWindowFrom.Value = this.ShipcallModel.Shipcall.TidalWindowFrom;
+ this.datePickerTidalWindowTo.Value = this.ShipcallModel.Shipcall.TidalWindowTo;
+ this.checkBoxCanceled.IsChecked = this.ShipcallModel.Shipcall.Canceled ?? false;
+
+ this.checkBoxTugRequired.IsChecked = this.ShipcallModel.Shipcall.TugRequired ?? false;
+ this.integerUpDownRecommendedTugs.Value = this.ShipcallModel.Shipcall.RecommendedTugs;
+ this.checkBoxPilotRequired.IsChecked = this.ShipcallModel.Shipcall.PilotRequired ?? false;
+
+ this.checkBoxMooredLock.IsChecked = this.ShipcallModel.Shipcall.MooredLock ?? false;
+ this.checkBoxRainsensitiveCargo.IsChecked = this.ShipcallModel.Shipcall.RainSensitiveCargo ?? false;
+ if(!string.IsNullOrEmpty(this.Times.Remarks))
+ this.textBoxRemarks.Text = this.Times.Remarks;
+
+ if (this.ShipcallModel.AssignedParticipants.ContainsKey(ParticipantType.MOORING))
+ {
+ if (BreCalLists.ParticipantLookupDict.ContainsKey(this.ShipcallModel.AssignedParticipants[ParticipantType.MOORING].ParticipantId))
+ {
+ this.comboBoxMooring.SelectedValue = this.ShipcallModel.AssignedParticipants[ParticipantType.MOORING].ParticipantId;
+ }
+ }
+
+ if (this.ShipcallModel.AssignedParticipants.ContainsKey(ParticipantType.PILOT))
+ {
+ if (BreCalLists.ParticipantLookupDict.ContainsKey(this.ShipcallModel.AssignedParticipants[ParticipantType.PILOT].ParticipantId))
+ {
+ this.comboBoxPilot.SelectedValue = this.ShipcallModel.AssignedParticipants[ParticipantType.PILOT].ParticipantId;
+ }
+ }
+
+ if (this.ShipcallModel.AssignedParticipants.ContainsKey(ParticipantType.TERMINAL))
+ {
+ if (BreCalLists.ParticipantLookupDict.ContainsKey(this.ShipcallModel.AssignedParticipants[ParticipantType.TERMINAL].ParticipantId))
+ {
+ this.comboBoxTerminal.SelectedValue = this.ShipcallModel.AssignedParticipants[ParticipantType.TERMINAL].ParticipantId;
+ }
+ }
+
+ if (this.ShipcallModel.AssignedParticipants.ContainsKey(ParticipantType.TUG))
+ {
+ if (BreCalLists.ParticipantLookupDict.ContainsKey(this.ShipcallModel.AssignedParticipants[ParticipantType.TUG].ParticipantId))
+ {
+ this.comboBoxTug.SelectedValue = this.ShipcallModel.AssignedParticipants[ParticipantType.TUG].ParticipantId;
+ }
+ }
+
+ }
+ }
+
+ private void EnableControls(bool isEnabled)
+ {
+ this.datePickerETD.IsEnabled = isEnabled;
+ this.comboBoxDepartureBerth.IsEnabled = isEnabled;
+ this.comboBoxPierside.IsEnabled = isEnabled;
+ this.textBoxBerthRemarks.IsEnabled = isEnabled;
+ this.doubleUpDownDraft.IsEnabled = isEnabled;
+ this.datePickerTidalWindowFrom.IsEnabled = isEnabled;
+ this.datePickerTidalWindowTo.IsEnabled = isEnabled;
+ this.checkBoxCanceled.IsEnabled = isEnabled;
+
+ this.checkBoxTugRequired.IsEnabled = isEnabled;
+ this.comboBoxTug.IsEnabled = isEnabled;
+ this.integerUpDownRecommendedTugs.IsEnabled = isEnabled;
+ this.checkBoxPilotRequired.IsEnabled = isEnabled;
+ this.comboBoxPilot.IsEnabled = isEnabled;
+ this.comboBoxMooring.IsEnabled = isEnabled;
+ this.checkBoxMooredLock.IsEnabled = isEnabled;
+ this.comboBoxTerminal.IsEnabled = isEnabled;
+ this.checkBoxRainsensitiveCargo.IsEnabled = isEnabled;
+ this.textBoxRemarks.IsEnabled = isEnabled;
+
+ this.buttonOK.IsEnabled = isEnabled;
+ }
+
+ #endregion
+
+ #region context menu handlers
+
+ private void contextMenuItemClearTug_Click(object sender, RoutedEventArgs e)
+ {
+ this.comboBoxTug.SelectedIndex = -1;
+ this.ShipcallModel.AssignedParticipants.Remove(Extensions.ParticipantType.TUG);
+ }
+
+ private void contextMenuItemClearPilot_Click(object sender, RoutedEventArgs e)
+ {
+ this.comboBoxPilot.SelectedIndex = -1;
+ this.ShipcallModel.AssignedParticipants.Remove(Extensions.ParticipantType.PILOT);
+ }
+
+ private void contextMenuItemClearMooring_Click(object sender, RoutedEventArgs e)
+ {
+ this.comboBoxMooring.SelectedIndex = -1;
+ this.ShipcallModel.AssignedParticipants.Remove(Extensions.ParticipantType.MOORING);
+ }
+
+ private void contextMenuItemDepartureBerth_Click(object sender, RoutedEventArgs e)
+ {
+ this.comboBoxDepartureBerth.SelectedIndex = -1;
+ this.ShipcallModel.Berth = "";
+ }
+
+ private void contextMenuItemClearTerminal_Click(object sender, RoutedEventArgs e)
+ {
+ this.comboBoxTerminal.SelectedIndex = -1;
+ this.ShipcallModel.AssignedParticipants.Remove(Extensions.ParticipantType.TERMINAL);
+ }
+
+ #endregion
+
+ }
+}
diff --git a/src/BreCalClient/EditTimesAgencyShiftingControl.xaml b/src/BreCalClient/EditTimesAgencyShiftingControl.xaml
new file mode 100644
index 0000000..7bcb118
--- /dev/null
+++ b/src/BreCalClient/EditTimesAgencyShiftingControl.xaml
@@ -0,0 +1,158 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/BreCalClient/EditTimesAgencyShiftingControl.xaml.cs b/src/BreCalClient/EditTimesAgencyShiftingControl.xaml.cs
new file mode 100644
index 0000000..86b5dfb
--- /dev/null
+++ b/src/BreCalClient/EditTimesAgencyShiftingControl.xaml.cs
@@ -0,0 +1,313 @@
+// Copyright (c) 2023 schick Informatik
+// Description: Input control for shifting operations
+//
+
+using BreCalClient.misc.Model;
+using System;
+using System.Windows;
+using static BreCalClient.Extensions;
+
+namespace BreCalClient
+{
+ ///
+ /// Interaction logic for EditTimesAgencyShiftingControl.xaml
+ ///
+ public partial class EditTimesAgencyShiftingControl : Window, IEditShipcallTimesControl
+ {
+
+ #region Construction
+
+ public EditTimesAgencyShiftingControl()
+ {
+ InitializeComponent();
+ }
+
+ #endregion
+
+ #region Properties
+
+ public ShipcallControlModel ShipcallModel { get; set; } = new();
+
+ public Times Times { get; set; } = new();
+
+ public Extensions.TypeEnum CallType { get; set; }
+
+ #endregion
+
+ #region event handler
+
+ private void Window_Loaded(object sender, RoutedEventArgs e)
+ {
+ this.comboBoxMooring.ItemsSource = BreCalLists.Participants_Mooring;
+ this.comboBoxPilot.ItemsSource = BreCalLists.Participants_Pilot;
+ this.comboBoxTug.ItemsSource = BreCalLists.Participants_Tug;
+ this.comboBoxTerminal.ItemsSource = BreCalLists.Participants_Terminal;
+
+ this.comboBoxDepartureBerth.ItemsSource = BreCalLists.Berths;
+ this.comboBoxArrivalBerth.ItemsSource = BreCalLists.Berths;
+ this.CopyToControls();
+
+ Participant? p = null;
+ if (this.ShipcallModel.AssignedParticipants.ContainsKey(ParticipantType.AGENCY))
+ p = BreCalLists.Participants.Find(x => x.Id == this.ShipcallModel.AssignedParticipants[ParticipantType.AGENCY].ParticipantId);
+
+ bool allowBSMD = false;
+ if (p != null)
+ {
+ allowBSMD = p.IsFlagSet(ParticipantFlag.ALLOW_BSMD);
+ }
+
+ bool enableControls = (this.Times.ParticipantId == App.Participant.Id) ||
+ (App.Participant.IsTypeFlagSet(ParticipantType.BSMD) && allowBSMD);
+
+ this.EnableControls(enableControls);
+
+ }
+
+ private void buttonOK_Click(object sender, RoutedEventArgs e)
+ {
+ this.CopyToModel();
+ this.DialogResult = true;
+ this.Close();
+ }
+
+ private void buttonCancel_Click(object sender, RoutedEventArgs e)
+ {
+ this.DialogResult = false;
+ this.Close();
+ }
+
+ #endregion
+
+ #region private methods
+
+ private void CopyToModel()
+ {
+ if (this.ShipcallModel.Shipcall != null)
+ {
+ this.Times.EtdBerth = this.datePickerETD.Value;
+ this.Times.EtaBerth = this.datePickerETA.Value;
+ this.ShipcallModel.Shipcall.DepartureBerthId = (int)this.comboBoxDepartureBerth.SelectedValue;
+ if (this.comboBoxPiersideArrival.SelectedIndex >= 0)
+ {
+ this.ShipcallModel.Shipcall.PierSide = (this.comboBoxPiersideArrival.SelectedIndex == 0) ? true : false;
+ }
+
+ this.Times.BerthInfo = this.textBoxBerthRemarksArrival.Text.Trim();
+ this.Times.BerthId = (int?)this.comboBoxArrivalBerth.SelectedValue;
+
+ this.ShipcallModel.Shipcall.Draft = (float?)this.doubleUpDownDraft.Value;
+ this.ShipcallModel.Shipcall.TidalWindowFrom = this.datePickerTidalWindowFrom.Value;
+ this.ShipcallModel.Shipcall.TidalWindowTo = this.datePickerTidalWindowTo.Value;
+ this.ShipcallModel.Shipcall.Canceled = this.checkBoxCanceled.IsChecked;
+
+
+ this.ShipcallModel.Shipcall.TugRequired = this.checkBoxTugRequired.IsChecked;
+ this.ShipcallModel.Shipcall.RecommendedTugs = this.integerUpDownRecommendedTugs.Value;
+ this.ShipcallModel.Shipcall.PilotRequired = this.checkBoxPilotRequired.IsChecked;
+ this.ShipcallModel.Shipcall.MooredLock = this.checkBoxMooredLock.IsChecked;
+ this.ShipcallModel.Shipcall.RainSensitiveCargo = this.checkBoxRainsensitiveCargo.IsChecked;
+ if(!string.IsNullOrEmpty(this.textBoxRemarks.Text.Trim()))
+ this.Times.Remarks = this.textBoxRemarks.Text.Trim();
+
+ Participant? participant = (Participant?)this.comboBoxMooring.SelectedItem;
+ if (participant != null)
+ {
+ ParticipantAssignment pa = new()
+ {
+ ParticipantId = participant.Id,
+ Type = (int)Extensions.ParticipantType.MOORING
+ };
+ this.ShipcallModel.AssignedParticipants[Extensions.ParticipantType.MOORING] = pa;
+ }
+ participant = (Participant?)this.comboBoxPilot.SelectedItem;
+ if (participant != null)
+ {
+ ParticipantAssignment pa = new()
+ {
+ ParticipantId = participant.Id,
+ Type = (int)Extensions.ParticipantType.PILOT
+ };
+ this.ShipcallModel.AssignedParticipants[Extensions.ParticipantType.PILOT] = pa;
+ }
+ participant = (Participant?)this.comboBoxTerminal.SelectedItem;
+ if (participant != null)
+ {
+ ParticipantAssignment pa = new()
+ {
+ ParticipantId = participant.Id,
+ Type = (int)Extensions.ParticipantType.TERMINAL
+ };
+ this.ShipcallModel.AssignedParticipants[Extensions.ParticipantType.TERMINAL] = pa;
+ }
+ participant = (Participant?)this.comboBoxTug.SelectedItem;
+ if (participant != null)
+ {
+ ParticipantAssignment pa = new()
+ {
+ ParticipantId = participant.Id,
+ Type = (int)Extensions.ParticipantType.TUG
+ };
+ this.ShipcallModel.AssignedParticipants[Extensions.ParticipantType.TUG] = pa;
+ }
+ }
+ }
+
+ private void CopyToControls()
+ {
+ if (this.ShipcallModel == null) return;
+ if (this.ShipcallModel.Shipcall != null)
+ {
+ if (this.Times.EtaBerth.HasValue)
+ {
+ this.datePickerETA.Value = this.Times.EtaBerth.Value;
+ }
+ else
+ {
+ // if not set through times use value of BSMD entry
+ if (this.ShipcallModel.Shipcall.Eta != DateTime.MinValue)
+ this.datePickerETA.Value = this.ShipcallModel.Shipcall.Eta;
+ }
+ if(this.Times.EtdBerth.HasValue)
+ {
+ this.datePickerETD.Value = this.Times.EtdBerth.Value;
+ }
+ else
+ {
+ if (this.ShipcallModel.Shipcall.Etd != DateTime.MinValue)
+ this.datePickerETD.Value = this.ShipcallModel.Shipcall.Etd;
+ }
+
+ if (this.Times.BerthId.HasValue)
+ this.comboBoxArrivalBerth.SelectedValue = this.Times.BerthId;
+ else if (this.ShipcallModel.Shipcall.ArrivalBerthId.HasValue)
+ this.comboBoxArrivalBerth.SelectedValue = this.ShipcallModel.Shipcall.ArrivalBerthId;
+
+ if (this.ShipcallModel.Shipcall.DepartureBerthId.HasValue)
+ this.comboBoxDepartureBerth.SelectedValue = this.ShipcallModel.Shipcall.DepartureBerthId;
+
+ if (this.ShipcallModel.Shipcall.PierSide.HasValue)
+ {
+ if (this.ShipcallModel.Shipcall.PierSide.Value) this.comboBoxPiersideArrival.SelectedIndex = 0;
+ else this.comboBoxPiersideArrival.SelectedIndex = 1;
+ }
+ this.textBoxBerthRemarksArrival.Text = this.Times.BerthInfo;
+ this.doubleUpDownDraft.Value = this.ShipcallModel.Shipcall.Draft;
+ this.datePickerTidalWindowFrom.Value = this.ShipcallModel.Shipcall.TidalWindowFrom;
+ this.datePickerTidalWindowTo.Value = this.ShipcallModel.Shipcall.TidalWindowTo;
+ this.checkBoxCanceled.IsChecked = this.ShipcallModel.Shipcall.Canceled ?? false;
+
+ this.checkBoxTugRequired.IsChecked = this.ShipcallModel.Shipcall.TugRequired ?? false;
+ this.integerUpDownRecommendedTugs.Value = this.ShipcallModel.Shipcall.RecommendedTugs;
+ this.checkBoxPilotRequired.IsChecked = this.ShipcallModel.Shipcall.PilotRequired ?? false;
+
+ this.checkBoxMooredLock.IsChecked = this.ShipcallModel.Shipcall.MooredLock ?? false;
+ this.checkBoxRainsensitiveCargo.IsChecked = this.ShipcallModel.Shipcall.RainSensitiveCargo ?? false;
+ if(!string.IsNullOrEmpty(this.Times.Remarks))
+ this.textBoxRemarks.Text = this.Times.Remarks;
+
+ if (this.ShipcallModel.AssignedParticipants.ContainsKey(ParticipantType.MOORING))
+ {
+ if (BreCalLists.ParticipantLookupDict.ContainsKey(this.ShipcallModel.AssignedParticipants[ParticipantType.MOORING].ParticipantId))
+ {
+ this.comboBoxMooring.SelectedValue = this.ShipcallModel.AssignedParticipants[ParticipantType.MOORING].ParticipantId;
+ }
+ }
+
+ if (this.ShipcallModel.AssignedParticipants.ContainsKey(ParticipantType.PILOT))
+ {
+ if (BreCalLists.ParticipantLookupDict.ContainsKey(this.ShipcallModel.AssignedParticipants[ParticipantType.PILOT].ParticipantId))
+ {
+ this.comboBoxPilot.SelectedValue = this.ShipcallModel.AssignedParticipants[ParticipantType.PILOT].ParticipantId;
+ }
+ }
+
+ if (this.ShipcallModel.AssignedParticipants.ContainsKey(ParticipantType.TERMINAL))
+ {
+ if (BreCalLists.ParticipantLookupDict.ContainsKey(this.ShipcallModel.AssignedParticipants[ParticipantType.TERMINAL].ParticipantId))
+ {
+ this.comboBoxTerminal.SelectedValue = this.ShipcallModel.AssignedParticipants[ParticipantType.TERMINAL].ParticipantId;
+ }
+ }
+
+ if (this.ShipcallModel.AssignedParticipants.ContainsKey(ParticipantType.TUG))
+ {
+ if (BreCalLists.ParticipantLookupDict.ContainsKey(this.ShipcallModel.AssignedParticipants[ParticipantType.TUG].ParticipantId))
+ {
+ this.comboBoxTug.SelectedValue = this.ShipcallModel.AssignedParticipants[ParticipantType.TUG].ParticipantId;
+ }
+ }
+ }
+ }
+
+ private void EnableControls(bool isEnabled)
+ {
+ this.datePickerETD.IsEnabled = isEnabled;
+ this.comboBoxArrivalBerth.IsEnabled = isEnabled;
+ this.doubleUpDownDraft.IsEnabled = isEnabled;
+ this.datePickerTidalWindowFrom.IsEnabled = isEnabled;
+ this.datePickerTidalWindowTo.IsEnabled = isEnabled;
+ this.datePickerETA.IsEnabled = isEnabled;
+ this.comboBoxDepartureBerth.IsEnabled = isEnabled;
+ this.comboBoxPiersideArrival.IsEnabled = isEnabled;
+ this.textBoxBerthRemarksArrival.IsEnabled = isEnabled;
+ this.checkBoxCanceled.IsEnabled = isEnabled;
+
+ this.checkBoxTugRequired.IsEnabled = isEnabled;
+ this.comboBoxTug.IsEnabled = isEnabled;
+ this.integerUpDownRecommendedTugs.IsEnabled = isEnabled;
+ this.checkBoxPilotRequired.IsEnabled = isEnabled;
+ this.comboBoxPilot.IsEnabled = isEnabled;
+ this.comboBoxMooring.IsEnabled = isEnabled;
+ this.checkBoxMooredLock.IsEnabled = isEnabled;
+ this.comboBoxTerminal.IsEnabled = isEnabled;
+ this.checkBoxRainsensitiveCargo.IsEnabled = isEnabled;
+ this.textBoxRemarks.IsEnabled = isEnabled;
+
+ this.buttonOK.IsEnabled = isEnabled;
+ }
+
+ #endregion
+
+ #region context menu handlers
+
+ private void contextMenuItemDepartureBerth_Click(object sender, RoutedEventArgs e)
+ {
+ this.comboBoxDepartureBerth.SelectedIndex = -1;
+ this.ShipcallModel.Berth = "";
+ }
+
+ private void contextMenuItemArrivalBerth_Click(object sender, RoutedEventArgs e)
+ {
+ this.comboBoxArrivalBerth.SelectedIndex = -1;
+ this.ShipcallModel.Berth = "";
+ }
+
+ private void contextMenuItemClearTug_Click(object sender, RoutedEventArgs e)
+ {
+ this.comboBoxTug.SelectedIndex = -1;
+ this.ShipcallModel.AssignedParticipants.Remove(Extensions.ParticipantType.TUG);
+ }
+
+ private void contextMenuItemClearPilot_Click(object sender, RoutedEventArgs e)
+ {
+ this.comboBoxPilot.SelectedIndex = -1;
+ this.ShipcallModel.AssignedParticipants.Remove(Extensions.ParticipantType.PILOT);
+ }
+
+ private void contextMenuItemClearMooring_Click(object sender, RoutedEventArgs e)
+ {
+ this.comboBoxMooring.SelectedIndex = -1;
+ this.ShipcallModel.AssignedParticipants.Remove(Extensions.ParticipantType.MOORING);
+ }
+
+ private void contextMenuItemClearTerminal_Click(object sender, RoutedEventArgs e)
+ {
+ this.comboBoxTerminal.SelectedIndex = -1;
+ this.ShipcallModel.AssignedParticipants.Remove(Extensions.ParticipantType.TERMINAL);
+ }
+
+ #endregion
+
+ }
+}
diff --git a/src/BreCalClient/EditTimesControl.xaml b/src/BreCalClient/EditTimesControl.xaml
index 39de9a5..01a78c9 100644
--- a/src/BreCalClient/EditTimesControl.xaml
+++ b/src/BreCalClient/EditTimesControl.xaml
@@ -81,9 +81,9 @@
-
+
-
+
diff --git a/src/BreCalClient/EditTimesControl.xaml.cs b/src/BreCalClient/EditTimesControl.xaml.cs
index c15f1a1..a157705 100644
--- a/src/BreCalClient/EditTimesControl.xaml.cs
+++ b/src/BreCalClient/EditTimesControl.xaml.cs
@@ -27,7 +27,7 @@ namespace BreCalClient
public Times Times { get; set; } = new();
- internal Extensions.ParticipantType ParticipantType { get; set; } = Extensions.ParticipantType.NONE;
+ public Extensions.TypeEnum CallType { get; set; }
#endregion
@@ -36,26 +36,7 @@ namespace BreCalClient
private void Window_Loaded(object sender, RoutedEventArgs e)
{
this.CopyToControls();
- // enable controls according to participant type
- this.datePickerETABerth.IsEnabled = App.Participant.IsTypeFlagSet(Extensions.ParticipantType.AGENCY) ||
- App.Participant.IsTypeFlagSet(Extensions.ParticipantType.MOORING) ||
- App.Participant.IsTypeFlagSet(Extensions.ParticipantType.PILOT) ||
- App.Participant.IsTypeFlagSet(Extensions.ParticipantType.PORT_ADMINISTRATION) ||
- App.Participant.IsTypeFlagSet(Extensions.ParticipantType.TUG);
-
-
- this.checkBoxEtaBerthFixed.IsEnabled = this.datePickerETABerth.IsEnabled;
- this.datePickerETDBerth.IsEnabled = this.datePickerETABerth.IsEnabled;
- this.checkBoxEtDBerthFixed.IsEnabled = this.datePickerETABerth.IsEnabled;
-
- this.datePickerLockTime.IsEnabled = App.Participant.IsTypeFlagSet(Extensions.ParticipantType.AGENCY) ||
- App.Participant.IsTypeFlagSet(Extensions.ParticipantType.MOORING) ||
- App.Participant.IsTypeFlagSet(Extensions.ParticipantType.PORT_ADMINISTRATION);
- this.checkBoxLockTimeFixed.IsEnabled = this.datePickerLockTime.IsEnabled;
-
- this.datePickerZoneEntry.IsEnabled = App.Participant.IsTypeFlagSet(Extensions.ParticipantType.AGENCY) ||
- App.Participant.IsTypeFlagSet(Extensions.ParticipantType.PILOT);
- this.checkBoxZoneEntryFixed.IsEnabled = this.datePickerZoneEntry.IsEnabled;
+ this.EnableControls();
}
private void buttonOK_Click(object sender, RoutedEventArgs e)
@@ -103,6 +84,41 @@ namespace BreCalClient
this.checkBoxZoneEntryFixed.IsChecked = this.Times.ZoneEntryFixed;
}
+ private void EnableControls()
+ {
+ Extensions.ParticipantType pType = (Extensions.ParticipantType) (this.Times.ParticipantType ?? 0);
+ if (this.Times.ParticipantId != App.Participant.Id) return; // if this is not "my" entry, there is no editing!
+
+ switch (pType)
+ {
+ case Extensions.ParticipantType.MOORING:
+ case Extensions.ParticipantType.PORT_ADMINISTRATION:
+ case Extensions.ParticipantType.TUG:
+ this.datePickerETABerth.IsEnabled = (CallType == Extensions.TypeEnum.Incoming || CallType == Extensions.TypeEnum.Shifting);
+ this.checkBoxEtaBerthFixed.IsEnabled = (CallType == Extensions.TypeEnum.Incoming || CallType == Extensions.TypeEnum.Shifting);
+ this.datePickerETDBerth.IsEnabled = (CallType == Extensions.TypeEnum.Outgoing || CallType == Extensions.TypeEnum.Shifting);
+ this.checkBoxEtDBerthFixed.IsEnabled = (CallType == Extensions.TypeEnum.Outgoing || CallType == Extensions.TypeEnum.Shifting);
+ this.datePickerLockTime.IsEnabled = (CallType == Extensions.TypeEnum.Incoming || CallType == Extensions.TypeEnum.Shifting);
+ this.checkBoxLockTimeFixed.IsEnabled = (CallType == Extensions.TypeEnum.Incoming || CallType == Extensions.TypeEnum.Shifting);
+ this.datePickerZoneEntry.IsEnabled = false;
+ this.checkBoxZoneEntryFixed.IsEnabled = false;
+ this.textBoxRemarks.IsEnabled = true;
+ break;
+ case Extensions.ParticipantType.PILOT:
+ this.datePickerETABerth.IsEnabled = (CallType == Extensions.TypeEnum.Incoming || CallType == Extensions.TypeEnum.Shifting);
+ this.checkBoxEtaBerthFixed.IsEnabled = (CallType == Extensions.TypeEnum.Incoming || CallType == Extensions.TypeEnum.Shifting);
+ this.datePickerETDBerth.IsEnabled = (CallType == Extensions.TypeEnum.Outgoing || CallType == Extensions.TypeEnum.Shifting);
+ this.checkBoxEtDBerthFixed.IsEnabled = (CallType == Extensions.TypeEnum.Outgoing || CallType == Extensions.TypeEnum.Shifting);
+ this.datePickerLockTime.IsEnabled = (CallType == Extensions.TypeEnum.Incoming || CallType == Extensions.TypeEnum.Shifting);
+ this.checkBoxLockTimeFixed.IsEnabled = (CallType == Extensions.TypeEnum.Incoming || CallType == Extensions.TypeEnum.Shifting);
+ this.datePickerZoneEntry.IsEnabled = (CallType == Extensions.TypeEnum.Incoming);
+ this.checkBoxZoneEntryFixed.IsEnabled = (CallType == Extensions.TypeEnum.Incoming);
+ this.textBoxRemarks.IsEnabled = true;
+ break;
+ }
+ this.buttonOK.IsEnabled = true;
+ }
+
#endregion
#region clear value event handler
diff --git a/src/BreCalClient/EditTimesTerminalControl.xaml b/src/BreCalClient/EditTimesTerminalControl.xaml
index e93115d..1df1810 100644
--- a/src/BreCalClient/EditTimesTerminalControl.xaml
+++ b/src/BreCalClient/EditTimesTerminalControl.xaml
@@ -32,7 +32,7 @@
-
+
@@ -43,7 +43,7 @@
-
+
@@ -54,21 +54,21 @@
-
+
-
+
-
-
+
+
-
+
diff --git a/src/BreCalClient/EditTimesTerminalControl.xaml.cs b/src/BreCalClient/EditTimesTerminalControl.xaml.cs
index cc7e277..ea9f257 100644
--- a/src/BreCalClient/EditTimesTerminalControl.xaml.cs
+++ b/src/BreCalClient/EditTimesTerminalControl.xaml.cs
@@ -3,19 +3,7 @@
//
using BreCalClient.misc.Model;
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
using System.Windows;
-using System.Windows.Controls;
-using System.Windows.Data;
-using System.Windows.Documents;
-using System.Windows.Input;
-using System.Windows.Media;
-using System.Windows.Media.Imaging;
-using System.Windows.Shapes;
namespace BreCalClient
{
@@ -31,9 +19,9 @@ namespace BreCalClient
#region Properties
- public Times Times { get; set; } = new();
-
- public List Berths { get; set; }
+ public Times Times { get; set; } = new();
+
+ public Extensions.TypeEnum CallType { get; set; }
#endregion
@@ -41,8 +29,9 @@ namespace BreCalClient
private void Window_Loaded(object sender, RoutedEventArgs e)
{
- this.comboBoxBerth.ItemsSource = this.Berths;
+ this.comboBoxBerth.ItemsSource = BreCalLists.Berths;
this.CopyToControls();
+ this.EnableControls();
}
private void contextMenuItemClearOperationStart_Click(object sender, RoutedEventArgs e)
@@ -103,8 +92,20 @@ namespace BreCalClient
this.textBoxBerthRemarks.Text = this.Times.BerthInfo;
}
- #endregion
+ private void EnableControls()
+ {
+ if (this.Times.ParticipantId != App.Participant.Id) return;
+ this.datePickerOperationStart.IsEnabled = (CallType == Extensions.TypeEnum.Incoming) || (CallType == Extensions.TypeEnum.Shifting);
+ this.datePickerOperationEnd.IsEnabled = (CallType == Extensions.TypeEnum.Outgoing) || (CallType == Extensions.TypeEnum.Shifting);
+ this.comboBoxBerth.IsEnabled = (CallType == Extensions.TypeEnum.Incoming) || (CallType == Extensions.TypeEnum.Shifting);
+ this.comboBoxPierside.IsEnabled = (CallType == Extensions.TypeEnum.Incoming) || (CallType == Extensions.TypeEnum.Shifting);
+ this.textBoxBerthRemarks.IsEnabled = (CallType == Extensions.TypeEnum.Incoming) || (CallType == Extensions.TypeEnum.Shifting);
+ this.textBoxRemarks.IsEnabled = true;
+ this.buttonOK.IsEnabled = true;
+ }
+
+ #endregion
}
}
diff --git a/src/BreCalClient/Extensions.cs b/src/BreCalClient/Extensions.cs
index 1a93d42..2d15fc9 100644
--- a/src/BreCalClient/Extensions.cs
+++ b/src/BreCalClient/Extensions.cs
@@ -4,15 +4,11 @@
using BreCalClient.misc.Model;
using System;
-using System.Collections.Generic;
using System.ComponentModel;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
namespace BreCalClient
{
- internal static class Extensions
+ public static class Extensions
{
#region Enum
diff --git a/src/BreCalClient/IEditTimesControl.cs b/src/BreCalClient/IEditTimesControl.cs
index b4497f6..aaaf669 100644
--- a/src/BreCalClient/IEditTimesControl.cs
+++ b/src/BreCalClient/IEditTimesControl.cs
@@ -1,9 +1,9 @@
-using BreCalClient.misc.Model;
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
+// Copyright (c) 2023 schick Informatik
+// Description: Interfaces to simplify dialog handling
+//
+
+using BreCalClient.misc.Model;
+
namespace BreCalClient
{
@@ -11,7 +11,15 @@ namespace BreCalClient
{
Times Times { get; set; }
+ Extensions.TypeEnum CallType { get; set; }
+
bool? ShowDialog();
}
+
+ internal interface IEditShipcallTimesControl : IEditTimesControl
+ {
+ ShipcallControlModel ShipcallModel { get; set; }
+ }
+
}
diff --git a/src/BreCalClient/MainWindow.xaml b/src/BreCalClient/MainWindow.xaml
index b87b972..39ba515 100644
--- a/src/BreCalClient/MainWindow.xaml
+++ b/src/BreCalClient/MainWindow.xaml
@@ -72,7 +72,7 @@
-
+
diff --git a/src/BreCalClient/MainWindow.xaml.cs b/src/BreCalClient/MainWindow.xaml.cs
index 61f6fe5..e5f21ea 100644
--- a/src/BreCalClient/MainWindow.xaml.cs
+++ b/src/BreCalClient/MainWindow.xaml.cs
@@ -2,19 +2,21 @@
// Description: Bremen calling main window
//
-using BreCalClient.misc.Api;
-using BreCalClient.misc.Client;
-using BreCalClient.misc.Model;
using System;
-using System.Collections.Concurrent;
using System.Collections.Generic;
-using System.Collections.ObjectModel;
using System.Diagnostics;
-using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
+
+using log4net;
+
+using BreCalClient.misc.Api;
+using BreCalClient.misc.Client;
+using BreCalClient.misc.Model;
+
using static BreCalClient.Extensions;
+using System.Collections.Concurrent;
namespace BreCalClient
{
@@ -23,33 +25,30 @@ namespace BreCalClient
///
public partial class MainWindow : Window
{
+ private readonly ILog _log = LogManager.GetLogger(typeof(MainWindow));
private const int SHIPCALL_UPDATE_INTERVAL_SECONDS = 30;
#region Fields
-
+ private static Int32 _uiUpdateRunning = 0;
- private readonly Dictionary _allShipcallsDict = new();
- private readonly Dictionary _allShipCallsControlDict = new();
+ private Timer? _timer;
+ private Credentials? _credentials;
- private readonly List _visibleControlModels = new();
-
-
- private List _ships = new();
- private readonly ConcurrentDictionary _shipLookupDict = new();
- private List _berths = new();
- private readonly ConcurrentDictionary _berthLookupDict = new();
- private List _participants = new();
- private readonly Dictionary _participantLookupDict = new();
+ private readonly ConcurrentDictionary _allShipcallsDict = new();
+ private readonly ConcurrentDictionary _allShipCallsControlDict = new();
+ private readonly List _visibleControlModels = new();
private readonly DefaultApi _api;
- private readonly CancellationTokenSource _tokenSource = new();
+ private CancellationTokenSource _tokenSource = new();
private LoginResult? _loginResult;
private bool _refreshImmediately = false;
private bool? _showCanceled = null;
- private Extensions.SortOrder? _sortOrder;
+ private SortOrder? _sortOrder;
+ private int searchPastDays = 0;
+
// private bool _filterChanged = false;
// private bool _sequenceChanged = false;
@@ -71,8 +70,8 @@ namespace BreCalClient
public MainWindow()
{
InitializeComponent();
- _api = new DefaultApi();
- _api.Configuration.ApiKeyPrefix["Authorization"] = "Bearer";
+ _api = new DefaultApi(Properties.Settings.Default.API_URL);
+ _api.Configuration.ApiKeyPrefix["Authorization"] = "Bearer";
}
#endregion
@@ -109,12 +108,11 @@ namespace BreCalClient
return;
}
- Credentials credentials = new(username: textUsername.Text.Trim(),
- password: textPassword.Password.Trim());
+ _credentials = new(username: textUsername.Text.Trim(), password: textPassword.Password.Trim());
try
{
- _loginResult = await _api.LoginPostAsync(credentials);
+ _loginResult = await _api.LoginPostAsync(_credentials);
if (_loginResult != null)
{
if (_loginResult.Id > 0)
@@ -122,7 +120,8 @@ namespace BreCalClient
this.busyIndicator.IsBusy = false;
this._api.Configuration.ApiKey["Authorization"] = _loginResult.Token;
this.LoadStaticLists();
- this.labelUsername.Text = $"{_loginResult.FirstName} {_loginResult.LastName}";
+ this.labelUsername.Text = $"{_loginResult.FirstName} {_loginResult.LastName}";
+ _timer = new Timer(RefreshToken, null, 4000000, Timeout.Infinite);
}
}
labelGeneralStatus.Text = $"Connection {ConnectionStatus.SUCCESSFUL}";
@@ -139,6 +138,29 @@ namespace BreCalClient
}
}
+ private void RefreshToken(object? state)
+ {
+ try
+ {
+ _loginResult = _api.LoginPost(_credentials);
+ if (_loginResult != null)
+ {
+ if (_loginResult.Id > 0)
+ {
+ this._api.Configuration.ApiKey["Authorization"] = _loginResult.Token;
+ }
+ }
+ else
+ {
+ _log.Error("Token refresh: Renewed login returned empty login result");
+ }
+ }
+ catch (Exception ex)
+ {
+ _log.ErrorFormat("Error refreshing token: {0}", ex.Message);
+ }
+ }
+
private void buttonExit_Click(object sender, RoutedEventArgs e)
{
this.Close();
@@ -146,12 +168,7 @@ namespace BreCalClient
private void buttonNew_Click(object sender, RoutedEventArgs e)
{
- EditShipcallControl esc = new()
- {
- Participants = this._participants,
- Ships = this._ships,
- Berths = this._berths
- };
+ EditShipcallControl esc = new();
if (esc.ShowDialog() ?? false)
{
@@ -160,6 +177,9 @@ namespace BreCalClient
{
this.UpdateUI();
+ esc.ShipcallModel.Shipcall?.Participants.Clear();
+ foreach (ParticipantAssignment pa in esc.ShipcallModel.AssignedParticipants.Values)
+ esc.ShipcallModel.Shipcall?.Participants.Add(pa);
this._api.ShipcallsPost(esc.ShipcallModel.Shipcall); // save new ship call
this.AddShipcall(esc.ShipcallModel);
@@ -172,6 +192,7 @@ namespace BreCalClient
private void buttonInfo_Click(object sender, RoutedEventArgs e)
{
AboutDialog ad = new();
+ ad.LoginResult = this._loginResult;
ad.ChangePasswordRequested += async (oldPw, newPw) =>
{
if (_loginResult != null)
@@ -182,6 +203,7 @@ namespace BreCalClient
FirstName = _loginResult.FirstName,
LastName = _loginResult.LastName,
UserPhone = _loginResult.UserPhone,
+ UserEmail = _loginResult.UserEmail,
OldPassword = oldPw,
NewPassword = newPw
};
@@ -234,28 +256,22 @@ namespace BreCalClient
private async void LoadStaticLists()
{
- this._berths = await _api.BerthsGetAsync();
- foreach(var berth in this._berths)
- _berthLookupDict[berth.Id] = berth;
- this.searchFilterControl.SetBerths(this._berths);
- this._ships = await _api.ShipsGetAsync();
- foreach(var ship in this._ships)
- _shipLookupDict[ship.Id] = ship;
- this._participants = await _api.ParticipantsGetAsync();
+ BreCalLists.InitializeBerths(await _api.BerthsGetAsync());
+ BreCalLists.InitializeShips(await _api.ShipsGetAsync());
+ BreCalLists.InitializeParticipants(await _api.ParticipantsGetAsync());
- List agencies = new();
- foreach (Participant participant in this._participants)
- {
- this._participantLookupDict[participant.Id] = participant;
+ this.searchFilterControl.SetBerths(BreCalLists.Berths);
+
+ foreach (Participant participant in BreCalLists.Participants)
+ {
if (_loginResult?.ParticipantId == participant.Id)
{
App.Participant = participant;
EnableControlsForParticipant();
- }
- if(participant.IsTypeFlagSet(Extensions.ParticipantType.AGENCY))
- agencies.Add(participant);
+ }
}
- this.searchFilterControl.SetAgencies(agencies);
+
+ this.searchFilterControl.SetAgencies(BreCalLists.Participants_Agent);
if (!string.IsNullOrEmpty(Properties.Settings.Default.FilterCriteria))
{
@@ -271,11 +287,21 @@ namespace BreCalClient
{
while (!_tokenSource.Token.IsCancellationRequested || _refreshImmediately)
{
- _refreshImmediately = false;
+
+ if (_refreshImmediately)
+ {
+ _refreshImmediately = false;
+ _tokenSource = new CancellationTokenSource();
+ }
+
List? shipcalls = null;
try
{
- shipcalls = await _api.ShipcallsGetAsync();
+ if(this.searchPastDays != 0)
+ shipcalls = await _api.ShipcallsGetAsync(this.searchPastDays);
+ else
+ shipcalls = await _api.ShipcallsGetAsync();
+
this.Dispatcher.Invoke(new Action(() =>
{
labelGeneralStatus.Text = $"Connection {ConnectionStatus.SUCCESSFUL}";
@@ -283,12 +309,17 @@ namespace BreCalClient
}));
}
catch (Exception ex)
- {
+ {
this.Dispatcher.Invoke(new Action(() =>
{
labelGeneralStatus.Text = $"Connection {ConnectionStatus.FAILED}";
labelStatusBar.Text = ex.Message;
}));
+
+ if (ex.Message.Contains("access", StringComparison.OrdinalIgnoreCase))
+ {
+ this.RefreshToken(null);
+ }
}
if (shipcalls != null)
@@ -313,7 +344,7 @@ namespace BreCalClient
// update entry
_allShipcallsDict[shipcall.Id].Shipcall = shipcall;
_allShipcallsDict[shipcall.Id].Times = currentTimes;
- this.UpdateShipcall(_allShipcallsDict[shipcall.Id]);
+ UpdateShipcall(_allShipcallsDict[shipcall.Id]);
}
}
@@ -349,37 +380,44 @@ namespace BreCalClient
_allShipcallsDict[scm.Shipcall.Id] = scm;
Shipcall shipcall = scm.Shipcall;
- if (this._shipLookupDict.ContainsKey(shipcall.ShipId))
- scm.Ship = this._shipLookupDict[shipcall.ShipId];
- if (this._berthLookupDict.ContainsKey(shipcall.ArrivalBerthId ?? 0))
- scm.Berth = this._berthLookupDict[shipcall.ArrivalBerthId ?? 0].Name;
- scm.AssignParticipants(this._participants);
+ if (BreCalLists.ShipLookupDict.ContainsKey(shipcall.ShipId))
+ scm.Ship = BreCalLists.ShipLookupDict[shipcall.ShipId];
+ if (shipcall.Type == 1)
+ {
+ if (BreCalLists.BerthLookupDict.ContainsKey(shipcall.ArrivalBerthId ?? 0))
+ scm.Berth = BreCalLists.BerthLookupDict[shipcall.ArrivalBerthId ?? 0].Name;
+ }
+ else
+ {
+ if (BreCalLists.BerthLookupDict.ContainsKey(shipcall.DepartureBerthId ?? 0))
+ scm.Berth = BreCalLists.BerthLookupDict[shipcall.DepartureBerthId ?? 0].Name;
+ }
+ scm.AssignParticipants();
this.Dispatcher.Invoke(() =>
{
ShipcallControl sc = new()
{
Height = 120,
- ShipcallControlModel = scm,
- ParticipantDict = _participantLookupDict,
- Berths = _berths
+ ShipcallControlModel = scm
};
sc.EditTimesRequested += Sc_EditTimesRequested;
sc.EditRequested += Sc_EditRequested;
+ sc.EditAgencyRequested += Sc_EditAgencyRequested;
sc.RefreshData();
this._allShipCallsControlDict[scm.Shipcall.Id] = sc;
});
- }
+ }
- private void UpdateShipcall(ShipcallControlModel scm)
+ private static void UpdateShipcall(ShipcallControlModel scm)
{
if(scm.Shipcall == null) return;
Shipcall shipcall = scm.Shipcall;
- if (this._shipLookupDict.ContainsKey(shipcall.ShipId))
- scm.Ship = this._shipLookupDict[shipcall.ShipId];
- if (this._berthLookupDict.ContainsKey(shipcall.ArrivalBerthId ?? 0))
- scm.Berth = this._berthLookupDict[shipcall.ArrivalBerthId ?? 0].Name;
- scm.AssignParticipants(this._participants);
+ if (BreCalLists.ShipLookupDict.ContainsKey(shipcall.ShipId))
+ scm.Ship = BreCalLists.ShipLookupDict[shipcall.ShipId];
+ if (BreCalLists.BerthLookupDict.ContainsKey(shipcall.ArrivalBerthId ?? 0))
+ scm.Berth = BreCalLists.BerthLookupDict[shipcall.ArrivalBerthId ?? 0].Name;
+ scm.AssignParticipants();
}
private void RemoveShipcall(int shipcallId)
@@ -392,14 +430,29 @@ namespace BreCalClient
ShipcallControlModel removeModel = this._allShipcallsDict[shipcallId];
_visibleControlModels.Remove(removeModel);
- this._allShipCallsControlDict.Remove(shipcallId);
- this._allShipcallsDict.Remove(shipcallId);
+ this._allShipCallsControlDict.Remove(shipcallId, out _);
+ this._allShipcallsDict.Remove(shipcallId, out _);
}
private void FilterShipcalls()
{
SearchFilterModel sfm = this.searchFilterControl.SearchFilter;
+ if( sfm.EtaFrom.HasValue && sfm.EtaFrom < DateTime.Now.AddDays(-2))
+ {
+ int daysInThePast = (int)Math.Ceiling((DateTime.Now - sfm.EtaFrom.Value).TotalDays);
+ if (this.searchPastDays != daysInThePast)
+ {
+ this.searchPastDays = daysInThePast;
+ _refreshImmediately = true; // set flag to avoid timer loop termination
+ _tokenSource.Cancel(); // force timer loop end
+ }
+ }
+ else
+ {
+ searchPastDays = 0;
+ }
+
this._visibleControlModels.Clear();
// first add everything
this._visibleControlModels.AddRange(_allShipcallsDict.Values);
@@ -413,42 +466,50 @@ namespace BreCalClient
if(sfm.Agencies.Count > 0 )
{
- this._visibleControlModels.RemoveAll(x => !sfm.Agencies.Contains((x.GetParticipantIdForType(Extensions.ParticipantType.AGENCY)) ?? -1));
+ _ = this._visibleControlModels.RemoveAll((x) =>
+ {
+ Participant? agency = x.GetParticipantForType(ParticipantType.AGENCY);
+ if(agency != null)
+ {
+ return !sfm.Agencies.Contains(agency.Id);
+ }
+ return true;
+ });
}
if(sfm.Categories.Count > 0 )
{
- this._visibleControlModels.RemoveAll(x => !sfm.Categories.Contains((x.Shipcall?.Type) ?? -1));
+ _ = this._visibleControlModels.RemoveAll(x => !sfm.Categories.Contains((x.Shipcall?.Type) ?? -1));
}
if(!string.IsNullOrEmpty(sfm.SearchString))
{
- this._visibleControlModels.RemoveAll(x => !x.ContainsRemarkText(sfm.SearchString));
+ _ = this._visibleControlModels.RemoveAll(x => !(x.ContainsRemarkText(sfm.SearchString) || (x.Ship?.Name.Contains(sfm.SearchString, StringComparison.InvariantCultureIgnoreCase) ?? false)));
}
if(sfm.ShipLengthTo != null)
{
- this._visibleControlModels.RemoveAll(x => x.Ship?.Length > sfm.ShipLengthTo);
+ _ = this._visibleControlModels.RemoveAll(x => x.Ship?.Length > sfm.ShipLengthTo);
}
if(sfm.ShipLengthFrom != null)
{
- this._visibleControlModels.RemoveAll(x => x.Ship?.Length < sfm.ShipLengthFrom);
+ _ = this._visibleControlModels.RemoveAll(x => x.Ship?.Length < sfm.ShipLengthFrom);
}
if(sfm.EtaFrom != null)
{
- this._visibleControlModels.RemoveAll(x => x.Shipcall?.Eta < sfm.EtaFrom);
+ _ = this._visibleControlModels.RemoveAll(x => x.Shipcall?.Eta < sfm.EtaFrom);
}
if(sfm.EtaTo != null)
{
- this._visibleControlModels.RemoveAll(x => x.Shipcall?.Eta > sfm.EtaTo);
+ _ = this._visibleControlModels.RemoveAll(x => x.Shipcall?.Eta > sfm.EtaTo);
}
if(!_showCanceled ?? true) // canceled calls are filtered by default
{
- this._visibleControlModels.RemoveAll(x => x.Shipcall?.Canceled ?? true);
+ _ = this._visibleControlModels.RemoveAll(x => x.Shipcall?.Canceled ?? false);
}
if (this._sortOrder != null)
@@ -466,8 +527,8 @@ namespace BreCalClient
{
if (x.Shipcall == null) return 0;
if (y.Shipcall == null) return 0;
- DateTime xDate = (x.Shipcall.Type == (int) Extensions.TypeEnum.Incoming) ? x.Shipcall.Eta : x.Shipcall.Etd ?? x.Shipcall.Eta;
- DateTime yDate = (y.Shipcall.Type == (int) Extensions.TypeEnum.Incoming) ? y.Shipcall.Eta : y.Shipcall.Etd ?? y.Shipcall.Eta;
+ DateTime xDate = (x.Shipcall.Type == (int) Extensions.TypeEnum.Incoming) ? x.Shipcall.Eta ?? DateTime.Now : x.Shipcall.Etd ?? DateTime.Now;
+ DateTime yDate = (y.Shipcall.Type == (int) Extensions.TypeEnum.Incoming) ? y.Shipcall.Eta ?? DateTime.Now : y.Shipcall.Etd ?? DateTime.Now;
return DateTime.Compare(xDate, yDate);
});
break;
@@ -477,28 +538,45 @@ namespace BreCalClient
}
}
-
+
#endregion
+ #region UpdateUI func
+
private void UpdateUI()
{
this.Dispatcher.Invoke(new Action(() =>
{
- this.stackPanel.Children.Clear();
- foreach(ShipcallControlModel visibleModel in this._visibleControlModels)
+ if (Interlocked.CompareExchange(ref _uiUpdateRunning, 1, 0) == 1) return;
+
+ try
{
- if (visibleModel.Shipcall == null) continue; // should not happen
- if(this._allShipCallsControlDict.ContainsKey(visibleModel.Shipcall.Id))
+ this.stackPanel.Children.Clear();
+ foreach (ShipcallControlModel visibleModel in this._visibleControlModels)
{
- this._allShipCallsControlDict[visibleModel.Shipcall.Id].RefreshData();
- this.stackPanel.Children.Add(this._allShipCallsControlDict[visibleModel.Shipcall.Id]);
+ if (visibleModel.Shipcall == null) continue; // should not happen
+ if (this._allShipCallsControlDict.ContainsKey(visibleModel.Shipcall.Id))
+ {
+ this._allShipCallsControlDict[visibleModel.Shipcall.Id].RefreshData();
+ this.stackPanel.Children.Add(this._allShipCallsControlDict[visibleModel.Shipcall.Id]);
+ }
}
}
+ catch(Exception e) {
+ _log.ErrorFormat("Exception running ui update: {0}", e.ToString());
+ }
+ finally
+ {
+ _uiUpdateRunning = 0;
+ }
+
}));
}
+ #endregion
+
#region control event handler
private async void Sc_EditRequested(ShipcallControl obj)
@@ -507,16 +585,17 @@ namespace BreCalClient
{
EditShipcallControl esc = new()
{
- ShipcallModel = obj.ShipcallControlModel,
- Ships = _ships,
- Participants = _participants,
- Berths = _berths
+ ShipcallModel = obj.ShipcallControlModel
};
if(esc.ShowDialog() ?? false)
{
try
{
+ obj.ShipcallControlModel.Shipcall?.Participants.Clear();
+ obj.ShipcallControlModel.UpdateTimesAssignments(this._api);
+ foreach(ParticipantAssignment pa in obj.ShipcallControlModel.AssignedParticipants.Values)
+ obj.ShipcallControlModel.Shipcall?.Participants.Add(pa);
await _api.ShipcallsPutAsync(obj.ShipcallControlModel.Shipcall);
obj.RefreshData();
_refreshImmediately = true;
@@ -532,10 +611,15 @@ namespace BreCalClient
private async void Sc_EditTimesRequested(ShipcallControl obj, Times? times, Extensions.ParticipantType participantType)
{
+
+ if( obj.ShipcallControlModel == null) { return; }
+ if (!obj.ShipcallControlModel.AssignedParticipants.ContainsKey(participantType)) return; // no assigment means no dialog my friend
+
// show a dialog that lets the user create / update times for the given shipcall
IEditTimesControl etc = (participantType == ParticipantType.TERMINAL) ? new EditTimesTerminalControl() : new EditTimesControl();
- if (etc is EditTimesTerminalControl ettc)
- ettc.Berths = this._berths;
+
+ if(obj.ShipcallControlModel.Shipcall != null)
+ etc.CallType = (TypeEnum) obj.ShipcallControlModel.Shipcall.Type;
bool wasEdit = false;
if (times != null)
@@ -543,6 +627,13 @@ namespace BreCalClient
etc.Times = times;
wasEdit = true;
}
+ else
+ {
+ if(obj.ShipcallControlModel.AssignedParticipants[participantType].ParticipantId == App.Participant.Id)
+ {
+ etc.Times.ParticipantId = App.Participant.Id; // this is my record, so the Participant Id is set that allows editing
+ }
+ }
// actually we should only do this on create but we have existing data
etc.Times.ParticipantType = (int) participantType;
@@ -562,7 +653,8 @@ namespace BreCalClient
{
etc.Times.ShipcallId = obj.ShipcallControlModel.Shipcall.Id;
}
- await _api.TimesPostAsync(etc.Times);
+ Id apiResultId = await _api.TimesPostAsync(etc.Times);
+ etc.Times.Id = apiResultId.VarId;
obj.ShipcallControlModel?.Times.Add(etc.Times);
}
_refreshImmediately = true;
@@ -575,6 +667,84 @@ namespace BreCalClient
}
}
+ private async void Sc_EditAgencyRequested(ShipcallControl sc, Times? times)
+ {
+ IEditShipcallTimesControl? editControl = null;
+ switch(sc.ShipcallControlModel?.Shipcall?.Type)
+ {
+ case (int)TypeEnum.Incoming:
+ editControl = new EditTimesAgencyIncomingControl();
+ break;
+ case (int)TypeEnum.Outgoing:
+ editControl = new EditTimesAgencyOutgoingControl();
+ break;
+ case (int)TypeEnum.Shifting:
+ editControl = new EditTimesAgencyShiftingControl();
+ break;
+ }
+
+ if (editControl != null)
+ {
+ editControl.ShipcallModel = sc.ShipcallControlModel ?? new ShipcallControlModel();
+ bool wasEdit = false;
+ if (times != null)
+ {
+ editControl.Times = times;
+ wasEdit = true;
+ }
+ else
+ {
+ if(editControl.ShipcallModel.AssignedParticipants.ContainsKey(ParticipantType.AGENCY))
+ editControl.Times.ParticipantId = editControl.ShipcallModel.AssignedParticipants[ParticipantType.AGENCY].ParticipantId;
+ }
+ editControl.Times.ParticipantType = (int)ParticipantType.AGENCY;
+ if(editControl.ShowDialog() ?? false)
+ {
+ try
+ {
+ sc.ShipcallControlModel?.UpdateTimesAssignments(_api); // if the agent changed the assignment of the participant to another
+
+ // always try to be the agent, even if we are BSMD
+ if (editControl.ShipcallModel.AssignedParticipants.ContainsKey(ParticipantType.AGENCY))
+ {
+ editControl.Times.ParticipantId = editControl.ShipcallModel.AssignedParticipants[ParticipantType.AGENCY].ParticipantId;
+ }
+ else
+ {
+ editControl.Times.ParticipantId = App.Participant.Id;
+ }
+
+ if (wasEdit)
+ {
+ await _api.TimesPutAsync(editControl.Times);
+ }
+ else
+ {
+ if ((sc.ShipcallControlModel != null) && (sc.ShipcallControlModel.Shipcall != null))
+ {
+ editControl.Times.ShipcallId = sc.ShipcallControlModel.Shipcall.Id;
+ }
+ Id resultAPI_Id = await _api.TimesPostAsync(editControl.Times);
+ editControl.Times.Id = resultAPI_Id.VarId;
+
+ sc.ShipcallControlModel?.Times.Add(editControl.Times);
+ }
+ editControl.ShipcallModel.Shipcall?.Participants.Clear();
+ foreach (ParticipantAssignment pa in editControl.ShipcallModel.AssignedParticipants.Values)
+ editControl.ShipcallModel.Shipcall?.Participants.Add(pa);
+ await _api.ShipcallsPutAsync(editControl.ShipcallModel.Shipcall);
+ _refreshImmediately = true;
+ _tokenSource.Cancel();
+ }
+ catch(Exception ex)
+ {
+ ShowErrorDialog(ex.Message, "Error saving agency information");
+ }
+ }
+ }
+
+ }
+
#endregion
#region helper
diff --git a/src/BreCalClient/Properties/PublishProfiles/ClickOnceProfile.pubxml b/src/BreCalClient/Properties/PublishProfiles/ClickOnceProfile.pubxml
index a262fac..fdb647f 100644
--- a/src/BreCalClient/Properties/PublishProfiles/ClickOnceProfile.pubxml
+++ b/src/BreCalClient/Properties/PublishProfiles/ClickOnceProfile.pubxml
@@ -5,7 +5,7 @@ https://go.microsoft.com/fwlink/?LinkID=208121.
0
- 0.6.0.0
+ 0.9.4.0
False
Release
True
diff --git a/src/BreCalClient/Properties/PublishProfiles/ClickOnceTestProfile.pubxml b/src/BreCalClient/Properties/PublishProfiles/ClickOnceTestProfile.pubxml
index c1f63d2..f423bad 100644
--- a/src/BreCalClient/Properties/PublishProfiles/ClickOnceTestProfile.pubxml
+++ b/src/BreCalClient/Properties/PublishProfiles/ClickOnceTestProfile.pubxml
@@ -5,7 +5,7 @@ https://go.microsoft.com/fwlink/?LinkID=208121.
0
- 0.6.2.0
+ 0.9.4.0
False
Debug
True
diff --git a/src/BreCalClient/Resources/Resources.Designer.cs b/src/BreCalClient/Resources/Resources.Designer.cs
index ed9cb7c..d020a2a 100644
--- a/src/BreCalClient/Resources/Resources.Designer.cs
+++ b/src/BreCalClient/Resources/Resources.Designer.cs
@@ -110,6 +110,16 @@ namespace BreCalClient.Resources {
}
}
+ ///
+ /// Looks up a localized resource of type System.Byte[].
+ ///
+ public static byte[] check {
+ get {
+ object obj = ResourceManager.GetObject("check", resourceCulture);
+ return ((byte[])(obj));
+ }
+ }
+
///
/// Looks up a localized resource of type System.Byte[].
///
@@ -160,6 +170,16 @@ namespace BreCalClient.Resources {
}
}
+ ///
+ /// Looks up a localized resource of type System.Byte[].
+ ///
+ public static byte[] delete2 {
+ get {
+ object obj = ResourceManager.GetObject("delete2", resourceCulture);
+ return ((byte[])(obj));
+ }
+ }
+
///
/// Looks up a localized resource of type System.Byte[].
///
@@ -190,6 +210,16 @@ namespace BreCalClient.Resources {
}
}
+ ///
+ /// Looks up a localized resource of type System.Byte[].
+ ///
+ public static byte[] sign_warning {
+ get {
+ object obj = ResourceManager.GetObject("sign_warning", resourceCulture);
+ return ((byte[])(obj));
+ }
+ }
+
///
/// Looks up a localized string similar to Agencies.
///
@@ -316,6 +346,15 @@ namespace BreCalClient.Resources {
}
}
+ ///
+ /// Looks up a localized string similar to Update contact info.
+ ///
+ public static string textChangeContactInfo {
+ get {
+ return ResourceManager.GetString("textChangeContactInfo", resourceCulture);
+ }
+ }
+
///
/// Looks up a localized string similar to Change password.
///
@@ -406,6 +445,15 @@ namespace BreCalClient.Resources {
}
}
+ ///
+ /// Looks up a localized string similar to E-mail.
+ ///
+ public static string textEmail {
+ get {
+ return ResourceManager.GetString("textEmail", resourceCulture);
+ }
+ }
+
///
/// Looks up a localized string similar to Enter keyword.
///
@@ -460,6 +508,15 @@ namespace BreCalClient.Resources {
}
}
+ ///
+ /// Looks up a localized string similar to Incoming.
+ ///
+ public static string textIncoming {
+ get {
+ return ResourceManager.GetString("textIncoming", resourceCulture);
+ }
+ }
+
///
/// Looks up a localized string similar to Interval.
///
@@ -469,6 +526,15 @@ namespace BreCalClient.Resources {
}
}
+ ///
+ /// Looks up a localized string similar to Length.
+ ///
+ public static string textLength {
+ get {
+ return ResourceManager.GetString("textLength", resourceCulture);
+ }
+ }
+
///
/// Looks up a localized string similar to L/W.
///
@@ -577,6 +643,15 @@ namespace BreCalClient.Resources {
}
}
+ ///
+ /// Looks up a localized string similar to Outgoing.
+ ///
+ public static string textOutgoing {
+ get {
+ return ResourceManager.GetString("textOutgoing", resourceCulture);
+ }
+ }
+
///
/// Looks up a localized string similar to Participants.
///
@@ -604,6 +679,15 @@ namespace BreCalClient.Resources {
}
}
+ ///
+ /// Looks up a localized string similar to Phone.
+ ///
+ public static string textPhone {
+ get {
+ return ResourceManager.GetString("textPhone", resourceCulture);
+ }
+ }
+
///
/// Looks up a localized string similar to Pier side.
///
@@ -703,6 +787,33 @@ namespace BreCalClient.Resources {
}
}
+ ///
+ /// Looks up a localized string similar to Shifting.
+ ///
+ public static string textShifting {
+ get {
+ return ResourceManager.GetString("textShifting", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Shifting from.
+ ///
+ public static string textShiftingFrom {
+ get {
+ return ResourceManager.GetString("textShiftingFrom", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Shifting to.
+ ///
+ public static string textShiftingTo {
+ get {
+ return ResourceManager.GetString("textShiftingTo", resourceCulture);
+ }
+ }
+
///
/// Looks up a localized string similar to Ship.
///
@@ -820,6 +931,15 @@ namespace BreCalClient.Resources {
}
}
+ ///
+ /// Looks up a localized string similar to Width.
+ ///
+ public static string textWidth {
+ get {
+ return ResourceManager.GetString("textWidth", resourceCulture);
+ }
+ }
+
///
/// Looks up a localized string similar to Zone entry.
///
diff --git a/src/BreCalClient/Resources/Resources.de.resx b/src/BreCalClient/Resources/Resources.de.resx
index 2cecb22..5dbb002 100644
--- a/src/BreCalClient/Resources/Resources.de.resx
+++ b/src/BreCalClient/Resources/Resources.de.resx
@@ -236,7 +236,7 @@
Operation Start
- Festmacher in Schleuse
+ auch in Schleuse
Festmacher
@@ -385,4 +385,34 @@
Info
+
+ Einkommend
+
+
+ Ausgehend
+
+
+ Verholung
+
+
+ Länge
+
+
+ Verholung von
+
+
+ Verholung nach
+
+
+ Breite
+
+
+ Kontaktdaten bearbeiten
+
+
+ E-Mail
+
+
+ Telefon
+
\ No newline at end of file
diff --git a/src/BreCalClient/Resources/Resources.resx b/src/BreCalClient/Resources/Resources.resx
index 5477bcf..add0c1f 100644
--- a/src/BreCalClient/Resources/Resources.resx
+++ b/src/BreCalClient/Resources/Resources.resx
@@ -133,6 +133,9 @@
arrow_up_red.png;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+ check.png;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
clipboard.png;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
@@ -148,6 +151,9 @@
delete.png;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+ delete2.png;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
emergency_stop_button.png;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
@@ -157,6 +163,9 @@
ship2.png;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+ sign_warning.png;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
Agencies
@@ -199,6 +208,9 @@
Change
+
+ Update contact info
+
Change password
@@ -229,6 +241,9 @@
Edit times
+
+ E-mail
+
Enter keyword
@@ -247,9 +262,15 @@
from
+
+ Incoming
+
Interval
+
+ Length
+
L/W
@@ -286,6 +307,9 @@
Operations start
+
+ Outgoing
+
Participants
@@ -295,6 +319,9 @@
Password changed.
+
+ Phone
+
Pier side
@@ -328,6 +355,15 @@
Search
+
+ Shifting
+
+
+ Shifting from
+
+
+ Shifting to
+
Ship
@@ -367,6 +403,9 @@
Voyage
+
+ Width
+
Zone entry
diff --git a/src/BreCalClient/Resources/check.png b/src/BreCalClient/Resources/check.png
new file mode 100644
index 0000000..5d739b1
Binary files /dev/null and b/src/BreCalClient/Resources/check.png differ
diff --git a/src/BreCalClient/Resources/delete2.png b/src/BreCalClient/Resources/delete2.png
new file mode 100644
index 0000000..d31437a
Binary files /dev/null and b/src/BreCalClient/Resources/delete2.png differ
diff --git a/src/BreCalClient/Resources/sign_warning.png b/src/BreCalClient/Resources/sign_warning.png
new file mode 100644
index 0000000..317ccc8
Binary files /dev/null and b/src/BreCalClient/Resources/sign_warning.png differ
diff --git a/src/BreCalClient/ShipcallControl.xaml b/src/BreCalClient/ShipcallControl.xaml
index 0f21e42..63a7bcb 100644
--- a/src/BreCalClient/ShipcallControl.xaml
+++ b/src/BreCalClient/ShipcallControl.xaml
@@ -2,18 +2,16 @@
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:local="clr-namespace:BreCalClient"
+ xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:p = "clr-namespace:BreCalClient.Resources"
xmlns:sets="clr-namespace:BreCalClient.Properties"
- xmlns:db="clr-namespace:BreCalClient;assembly=BreCalClient"
- xmlns:db2="clr-namespace:BreCalClient.misc.Model;assembly=BreCalClient"
+ xmlns:db="clr-namespace:BreCalClient;assembly=BreCalClient"
mc:Ignorable="d"
d:DesignHeight="120" d:DesignWidth="800" Loaded="UserControl_Loaded">
-
+
@@ -35,20 +33,23 @@
-
-
+
+
+
+
+
@@ -72,20 +73,15 @@
-
+
-
+
-
-
-
-
-
-
-
+
+
@@ -101,160 +97,123 @@
HorizontalAlignment="Stretch" HorizontalContentAlignment="Center" VerticalContentAlignment="Center" Name="labelTug" PreviewMouseUp="labelTug_PreviewMouseUp"/>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/BreCalClient/ShipcallControl.xaml.cs b/src/BreCalClient/ShipcallControl.xaml.cs
index ca2e298..1fcd904 100644
--- a/src/BreCalClient/ShipcallControl.xaml.cs
+++ b/src/BreCalClient/ShipcallControl.xaml.cs
@@ -3,15 +3,13 @@
//
using BreCalClient.misc.Model;
+using log4net;
using System;
-using System.Collections.Generic;
-using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Media.Imaging;
-
namespace BreCalClient
{
///
@@ -19,6 +17,17 @@ namespace BreCalClient
///
public partial class ShipcallControl : UserControl
{
+ #region Fields
+
+ Participant? _agency;
+ Participant? _pilot;
+ Participant? _mooring;
+ Participant? _terminal;
+ Participant? _tug;
+ Participant? _port_administration;
+ private static readonly ILog _log = LogManager.GetLogger(typeof(ShipcallControl));
+
+ #endregion
#region Construction
@@ -33,6 +42,8 @@ namespace BreCalClient
public event Action? EditRequested;
+ public event Action? EditAgencyRequested;
+
internal event Action? EditTimesRequested;
#endregion
@@ -42,165 +53,266 @@ namespace BreCalClient
///
/// this is our datasource
///
- public ShipcallControlModel? ShipcallControlModel { get; set; }
-
- ///
- /// these are all participants (currently loaded)
- ///
- public Dictionary? ParticipantDict { get; set; }
-
- ///
- /// For berth name lookup
- ///
- public List? Berths {get; set;}
+ public ShipcallControlModel? ShipcallControlModel { get; set; }
#endregion
#region public methods
public void RefreshData()
- {
- if (this.ShipcallControlModel == null) return;
- string agentName = "";
- string? name;
- name = this.ShipcallControlModel.GetParticipantNameForType(Extensions.ParticipantType.AGENCY);
- if (name != null) agentName = name;
- this.labelAgent.Content = name ?? "- / -";
-
- name = this.ShipcallControlModel.GetParticipantNameForType(Extensions.ParticipantType.MOORING);
- this.labelMooring.Content = name ?? "- / -";
-
- name = this.ShipcallControlModel.GetParticipantNameForType(Extensions.ParticipantType.PILOT);
- this.labelPilot.Content = name ?? "- / - ";
-
- name = this.ShipcallControlModel.GetParticipantNameForType(Extensions.ParticipantType.TUG);
- this.labelTug.Content = name ?? "- / - ";
-
- name = this.ShipcallControlModel.GetParticipantNameForType(Extensions.ParticipantType.PORT_ADMINISTRATION);
- this.labelPortAuthority.Content = name ?? "- / - ";
-
- name = this.ShipcallControlModel.GetParticipantNameForType(Extensions.ParticipantType.TERMINAL);
- this.labelTerminal.Content = name ?? "- / - ";
-
- if(App.Participant.IsTypeFlagSet(Extensions.ParticipantType.TERMINAL) && (App.Participant.Id == this.ShipcallControlModel.GetParticipantIdForType(Extensions.ParticipantType.TERMINAL)))
- {
- this.labelTerminal.FontWeight = FontWeights.Bold;
- this.labelTerminal.Foreground = Brushes.LightYellow;
- }
- if(App.Participant.IsTypeFlagSet(Extensions.ParticipantType.PILOT) && (App.Participant.Id == this.ShipcallControlModel.GetParticipantIdForType(Extensions.ParticipantType.PILOT)))
- {
- this.labelPilot.FontWeight = FontWeights.Bold;
- this.labelPilot.Foreground = Brushes.LightYellow;
- }
- if(App.Participant.IsTypeFlagSet(Extensions.ParticipantType.AGENCY) && (App.Participant.Id == this.ShipcallControlModel.GetParticipantIdForType(Extensions.ParticipantType.AGENCY)))
- {
- this.labelAgent.FontWeight = FontWeights.Bold;
- this.labelAgent.Foreground = Brushes.LightYellow;
- }
- if(App.Participant.IsTypeFlagSet(Extensions.ParticipantType.MOORING) && (App.Participant.Id == this.ShipcallControlModel.GetParticipantIdForType(Extensions.ParticipantType.MOORING)))
- {
- this.labelMooring.FontWeight = FontWeights.Bold;
- this.labelMooring.Foreground = Brushes.LightYellow;
- }
- if(App.Participant.IsTypeFlagSet(Extensions.ParticipantType.PORT_ADMINISTRATION) && (App.Participant.Id == this.ShipcallControlModel.GetParticipantIdForType(Extensions.ParticipantType.PORT_ADMINISTRATION)))
- {
- this.labelPortAuthority.FontWeight = FontWeights.Bold;
- this.labelPortAuthority.Foreground = Brushes.LightYellow;
- }
- if (App.Participant.IsTypeFlagSet(Extensions.ParticipantType.TUG) && (App.Participant.Id == this.ShipcallControlModel.GetParticipantIdForType(Extensions.ParticipantType.TUG)))
- {
- this.labelTug.FontWeight = FontWeights.Bold;
- this.labelTug.Foreground = Brushes.LightYellow;
- }
- if (App.Participant.IsTypeFlagSet(Extensions.ParticipantType.BSMD) ||
- (App.Participant.IsTypeFlagSet(Extensions.ParticipantType.AGENCY) && (App.Participant.Id == this.ShipcallControlModel.GetParticipantIdForType(Extensions.ParticipantType.AGENCY))))
- {
- this.labelShipName.FontWeight = FontWeights.Bold;
- this.labelShipName.Foreground = Brushes.LightYellow;
- }
-
- this.labelShipName.Content = this.ShipcallControlModel?.Ship?.Name;
- switch(this.ShipcallControlModel?.Shipcall?.Type)
- {
- case 1: // incoming
- this.imageShipcallType.Source = new BitmapImage(new Uri("pack://application:,,,/BreCalTestClient;component/Resources/arrow_down_red.png"));
- break;
- case 2: // outgoing
- this.imageShipcallType.Source = new BitmapImage(new Uri("pack://application:,,,/BreCalTestClient;component/Resources/arrow_up_blue.png"));
- break;
- case 3: // shifting
- this.imageShipcallType.Source = new BitmapImage(new Uri("pack://application:,,,/BreCalTestClient;component/Resources/arrow_right_green.png"));
- break;
- default:
- break;
- }
-
- this.textBlockBerth.Text = this.ShipcallControlModel?.Berth;
- this.textBlockCallsign.Text = this.ShipcallControlModel?.Ship?.Callsign;
- if ((this.ShipcallControlModel?.Shipcall?.Type == 1) || (this.ShipcallControlModel?.Shipcall?.Type == 3))
- {
- this.textBlockETA.Text = this.ShipcallControlModel?.Shipcall?.Eta.ToString("dd.MM. HH:mm");
- }
- if(this.ShipcallControlModel?.Shipcall?.Type == 2)
- {
- this.labelETA.Text = "ETD";
- this.textBlockETA.Text = this.ShipcallControlModel?.Shipcall?.Etd?.ToString("dd.MM. HH:mm");
- }
-
- this.textBlockIMO.Text = this.ShipcallControlModel?.Ship?.Imo.ToString();
- this.textBlockLengthWidth.Text = $"{this.ShipcallControlModel?.Ship?.Length} / {this.ShipcallControlModel?.Ship?.Width}";
- this.textBlockAgency.Text = agentName.TruncateDots(10);
-
- if (this.ParticipantDict != null)
+ {
+ try
{
if (this.ShipcallControlModel != null)
{
- foreach (Times times in this.ShipcallControlModel.Times)
- {
- if (times.ParticipantType == (int)Extensions.ParticipantType.AGENCY)
- {
- this.labelAgencyETA.Content = times.EtaBerth.HasValue ? times.EtaBerth.Value.ToString("dd.MM.yyyy HH:mm") : "- / -";
- this.labelAgencyETD.Content = times.EtdBerth.HasValue ? times.EtdBerth.Value.ToString("dd.MM.yyyy HH:mm") : "- / -";
- this.textBlockAgencyRemarks.Text = times.Remarks;
- }
- if (times.ParticipantType == (int) Extensions.ParticipantType.MOORING)
- {
- this.labelMooringETA.Content = times.EtaBerth.HasValue ? times.EtaBerth.Value.ToString("dd.MM.yyyy HH:mm") : "- / -";
- this.labelMooringETD.Content = times.EtdBerth.HasValue ? times.EtdBerth.Value.ToString("dd.MM.yyyy HH:mm") : "- / -";
- this.textBlockMooringRemarks.Text = times.Remarks;
- }
- if (times.ParticipantType == (int)Extensions.ParticipantType.PORT_ADMINISTRATION)
- {
- this.labelPortAuthorityETA.Content = times.EtaBerth.HasValue ? times.EtaBerth.Value.ToString("dd.MM.yyyy HH:mm") : "- / -";
- this.labelPortAuthorityETD.Content = times.EtdBerth.HasValue ? times.EtdBerth.Value.ToString("dd.MM.yyyy HH:mm") : "- / -";
- this.textBlockPortAuthorityRemarks.Text = times.Remarks;
- }
- if (times.ParticipantType == (int)Extensions.ParticipantType.PILOT)
- {
- this.labelPilotETA.Content = times.EtaBerth.HasValue ? times.EtaBerth.Value.ToString("dd.MM.yyyy HH:mm") : "- / -";
- this.labelPilotETD.Content = times.EtdBerth.HasValue ? times.EtdBerth.Value.ToString("dd.MM.yyyy HH:mm") : "- / -";
- this.textBlockPilotRemarks.Text = times.Remarks;
- }
- if (times.ParticipantType == (int)Extensions.ParticipantType.TUG)
- {
- this.labelTugETA.Content = times.EtaBerth.HasValue ? times.EtaBerth.Value.ToString("dd.MM.yyyy HH:mm") : "- / -";
- this.labelTugETD.Content = times.EtdBerth.HasValue ? times.EtdBerth.Value.ToString("dd.MM.yyyy HH:mm") : "- / -";
- this.textBlockTugRemarks.Text = times.Remarks;
- }
- if (times.ParticipantType == (int)Extensions.ParticipantType.TERMINAL)
- {
- if (this.Berths != null)
- {
- Berth? berth = this.Berths.Find((x) => x.Id == times.BerthId);
- this.labelTerminalBerth.Content = (berth != null) ? berth.Name : "";
- }
- this.labelOperationsStart.Content = times.OperationsStart.HasValue ? times.OperationsStart.Value.ToString("dd.MM.yyyy HH:mm") : "- / -";
- this.labelOperationsEnd.Content = times.OperationsEnd.HasValue ? times.OperationsEnd.Value.ToString("dd.MM.yyyy HH:mm") : "- / -";
- this.textBlockTerminalRemarks.Text = times.Remarks;
- }
+ string agentName = "";
+ string? name;
+ _agency = this.ShipcallControlModel.GetParticipantForType(Extensions.ParticipantType.AGENCY);
+ name = _agency?.Name;
+ if (name != null) agentName = name;
+ this.labelAgent.Content = name ?? "- / -";
+
+ _mooring = this.ShipcallControlModel.GetParticipantForType(Extensions.ParticipantType.MOORING);
+ name = _mooring?.Name;
+ this.labelMooring.Content = name ?? "- / -";
+
+ _pilot = this.ShipcallControlModel.GetParticipantForType(Extensions.ParticipantType.PILOT);
+ name = _pilot?.Name;
+ this.labelPilot.Content = name ?? "- / - ";
+
+ _tug = this.ShipcallControlModel.GetParticipantForType(Extensions.ParticipantType.TUG);
+ name = _tug?.Name;
+ this.labelTug.Content = name ?? "- / - ";
+
+ _port_administration = this.ShipcallControlModel.GetParticipantForType(Extensions.ParticipantType.PORT_ADMINISTRATION);
+ name = _port_administration?.Name;
+ this.labelPortAuthority.Content = name ?? "- / - ";
+
+ _terminal = this.ShipcallControlModel.GetParticipantForType(Extensions.ParticipantType.TERMINAL);
+ name = _terminal?.Name;
+ this.labelTerminal.Content = name ?? "- / - ";
+
+ if (App.Participant.IsTypeFlagSet(Extensions.ParticipantType.TERMINAL) && (App.Participant.Id == _terminal?.Id))
+ {
+ this.labelTerminal.FontWeight = FontWeights.Bold;
+ this.labelTerminal.Foreground = Brushes.LightYellow;
}
+
+ if (App.Participant.IsTypeFlagSet(Extensions.ParticipantType.PILOT) && (App.Participant.Id == _pilot?.Id))
+ {
+ this.labelPilot.FontWeight = FontWeights.Bold;
+ this.labelPilot.Foreground = Brushes.LightYellow;
+ }
+
+ if ((App.Participant.IsTypeFlagSet(Extensions.ParticipantType.AGENCY) && (App.Participant.Id == _agency?.Id)) ||
+ (App.Participant.IsTypeFlagSet(Extensions.ParticipantType.BSMD) && (_agency != null) && _agency.IsFlagSet(Extensions.ParticipantFlag.ALLOW_BSMD)))
+ {
+ this.labelAgent.FontWeight = FontWeights.Bold;
+ this.labelAgent.Foreground = Brushes.LightYellow;
+ }
+
+ if (App.Participant.IsTypeFlagSet(Extensions.ParticipantType.MOORING) && (App.Participant.Id == _mooring?.Id))
+ {
+ this.labelMooring.FontWeight = FontWeights.Bold;
+ this.labelMooring.Foreground = Brushes.LightYellow;
+ }
+
+ if (App.Participant.IsTypeFlagSet(Extensions.ParticipantType.PORT_ADMINISTRATION) && (App.Participant.Id == _port_administration?.Id))
+ {
+ this.labelPortAuthority.FontWeight = FontWeights.Bold;
+ this.labelPortAuthority.Foreground = Brushes.LightYellow;
+ }
+
+ if (App.Participant.IsTypeFlagSet(Extensions.ParticipantType.TUG) && (App.Participant.Id == _tug?.Id))
+ {
+ this.labelTug.FontWeight = FontWeights.Bold;
+ this.labelTug.Foreground = Brushes.LightYellow;
+ }
+
+ if (App.Participant.IsTypeFlagSet(Extensions.ParticipantType.BSMD))
+ {
+ this.labelShipName.FontWeight = FontWeights.Bold;
+ this.labelShipName.Foreground = Brushes.LightYellow;
+ }
+
+ this.labelShipName.Content = this.ShipcallControlModel?.Ship?.Name;
+ switch (this.ShipcallControlModel?.Shipcall?.Type)
+ {
+ case 1: // incoming
+ this.imageShipcallType.Source = new BitmapImage(new Uri("pack://application:,,,/BreCalClient;component/Resources/arrow_down_red.png"));
+ break;
+ case 2: // outgoing
+ this.imageShipcallType.Source = new BitmapImage(new Uri("pack://application:,,,/BreCalClient;component/Resources/arrow_up_blue.png"));
+ break;
+ case 3: // shifting
+ this.imageShipcallType.Source = new BitmapImage(new Uri("pack://application:,,,/BreCalClient;component/Resources/arrow_right_green.png"));
+ break;
+ default:
+ break;
+ }
+
+ switch(this.ShipcallControlModel?.LightMode)
+ {
+ case ShipcallControlModel.TrafficLightMode.GREEN:
+ this.imageEvaluation.Source = new BitmapImage(new Uri("pack://application:,,,/BreCalClient;component/Resources/check.png"));
+ break;
+ case ShipcallControlModel.TrafficLightMode.YELLOW:
+ this.imageEvaluation.Source = new BitmapImage(new Uri("pack://application:,,,/BreCalClient;component/Resources/sign_warning.png"));
+ break;
+ case ShipcallControlModel.TrafficLightMode.RED:
+ this.imageEvaluation.Source = new BitmapImage(new Uri("pack://application:,,,/BreCalClient;component/Resources/delete2.png"));
+ break;
+ default:
+ break;
+ }
+
+ if (this.ShipcallControlModel?.Shipcall?.Evaluation != null)
+ {
+ ShipcallControlModel.TrafficLightMode resultColor = (ShipcallControlModel.TrafficLightMode) (this.ShipcallControlModel?.Shipcall?.Evaluation ?? 0); // der nullable Operator hier ist so doof, die VS validation blickts einfach nicht
+ switch (resultColor)
+ {
+ case ShipcallControlModel.TrafficLightMode.GREEN:
+ this.Background = Brushes.LightGreen;
+ break;
+ case ShipcallControlModel.TrafficLightMode.YELLOW:
+ this.Background= Brushes.LightYellow;
+ break;
+ case ShipcallControlModel.TrafficLightMode.RED:
+ this.Background = new SolidColorBrush(Color.FromArgb(200, 255, 100, 100));
+ break;
+ default:
+ this.Background = Brushes.Transparent;
+ break;
+ }
+ }
+
+ if (!string.IsNullOrEmpty(this.ShipcallControlModel?.Shipcall?.EvaluationMessage))
+ this.imageEvaluation.ToolTip = this.ShipcallControlModel?.Shipcall?.EvaluationMessage;
+
+ this.textBlockBerth.Text = this.ShipcallControlModel?.Berth;
+ this.textBlockCallsign.Text = this.ShipcallControlModel?.Ship?.Callsign;
+ if (this.ShipcallControlModel?.Shipcall?.Type == 1)
+ {
+ this.textBlockETA.Text = this.ShipcallControlModel?.Shipcall?.Eta?.ToString("dd.MM. HH:mm");
+ }
+ if ((this.ShipcallControlModel?.Shipcall?.Type == 2) || (this.ShipcallControlModel?.Shipcall?.Type == 3))
+ {
+ this.labelETA.Text = "ETD";
+ this.textBlockETA.Text = this.ShipcallControlModel?.Shipcall?.Etd?.ToString("dd.MM. HH:mm");
+ }
+
+ this.textBlockIMO.Text = this.ShipcallControlModel?.Ship?.Imo.ToString();
+ this.textBlockLengthWidth.Text = $"{this.ShipcallControlModel?.Ship?.Length} / {this.ShipcallControlModel?.Ship?.Width}";
+
+ // rename labels if this is not an incoming
+ // must be here because there may not be a times record for each participant (yet)
+
+ if (this.ShipcallControlModel?.Shipcall?.Type != 1)
+ {
+ this.labelETAETDAgent.Content = "ETD";
+ this.labelETAETDMooring.Content = "ETD";
+ this.labelETAETDPilot.Content = "ETD";
+ this.labelETAETDPortAuthority.Content = "ETD";
+ this.labelETAETDTug.Content = "ETD";
+ this.labelETAETDTerminal.Content = BreCalClient.Resources.Resources.textOperationsEnd;
+ }
+
+ if (this.ShipcallControlModel != null)
+ {
+ foreach (Times times in this.ShipcallControlModel.Times)
+ {
+ string? berthText = null;
+ if ((BreCalLists.Berths != null) && times.BerthId.HasValue)
+ {
+ Berth? berth = BreCalLists.Berths.Find((x) => x.Id == times.BerthId);
+ berthText = berth?.Name;
+ }
+ if (berthText == null)
+ {
+ if (this.ShipcallControlModel?.Shipcall?.Type == (int)Extensions.TypeEnum.Incoming)
+ {
+ Berth? berth = BreCalLists.Berths?.Find((x) => x.Id == this.ShipcallControlModel.Shipcall?.ArrivalBerthId);
+ berthText = berth?.Name;
+ }
+ else
+ {
+ Berth? berth = BreCalLists.Berths?.Find((x) => x.Id == this.ShipcallControlModel?.Shipcall?.DepartureBerthId);
+ berthText = berth?.Name;
+ }
+ }
+
+ if (times.ParticipantType == (int)Extensions.ParticipantType.AGENCY)
+ {
+ this.labelAgencyBerth.Content = berthText;
+ this.labelAgencyETAETDValue.Content = times.EtaBerth.HasValue ? times.EtaBerth.Value.ToString("dd.MM.yyyy HH:mm") : "- / -";
+ this.textBlockAgencyRemarks.Text = times.Remarks;
+ this.textBlockAgencyBerthRemarks.Text = times.BerthInfo;
+ if (this.ShipcallControlModel?.Shipcall?.Type != 1)
+ {
+ this.labelAgencyETAETDValue.Content = times.EtdBerth.HasValue ? times.EtdBerth.Value.ToString("dd.MM.yyyy HH:mm") : "- / -";
+ }
+ }
+
+ if (times.ParticipantType == (int)Extensions.ParticipantType.MOORING)
+ {
+ this.labelMooringETAETDValue.Content = times.EtaBerth.HasValue ? times.EtaBerth.Value.ToString("dd.MM.yyyy HH:mm") : "- / -";
+ this.textBlockMooringRemarks.Text = times.Remarks;
+ if (this.ShipcallControlModel?.Shipcall?.Type != 1)
+ {
+ this.labelMooringETAETDValue.Content = times.EtdBerth.HasValue ? times.EtdBerth.Value.ToString("dd.MM.yyyy HH:mm") : "- / -";
+ }
+ }
+
+ if (times.ParticipantType == (int)Extensions.ParticipantType.PORT_ADMINISTRATION)
+ {
+ this.labelPortAuthorityETAETDValue.Content = times.EtaBerth.HasValue ? times.EtaBerth.Value.ToString("dd.MM.yyyy HH:mm") : "- / -";
+ this.textBlockPortAuthorityRemarks.Text = times.Remarks;
+ if (this.ShipcallControlModel?.Shipcall?.Type != 1)
+ {
+ this.labelPortAuthorityETAETDValue.Content = times.EtdBerth.HasValue ? times.EtdBerth.Value.ToString("dd.MM.yyyy HH:mm") : "- / -";
+ }
+ }
+
+ if (times.ParticipantType == (int)Extensions.ParticipantType.PILOT)
+ {
+ this.labelPilotETAETDValue.Content = times.EtaBerth.HasValue ? times.EtaBerth.Value.ToString("dd.MM.yyyy HH:mm") : "- / -";
+ this.textBlockPilotRemarks.Text = times.Remarks;
+ if (this.ShipcallControlModel?.Shipcall?.Type != 1)
+ {
+ this.labelPilotETAETDValue.Content = times.EtdBerth.HasValue ? times.EtdBerth.Value.ToString("dd.MM.yyyy HH:mm") : "- / -";
+ }
+ }
+
+ if (times.ParticipantType == (int)Extensions.ParticipantType.TUG)
+ {
+ this.labelTugETAETDValue.Content = times.EtaBerth.HasValue ? times.EtaBerth.Value.ToString("dd.MM.yyyy HH:mm") : "- / -";
+ this.textBlockTugRemarks.Text = times.Remarks;
+ if (this.ShipcallControlModel?.Shipcall?.Type != 1)
+ {
+ this.labelTugETAETDValue.Content = times.EtdBerth.HasValue ? times.EtdBerth.Value.ToString("dd.MM.yyyy HH:mm") : "- / -";
+ }
+ }
+
+ if (times.ParticipantType == (int)Extensions.ParticipantType.TERMINAL)
+ {
+ this.labelTerminalBerth.Content = berthText;
+ this.labelOperationsStart.Content = times.OperationsStart.HasValue ? times.OperationsStart.Value.ToString("dd.MM.yyyy HH:mm") : "- / -";
+ this.textBlockTerminalRemarks.Text = times.Remarks;
+ if (this.ShipcallControlModel?.Shipcall?.Type != 1)
+ {
+ this.labelOperationsStart.Content = times.OperationsEnd.HasValue ? times.OperationsEnd.Value.ToString("dd.MM.yyyy HH:mm") : "- / -";
+ }
+ this.textBlockTerminalBerthRemarks.Text = times.BerthInfo;
+ }
+ }
+ }
+ this.DataContext = this.ShipcallControlModel;
}
}
+ catch (Exception ex)
+ {
+ _log.ErrorFormat("Something went wrong during data refresh: {0}", ex.ToString());
+ }
}
#endregion
@@ -209,14 +321,13 @@ namespace BreCalClient
private void UserControl_Loaded(object sender, RoutedEventArgs e)
{
-
+ // TBD
}
private void buttonEditShipcall_Click(object? sender, RoutedEventArgs? e)
{
- if(App.Participant.IsTypeFlagSet(Extensions.ParticipantType.BSMD) ||
- (App.Participant.IsTypeFlagSet(Extensions.ParticipantType.AGENCY) && (App.Participant.Id == this.ShipcallControlModel?.GetParticipantIdForType(Extensions.ParticipantType.AGENCY))))
- this.EditRequested?.Invoke(this);
+ if(App.Participant.IsTypeFlagSet(Extensions.ParticipantType.BSMD))
+ this.EditRequested?.Invoke(this);
}
private void Image_PreviewMouseUp(object sender, System.Windows.Input.MouseButtonEventArgs e)
@@ -225,56 +336,39 @@ namespace BreCalClient
}
private void labelAgent_PreviewMouseUp(object sender, System.Windows.Input.MouseButtonEventArgs e)
- {
- if (App.Participant.IsTypeFlagSet(Extensions.ParticipantType.AGENCY) && (App.Participant.Id == this.ShipcallControlModel?.GetParticipantIdForType(Extensions.ParticipantType.AGENCY)))
- {
- this.EditRequested?.Invoke(this);
- }
+ {
+ Times? times = this.ShipcallControlModel?.GetTimesForParticipantType(Extensions.ParticipantType.AGENCY);
+ this.EditAgencyRequested?.Invoke(this, times);
}
private void labelMooring_PreviewMouseUp(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
- if (App.Participant.IsTypeFlagSet(Extensions.ParticipantType.MOORING) && (App.Participant.Id == this.ShipcallControlModel?.GetParticipantIdForType(Extensions.ParticipantType.MOORING)))
- {
- Times? times = this.ShipcallControlModel?.GetTimesForParticipantType(Extensions.ParticipantType.MOORING);
- this.EditTimesRequested?.Invoke(this, times, Extensions.ParticipantType.MOORING);
- }
+ Times? times = this.ShipcallControlModel?.GetTimesForParticipantType(Extensions.ParticipantType.MOORING);
+ this.EditTimesRequested?.Invoke(this, times, Extensions.ParticipantType.MOORING);
}
private void labelPortAuthority_PreviewMouseUp(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
- if (App.Participant.IsTypeFlagSet(Extensions.ParticipantType.PORT_ADMINISTRATION) && (App.Participant.Id == this.ShipcallControlModel?.GetParticipantIdForType(Extensions.ParticipantType.PORT_ADMINISTRATION)))
- {
- Times? times = this.ShipcallControlModel?.GetTimesForParticipantType(Extensions.ParticipantType.PORT_ADMINISTRATION);
- this.EditTimesRequested?.Invoke(this, times, Extensions.ParticipantType.PORT_ADMINISTRATION);
- }
+ Times? times = this.ShipcallControlModel?.GetTimesForParticipantType(Extensions.ParticipantType.PORT_ADMINISTRATION);
+ this.EditTimesRequested?.Invoke(this, times, Extensions.ParticipantType.PORT_ADMINISTRATION);
}
private void labelPilot_PreviewMouseUp(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
- if (App.Participant.IsTypeFlagSet(Extensions.ParticipantType.PILOT) && (App.Participant.Id == this.ShipcallControlModel?.GetParticipantIdForType(Extensions.ParticipantType.PILOT)))
- {
- Times? times = this.ShipcallControlModel?.GetTimesForParticipantType(Extensions.ParticipantType.PILOT);
- this.EditTimesRequested?.Invoke(this, times, Extensions.ParticipantType.PILOT);
- }
+ Times? times = this.ShipcallControlModel?.GetTimesForParticipantType(Extensions.ParticipantType.PILOT);
+ this.EditTimesRequested?.Invoke(this, times, Extensions.ParticipantType.PILOT);
}
private void labelTug_PreviewMouseUp(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
- if (App.Participant.IsTypeFlagSet(Extensions.ParticipantType.TUG) && (App.Participant.Id == this.ShipcallControlModel?.GetParticipantIdForType(Extensions.ParticipantType.TUG)))
- {
- Times? times = this.ShipcallControlModel?.GetTimesForParticipantType(Extensions.ParticipantType.TUG);
- this.EditTimesRequested?.Invoke(this, times, Extensions.ParticipantType.TUG);
- }
+ Times? times = this.ShipcallControlModel?.GetTimesForParticipantType(Extensions.ParticipantType.TUG);
+ this.EditTimesRequested?.Invoke(this, times, Extensions.ParticipantType.TUG);
}
private void labelTerminal_PreviewMouseUp(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
- if (App.Participant.IsTypeFlagSet(Extensions.ParticipantType.TERMINAL) && (App.Participant.Id == this.ShipcallControlModel?.GetParticipantIdForType(Extensions.ParticipantType.TERMINAL)))
- {
- Times? times = this.ShipcallControlModel?.GetTimesForParticipantType(Extensions.ParticipantType.TERMINAL);
- this.EditTimesRequested?.Invoke(this, times, Extensions.ParticipantType.TERMINAL);
- }
+ Times? times = this.ShipcallControlModel?.GetTimesForParticipantType(Extensions.ParticipantType.TERMINAL);
+ this.EditTimesRequested?.Invoke(this, times, Extensions.ParticipantType.TERMINAL);
}
#endregion
diff --git a/src/BreCalClient/ShipcallControlModel.cs b/src/BreCalClient/ShipcallControlModel.cs
index 0d39601..a5e8e73 100644
--- a/src/BreCalClient/ShipcallControlModel.cs
+++ b/src/BreCalClient/ShipcallControlModel.cs
@@ -2,6 +2,7 @@
// Description: Container model for shipcall related info
//
+using BreCalClient.misc.Api;
using BreCalClient.misc.Model;
using System;
using System.Collections.Generic;
@@ -47,7 +48,7 @@ namespace BreCalClient
public string? Berth { get; set; }
- internal Dictionary AssignedParticipants { get; } = new();
+ internal Dictionary AssignedParticipants { get; } = new();
public List Times { get; set; } = new();
@@ -55,46 +56,31 @@ namespace BreCalClient
{
get
{
- if (IsFlagSet(StatusFlags.RED))
+ TrafficLightMode tlm = TrafficLightMode.OFF;
+
+ if (this.Shipcall != null)
{
- if (IsFlagSet((StatusFlags)StatusFlags.YELLOW))
+ if(this.Shipcall.Evaluation.HasValue)
{
- if (IsFlagSet(StatusFlags.GREEN))
- {
- return TrafficLightMode.ALL;
- }
- return TrafficLightMode.RED_YELLOW;
+ tlm = (TrafficLightMode)this.Shipcall.Evaluation;
}
- return TrafficLightMode.RED;
}
- if (IsFlagSet(StatusFlags.YELLOW))
- return TrafficLightMode.YELLOW;
- if (IsFlagSet(StatusFlags.GREEN))
- return TrafficLightMode.GREEN;
- return TrafficLightMode.OFF;
- }
+ return tlm;
+ }
}
#endregion
#region public methods
- public void AssignParticipants(List participants)
+ public void AssignParticipants()
{
this.AssignedParticipants.Clear();
if (Shipcall != null)
{
- foreach (int participantId in Shipcall.Participants)
+ foreach (ParticipantAssignment participantAssignment in Shipcall.Participants)
{
- Participant? participant = participants.Find((x) => x.Id == participantId);
- if (participant != null)
- {
- foreach(Extensions.ParticipantType participantType in Enum.GetValues(typeof(Extensions.ParticipantType)))
- {
- if(participant.IsTypeFlagSet(participantType))
- AssignedParticipants[participantType] = participant;
- }
- }
+ AssignedParticipants[(Extensions.ParticipantType)participantAssignment.Type] = participantAssignment;
}
}
}
@@ -103,12 +89,24 @@ namespace BreCalClient
{
if (AssignedParticipants.ContainsKey(type)) {
- int participantId = AssignedParticipants[type].Id;
+ int participantId = AssignedParticipants[type].ParticipantId;
foreach (Times times in this.Times)
{
if ((times.ParticipantId == participantId) && (times.ParticipantType == (int) type))
return times;
}
+ if(type == Extensions.ParticipantType.AGENCY)
+ {
+ // if I am BSMD and no agency entry was found this means we are editing the agency entry
+ if(App.Participant.Type == (int) Extensions.ParticipantType.BSMD)
+ {
+ foreach(Times times in this.Times)
+ {
+ if ((times.ParticipantId == App.Participant.Id) && (times.ParticipantType == (int) Extensions.ParticipantType.AGENCY))
+ return times;
+ }
+ }
+ }
}
return null;
}
@@ -127,29 +125,36 @@ namespace BreCalClient
return false;
}
+ ///
+ /// After closing the edit shipcall or edit agency dialogs, the times assignments may have changed.
+ /// This function updates the assignments for existing times records accordingly and saves them.
+ ///
+ /// API reference to PUT eidted times
+ internal async void UpdateTimesAssignments(DefaultApi _api)
+ {
+ foreach (Extensions.ParticipantType participantType in this.AssignedParticipants.Keys)
+ {
+ Times? times = this.GetTimesForParticipantType(participantType);
+ if(times == null) continue;
+ if(times.ParticipantId != this.AssignedParticipants[participantType].ParticipantId)
+ {
+ times.ParticipantId = this.AssignedParticipants[participantType].ParticipantId;
+ await _api.TimesPutAsync(times);
+ }
+ }
+ }
+
#endregion
#region helper
- internal string? GetParticipantNameForType(Extensions.ParticipantType participantType)
+ internal Participant? GetParticipantForType(Extensions.ParticipantType participantType)
{
- foreach(Participant p in AssignedParticipants.Values)
- {
- if (p.IsTypeFlagSet(participantType))
- return p.Name;
- }
+ if(AssignedParticipants.ContainsKey(participantType) && BreCalLists.ParticipantLookupDict.ContainsKey(AssignedParticipants[participantType].ParticipantId))
+ return BreCalLists.ParticipantLookupDict[AssignedParticipants[participantType].ParticipantId];
+
return null;
- }
-
- internal int? GetParticipantIdForType(Extensions.ParticipantType participantType)
- {
- foreach(Participant p in AssignedParticipants.Values)
- {
- if(p.IsTypeFlagSet(participantType))
- return p.Id;
- }
- return null;
- }
+ }
private bool IsFlagSet(StatusFlags flag)
{
diff --git a/src/RoleEditor/App.config b/src/RoleEditor/App.config
index 7c6ee29..51c1ce1 100644
--- a/src/RoleEditor/App.config
+++ b/src/RoleEditor/App.config
@@ -8,7 +8,7 @@
- Server=localhost;User ID=ds;Password=HalloWach_2323XXL!!;Database=bremen_calling;Port=33306
+ Server=localhost;User ID=ds;Password=HalloWach_2323XXL!!;Database=bremen_calling_devel;Port=33306
diff --git a/src/RoleEditor/EditBerthDialog.xaml b/src/RoleEditor/EditBerthDialog.xaml
index 78ef683..234b02b 100644
--- a/src/RoleEditor/EditBerthDialog.xaml
+++ b/src/RoleEditor/EditBerthDialog.xaml
@@ -5,7 +5,7 @@
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:RoleEditor"
mc:Ignorable="d"
- Title="Edit berth" Height="160" Width="450" Loaded="Window_Loaded">
+ Title="Edit berth" Height="188" Width="450" Loaded="Window_Loaded">
@@ -15,25 +15,37 @@
+
-
+
-
+
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/RoleEditor/EditBerthDialog.xaml.cs b/src/RoleEditor/EditBerthDialog.xaml.cs
index 41cf0ad..9f1a0a3 100644
--- a/src/RoleEditor/EditBerthDialog.xaml.cs
+++ b/src/RoleEditor/EditBerthDialog.xaml.cs
@@ -16,7 +16,9 @@ namespace RoleEditor
public Berth Berth { get; set; } = new Berth();
- public List Participants { get; } = new List();
+ public List Owners { get; } = new List();
+
+ public List Authorities { get; } = new List();
private void buttonCancel_Click(object sender, RoutedEventArgs e)
{
@@ -28,11 +30,19 @@ namespace RoleEditor
{
this.Berth.Name = this.textBoxName.Text.Trim();
this.Berth.Lock = this.checkBoxLock.IsChecked;
- this.Berth.Participant = this.comboBoxParticipants.SelectedItem as Participant;
- if (this.Berth.Participant != null)
- this.Berth.Participant_Id = this.Berth.Participant.Id;
+
+ this.Berth.Owner = this.comboBoxParticipants.SelectedItem as Participant;
+ if (this.Berth.Owner != null)
+ this.Berth.Owner_Id = this.Berth.Owner.Id;
else
- this.Berth.Participant_Id = null;
+ this.Berth.Owner_Id = null;
+
+ this.Berth.Authority = this.comboBoxAuthorities.SelectedItem as Participant;
+ if (this.Berth.Authority != null)
+ this.Berth.Authority_Id = this.Berth.Authority.Id;
+ else
+ this.Berth.Authority_Id = null;
+
this.DialogResult = true;
this.Close();
}
@@ -40,12 +50,18 @@ namespace RoleEditor
private void Window_Loaded(object sender, RoutedEventArgs e)
{
this.DataContext = this.Berth;
- this.comboBoxParticipants.ItemsSource = this.Participants;
+ this.comboBoxParticipants.ItemsSource = this.Owners;
+ this.comboBoxAuthorities.ItemsSource = this.Authorities;
}
private void buttonResetParticipant_Click(object sender, RoutedEventArgs e)
{
this.comboBoxParticipants.SelectedItem = null;
}
+
+ private void buttonResetAuthority_Click(object sender, RoutedEventArgs e)
+ {
+ this.comboBoxAuthorities.SelectedItem = null;
+ }
}
}
diff --git a/src/RoleEditor/MainWindow.xaml b/src/RoleEditor/MainWindow.xaml
index 67e58e5..2883102 100644
--- a/src/RoleEditor/MainWindow.xaml
+++ b/src/RoleEditor/MainWindow.xaml
@@ -6,7 +6,7 @@
xmlns:local="clr-namespace:RoleEditor"
xmlns:xctk="http://schemas.xceed.com/wpf/xaml/toolkit"
mc:Ignorable="d"
- Title="Bremen calling admin editor" Height="650" Width="800" Icon="Resources/lock_preferences.ico" Loaded="Window_Loaded">
+ Title="Bremen calling admin editor" Height="670" Width="800" Icon="Resources/lock_preferences.ico" Loaded="Window_Loaded">
@@ -121,19 +121,23 @@
-
-
-
+
+
+
+
+
-
-
-
+
+
+
+
+
-
+
@@ -261,6 +265,7 @@
+
diff --git a/src/RoleEditor/MainWindow.xaml.cs b/src/RoleEditor/MainWindow.xaml.cs
index c3b4cef..9eeb98d 100644
--- a/src/RoleEditor/MainWindow.xaml.cs
+++ b/src/RoleEditor/MainWindow.xaml.cs
@@ -28,6 +28,9 @@ namespace RoleEditor
#region private fields
private readonly ObservableCollection _participants = new ObservableCollection();
+ private readonly ObservableCollection _terminals = new ObservableCollection();
+ private readonly ObservableCollection _authorities = new ObservableCollection();
+
private readonly ObservableCollection _roles = new ObservableCollection();
private readonly ObservableCollection _securables = new ObservableCollection();
private readonly ObservableCollection _users = new ObservableCollection();
@@ -56,8 +59,12 @@ namespace RoleEditor
// load all participants
List participants = await Participant.LoadAll(_dbManager);
- foreach(Participant p in participants)
+ foreach (Participant p in participants)
+ {
_participants.Add(p);
+ if(p.IsTypeFlagSet(Participant.ParticipantType.TERMINAL)) { _terminals.Add(p); }
+ if(p.IsTypeFlagSet(Participant.ParticipantType.PORT_ADMINISTRATION)) { _authorities.Add(p); }
+ }
this.listBoxParticipant.ItemsSource = _participants;
// load all roles
@@ -74,9 +81,13 @@ namespace RoleEditor
foreach (Berth b in await Berth.LoadAll(_dbManager))
{
_berths.Add(b);
- if(b.Participant_Id != null)
+ if (b.Owner_Id != null)
{
- b.Participant = participants.Where( p => p.Id== b.Participant_Id ).FirstOrDefault();
+ b.Owner = participants.Where(p => p.Id == b.Owner_Id).FirstOrDefault();
+ }
+ if (b.Authority_Id != null)
+ {
+ b.Authority = participants.Where(p => p.Id == b.Authority_Id).FirstOrDefault();
}
}
this.dataGridBerths.Initialize();
@@ -173,7 +184,8 @@ namespace RoleEditor
{
EditBerthDialog ebd = new();
ebd.Berth = b;
- ebd.Participants.AddRange(this._participants);
+ ebd.Owners.AddRange(this._terminals);
+ ebd.Authorities.AddRange(this._authorities);
if (ebd.ShowDialog() ?? false)
{
await b.Save(_dbManager);
@@ -188,7 +200,8 @@ namespace RoleEditor
Berth b = new();
EditBerthDialog ebd = new();
ebd.Berth = b;
- ebd.Participants.AddRange(this._participants);
+ ebd.Owners.AddRange(this._terminals);
+ ebd.Authorities.AddRange(this._authorities);
if (ebd.ShowDialog() ?? false)
{
_berths.Add(b);
@@ -240,6 +253,8 @@ namespace RoleEditor
u.Firstname = this.textBoxUserFirstName.Text.Trim();
u.Lastname = this.textBoxUserLastName.Text.Trim();
u.Username = this.textBoxUserUserName.Text.Trim();
+ u.EMail = this.textBoxUserEMail.Text.Trim();
+ u.Phone = this.textBoxUserPhone.Text.Trim();
if(this.textBoxUserPassword.Text.Trim().Length > 0 )
{
string passwortText = this.textBoxUserPassword.Text.Trim();
@@ -442,6 +457,8 @@ namespace RoleEditor
this.textBoxUserFirstName.Text = (u != null) ? u.Firstname : string.Empty;
this.textBoxUserLastName.Text = (u != null) ? u.Lastname : string.Empty;
this.textBoxUserUserName.Text = (u != null) ? u.Username : string.Empty;
+ this.textBoxUserEMail.Text = (u != null) ? u.EMail : string.Empty;
+ this.textBoxUserPhone.Text = (u != null) ? u.Phone : string.Empty;
this.textBoxUserAPIKey.Text = (u != null) ? u.APIKey : string.Empty;
this.textBoxUserCreated.Text = (u != null) ? u.Created.ToString() : string.Empty;
this.textBoxUserModified.Text = (u != null) ? u.Modified.ToString() : string.Empty;
@@ -634,7 +651,7 @@ namespace RoleEditor
{
if ((p.Name != null) && p.Name.Contains(participant_name, StringComparison.OrdinalIgnoreCase))
{
- b.Participant_Id = p.Id;
+ b.Owner_Id = p.Id;
found_participant = true;
break;
}
@@ -649,7 +666,7 @@ namespace RoleEditor
await p.Save(_dbManager);
_participants.Add(p);
pCounter++;
- b.Participant_Id = p.Id;
+ b.Owner_Id = p.Id;
}
await b.Save(_dbManager);
diff --git a/src/brecal.model/Berth.cs b/src/brecal.model/Berth.cs
index 11d675b..12fed2d 100644
--- a/src/brecal.model/Berth.cs
+++ b/src/brecal.model/Berth.cs
@@ -1,4 +1,7 @@
-using System;
+// Copyright (c) 2023- schick Informatik
+// Description: Model class for berth entity
+
+using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
@@ -16,11 +19,17 @@ namespace brecal.model
public bool? Lock { get; set; }
- public uint? Participant_Id { get; set; }
+ public uint? Owner_Id { get; set; }
- public Participant? Participant { get; set; }
+ public uint? Authority_Id { get; set; }
- public string? Terminal { get { if (Participant != null) return Participant.Name; else return "n/a"; } }
+ public Participant? Owner { get; set; }
+
+ public Participant? Authority { get; set; }
+
+ public string? Terminal { get { if (Owner != null) return Owner.Name; else return "n/a"; } }
+
+ public string? Authority_Text { get { if (Authority != null) return Authority.Name; else return "n/a"; } }
#endregion
@@ -37,7 +46,7 @@ namespace brecal.model
public static void SetLoadQuery(IDbCommand cmd, params object?[] list)
{
- cmd.CommandText = "SELECT id, name, participant_id, `lock`, created, modified FROM berth";
+ cmd.CommandText = "SELECT id, name, owner_id, authority_id, `lock`, created, modified FROM berth";
}
public static List LoadElems(IDataReader reader)
@@ -48,10 +57,11 @@ namespace brecal.model
Berth b = new();
b.Id = (uint)reader.GetInt32(0);
if (!reader.IsDBNull(1)) b.Name = reader.GetString(1);
- if (!reader.IsDBNull(2)) b.Participant_Id = (uint) reader.GetInt32(2);
- if (!reader.IsDBNull(3)) b.Lock = reader.GetBoolean(3);
- if (!reader.IsDBNull(4)) b.Created = reader.GetDateTime(4);
- if (!reader.IsDBNull(5)) b.Modified = reader.GetDateTime(5);
+ if (!reader.IsDBNull(2)) b.Owner_Id = (uint) reader.GetInt32(2);
+ if (!reader.IsDBNull(3)) b.Authority_Id = (uint) reader.GetInt32(3);
+ if (!reader.IsDBNull(4)) b.Lock = reader.GetBoolean(4);
+ if (!reader.IsDBNull(5)) b.Created = reader.GetDateTime(5);
+ if (!reader.IsDBNull(6)) b.Modified = reader.GetDateTime(6);
result.Add(b);
}
return result;
@@ -63,7 +73,7 @@ namespace brecal.model
public override void SetCreate(IDbCommand cmd)
{
- cmd.CommandText = "INSERT INTO berth (participant_id, name, `lock`) VALUES ( @PID, @NAME, @LOCK)";
+ cmd.CommandText = "INSERT INTO berth (owner_id, authority_id, name, `lock`) VALUES ( @PID, @AID, @NAME, @LOCK)";
this.SetParameters(cmd);
}
@@ -79,7 +89,7 @@ namespace brecal.model
public override void SetUpdate(IDbCommand cmd)
{
- cmd.CommandText = "UPDATE berth SET name = @NAME, participant_id = @PID, `lock` = @LOCK WHERE id = @ID";
+ cmd.CommandText = "UPDATE berth SET name = @NAME, owner_id = @PID, authority_id = @AID, `lock` = @LOCK WHERE id = @ID";
this.SetParameters(cmd);
}
@@ -96,9 +106,14 @@ namespace brecal.model
IDbDataParameter pid = cmd.CreateParameter();
pid.ParameterName = "PID";
- pid.Value = this.Participant_Id;
+ pid.Value = this.Owner_Id;
cmd.Parameters.Add(pid);
+ IDbDataParameter aid = cmd.CreateParameter();
+ aid.ParameterName = "AID";
+ aid.Value = this.Authority_Id;
+ cmd.Parameters.Add(aid);
+
IDbDataParameter name = cmd.CreateParameter();
name.ParameterName = "NAME";
name.Value = this.Name;
diff --git a/src/brecal.model/User.cs b/src/brecal.model/User.cs
index 2c4cf65..37111d5 100644
--- a/src/brecal.model/User.cs
+++ b/src/brecal.model/User.cs
@@ -12,6 +12,10 @@ namespace brecal.model
public string Username { get; set; } = "";
+ public string EMail { get; set; } = "";
+
+ public string Phone { get; set; } = "";
+
public string? PasswordHash { get; set; }
public string? APIKey { get; set; }
@@ -33,7 +37,7 @@ namespace brecal.model
public static void SetLoadQuery(IDbCommand cmd, params object?[] args)
{
- cmd.CommandText = "SELECT id, first_name, last_name, user_name, api_key, created, modified FROM user WHERE participant_id = @PID";
+ cmd.CommandText = "SELECT id, first_name, last_name, user_name, user_email, user_phone, api_key, created, modified FROM user WHERE participant_id = @PID";
if (args.Length != 1 || !(args[0] is Participant))
throw new ArgumentException("loader needs single partipant as argument");
IDataParameter pid = cmd.CreateParameter();
@@ -53,9 +57,11 @@ namespace brecal.model
if (!reader.IsDBNull(1)) u.Firstname = reader.GetString(1);
if (!reader.IsDBNull(2)) u.Lastname = reader.GetString(2);
if (!reader.IsDBNull(3)) u.Username = reader.GetString(3);
- if (!reader.IsDBNull(4)) u.APIKey = reader.GetString(4);
- if (!reader.IsDBNull(5)) u.Created = reader.GetDateTime(5);
- if (!reader.IsDBNull(6)) u.Modified = reader.GetDateTime(6);
+ if (!reader.IsDBNull(4)) u.EMail = reader.GetString(4);
+ if (!reader.IsDBNull(5)) u.Phone = reader.GetString(5);
+ if (!reader.IsDBNull(6)) u.APIKey = reader.GetString(6);
+ if (!reader.IsDBNull(7)) u.Created = reader.GetDateTime(7);
+ if (!reader.IsDBNull(8)) u.Modified = reader.GetDateTime(8);
result.Add(u);
}
return result;
@@ -68,15 +74,15 @@ namespace brecal.model
public override void SetUpdate(IDbCommand cmd)
{
if(!string.IsNullOrEmpty(this.PasswordHash))
- cmd.CommandText = "UPDATE user SET first_name = @FIRSTNAME, last_name = @LASTNAME, user_name = @USERNAME, password_hash = @PWHASH, api_key = @APIKEY WHERE id = @ID";
+ cmd.CommandText = "UPDATE user SET first_name = @FIRSTNAME, last_name = @LASTNAME, user_name = @USERNAME, password_hash = @PWHASH, api_key = @APIKEY, user_email = @USEREMAIL, user_phone = @USERPHONE WHERE id = @ID";
else
- cmd.CommandText = "UPDATE user SET first_name = @FIRSTNAME, last_name = @LASTNAME, user_name = @USERNAME, api_key = @APIKEY WHERE id = @ID";
+ cmd.CommandText = "UPDATE user SET first_name = @FIRSTNAME, last_name = @LASTNAME, user_name = @USERNAME, api_key = @APIKEY, user_email = @USEREMAIL, user_phone = @USERPHONE WHERE id = @ID";
this.SetParameters(cmd);
}
public override void SetCreate(IDbCommand cmd)
{
- cmd.CommandText = "INSERT INTO user (participant_id, first_name, last_name, user_name, password_hash, api_key) VALUES ( @PID, @FIRSTNAME, @LASTNAME, @USERNAME, @PWHASH, @APIKEY)";
+ cmd.CommandText = "INSERT INTO user (participant_id, first_name, last_name, user_name, password_hash, api_key, user_email, user_phone) VALUES ( @PID, @FIRSTNAME, @LASTNAME, @USERNAME, @PWHASH, @APIKEY, @USEREMAIL, @USERPHONE)";
this.SetParameters(cmd);
}
@@ -126,6 +132,16 @@ namespace brecal.model
username.Value = this.Username;
cmd.Parameters.Add(username);
+ IDbDataParameter email = cmd.CreateParameter();
+ email.ParameterName = "USEREMAIL";
+ email.Value = this.EMail;
+ cmd.Parameters.Add(email);
+
+ IDbDataParameter phone = cmd.CreateParameter();
+ phone.ParameterName = "USERPHONE";
+ phone.Value = this.Phone;
+ cmd.Parameters.Add(phone);
+
IDbDataParameter pwhash = cmd.CreateParameter();
pwhash.ParameterName = "PWHASH";
pwhash.Value = this.PasswordHash;
diff --git a/src/server/BreCal/__init__.py b/src/server/BreCal/__init__.py
index e15818a..3e1839d 100644
--- a/src/server/BreCal/__init__.py
+++ b/src/server/BreCal/__init__.py
@@ -13,8 +13,6 @@ from .api import ships
from .api import login
from .api import user
-sessions = dict()
-
def create_app(test_config=None):
app = Flask(__name__, instance_relative_config=True)
@@ -44,7 +42,27 @@ def create_app(test_config=None):
logging.basicConfig(filename='brecal.log', level=logging.DEBUG, format='%(asctime)s | %(name)s | %(levelname)s | %(message)s')
- local_db.initPool()
+ local_db.initPool(os.path.dirname(app.instance_path))
logging.info('App started')
return app
+
+from BreCal.brecal_utils.file_handling import get_project_root, ensure_path
+from BreCal.brecal_utils.test_handling import execute_test_with_pytest, execute_coverage_test
+from BreCal.brecal_utils.time_handling import difference_to_then
+
+from BreCal.validators.time_logic import TimeLogic
+from BreCal.validators.validation_rules import ValidationRules
+from BreCal.validators.schema_validation import validation_state_and_validation_name
+
+__all__ = [
+ "get_project_root",
+ "ensure_path",
+ "execute_test_with_pytest",
+ "execute_coverage_test",
+ "difference_to_then",
+ "TimeLogic",
+ "ValidationRules",
+ "validation_state_and_validation_name",
+]
+
diff --git a/src/server/BreCal/api/__init__.py b/src/server/BreCal/api/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/src/server/BreCal/api/shipcalls.py b/src/server/BreCal/api/shipcalls.py
index 51c79d6..8d97616 100644
--- a/src/server/BreCal/api/shipcalls.py
+++ b/src/server/BreCal/api/shipcalls.py
@@ -17,6 +17,7 @@ def GetShipcalls():
token = request.headers.get('Authorization')
options = {}
options["participant_id"] = request.args.get("participant_id")
+ options["past_days"] = request.args.get("past_days", default=2, type=int)
return impl.shipcalls.GetShipcalls(options)
else:
diff --git a/src/server/BreCal/brecal_utils/__init__.py b/src/server/BreCal/brecal_utils/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/src/server/BreCal/brecal_utils/file_handling.py b/src/server/BreCal/brecal_utils/file_handling.py
new file mode 100644
index 0000000..0b3c171
--- /dev/null
+++ b/src/server/BreCal/brecal_utils/file_handling.py
@@ -0,0 +1,46 @@
+
+
+import os
+
+def get_project_root(root_base_name:str, root_dir:None=None):
+ """
+ given a {root_base_name}, this function searches the parent folders of {root_dir} until
+ the basename matches.
+
+ Example:
+ root_base_name = "brecal"
+ root_dir = "/home/arbitrary_user/brecal/_template/tests"
+
+ returns: "/home/arbitrary_user/brecal"
+
+ arguments:
+ root_base_name:str, base directory name that should be searched for
+ root_dir: defaults to 'None', whereas then the current working directory is selected. Can be an arbitrary path.
+
+ returns: root_dir
+ """
+ if root_dir is None:
+ root_dir = os.getcwd()
+
+ assert root_base_name in root_dir, f"the desired base name MUST be present within the root directory.\nRoot Directory: {root_dir}\nDesired Root Base Name: {root_base_name}"
+ assert root_dir.count(root_base_name)==1, f"found multiple matches for root_base_name" # do not change, as a pytest requires precise wording
+
+
+ while not os.path.basename(root_dir)==root_base_name:
+ root_dir = os.path.dirname(root_dir)
+
+ return root_dir
+
+def ensure_path(path, print_info=0):
+ """
+ Function ensures that a certain directory exists. If it does not exist, it will be created.
+ It further checks if the parent-directory of the file exists and also ensures that.
+
+ options:
+ print_info: print additional information (debugging)
+ """
+ if not os.path.exists(path):
+ os.makedirs(path)
+ if print_info == 1:
+ print(f"Created directory and subdirectories: {path}")
+ return
diff --git a/src/server/BreCal/brecal_utils/request_status_code.py b/src/server/BreCal/brecal_utils/request_status_code.py
new file mode 100644
index 0000000..c3d72ea
--- /dev/null
+++ b/src/server/BreCal/brecal_utils/request_status_code.py
@@ -0,0 +1,131 @@
+import json
+from abc import ABC, abstractmethod
+from BreCal.schemas.model import obj_dict
+
+
+"""implementation of default objects for http request codes. this enforces standardized outputs in the (response, code, headers)-style"""
+
+def get_request_code(code_id):
+ """convenience function, which returns the desired request code object"""
+ request_code_dict = {
+ 200:RequestCode_HTTP_200_OK,
+ 201:RequestCode_HTTP_201_CREATED,
+ 400:RequestCode_HTTP_400_BAD_REQUEST,
+ 403:RequestCode_HTTP_403_FORBIDDEN,
+ 404:RequestCode_HTTP_404_NOT_FOUND,
+ 500:RequestCode_HTTP_500_INTERNAL_SERVER_ERROR
+ }
+
+ assert code_id in list(request_code_dict.keys()), f"unsupported request code: {code_id}. \nAvailable codes: {request_code_dict}"
+ return request_code_dict.get(code_id)()
+
+class RequestStatusCode(ABC):
+ def __init__(self):
+ return
+
+ @abstractmethod
+ def __call__(self, data):
+ raise NotImplementedError("any default status code object must be callable")
+
+ @abstractmethod
+ def status_code(self):
+ raise NotImplementedError("any default status code object should return an integer")
+
+ @abstractmethod
+ def response(self, data):
+ raise NotImplementedError("the response method should return a binary json object. typically, json.dumps is used")
+
+
+ def headers(self):
+ return {'Content-Type': 'application/json; charset=utf-8'}
+
+
+class RequestCode_HTTP_200_OK(RequestStatusCode):
+ def __init__(self) -> None:
+ super().__init__()
+
+ def __call__(self, data):
+ return (self.response(data), self.status_code(), self.headers())
+
+ def status_code(self):
+ return 200
+
+ def response(self, data):
+ return json.dumps(data, default=obj_dict)
+
+
+class RequestCode_HTTP_201_CREATED(RequestStatusCode):
+ def __init__(self) -> None:
+ super().__init__()
+
+ def __call__(self, data):
+ return (self.response(data), self.status_code(), self.headers())
+
+ def status_code(self):
+ return 201
+
+ def response(self, new_id):
+ return json.dumps({"id":new_id})
+
+
+class RequestCode_HTTP_400_BAD_REQUEST(RequestStatusCode):
+ def __init__(self) -> None:
+ super().__init__()
+
+ def __call__(self, data):
+ return (self.response(data), self.status_code(), self.headers())
+
+ def status_code(self):
+ return 400
+
+ def response(self, data):
+ return json.dumps(data)
+
+
+class RequestCode_HTTP_403_FORBIDDEN(RequestStatusCode):
+ def __init__(self) -> None:
+ super().__init__()
+
+ def __call__(self, data):
+ return (self.response(data), self.status_code(), self.headers())
+
+ def status_code(self):
+ return 403
+
+ def response(self, message="invalid credentials"):
+ result = {}
+ result["message"] = message
+ return json.dumps(result)
+
+
+class RequestCode_HTTP_404_NOT_FOUND(RequestStatusCode):
+ def __init__(self) -> None:
+ super().__init__()
+
+ def __call__(self, data):
+ return (self.response(data), self.status_code(), self.headers())
+
+ def status_code(self):
+ return 404
+
+ def response(self, message="no such record"):
+ result = {}
+ result["message"] = message
+ return json.dumps(result)
+
+
+class RequestCode_HTTP_500_INTERNAL_SERVER_ERROR(RequestStatusCode):
+ def __init__(self) -> None:
+ super().__init__()
+
+ def __call__(self, data):
+ return (self.response(data), self.status_code(), self.headers())
+
+ def status_code(self):
+ return 500
+
+ def response(self, message="credential lookup mismatch"):
+ result = {}
+ result["message"] = message
+ return json.dumps(result)
+
diff --git a/src/server/BreCal/brecal_utils/test_handling.py b/src/server/BreCal/brecal_utils/test_handling.py
new file mode 100644
index 0000000..070dac1
--- /dev/null
+++ b/src/server/BreCal/brecal_utils/test_handling.py
@@ -0,0 +1,84 @@
+
+def execute_test_with_pytest(filepath):
+ """
+ creates a subprocess to use 'pytest' on a script. Every function inside the filepath
+ will be tested individually. The function returns verbose information about the outcome.
+
+ filepath:
+ can either be an individual .py file or a root directory, which contains multiple files
+ """
+ import os
+ import pytest
+ from subprocess import Popen, PIPE
+
+ assert os.path.exists(filepath), f"cannot find file {filepath}"
+
+ with Popen(['pytest',
+ '-v',
+ '-W ignore::DeprecationWarning',
+ '-vv',
+ '--durations=0',
+ '--tb=short', # shorter traceback format
+ str(filepath)], stdout=PIPE, bufsize=1,
+ universal_newlines=True) as p:
+ for line in p.stdout:
+ print(line, end='')
+ return
+
+def execute_coverage_test(tests_path, coverage_path, cov_report_dst_dir=None, cov_fail_under_rate=80, is_test=0):
+ """
+ creates a subprocess to use 'coverage' on a script. Every function inside the file
+ will be tested individually. The function returns verbose information about the outcome.
+
+ this function needs two inputs:
+ tests_path, a path that locates each test that should be executed
+ e.g.: "/home/scope_sorting/brecal/src/server/tests"
+
+ coverage_path, a path where the code is stored, which should be analyzed for coverage
+ e.g.: "/home/scope_sorting/brecal/src/server/BreCal"
+
+ optional:
+ cov_report_dst_dir, which determines, where the coverage report will be stored. This function then
+ creates & stores an .html and .xml report in that folder. default: None
+
+ cov_fail_under_rate, an integer which determines, when a coverage test should fail. Default: 80, meaning
+ that at least 80 % of the directory should be tested to pass the test.
+ """
+ import os
+ import pytest
+ from subprocess import Popen, PIPE
+
+ assert os.path.exists(tests_path), f"cannot find root directory {tests_path}"
+ assert os.path.exists(coverage_path), f"cannot find root directory {coverage_path}"
+
+ if cov_report_dst_dir is not None:
+ p_open_list_arguments = [
+ 'pytest',
+ f"{str(tests_path)}",
+ "-v",
+ "-vv",
+ "--durations=0",
+ "--cov-report=term",
+ f"--cov-report=html:{cov_report_dst_dir}",
+ f"--cov-report=xml:{cov_report_dst_dir}/coverage.xml",
+ f"--cov-fail-under={cov_fail_under_rate}",
+ f"--cov={str(coverage_path)}",
+ ]
+ else:
+ p_open_list_arguments = [
+ 'pytest',
+ f"{str(tests_path)}",
+ "-v",
+ "-vv",
+ "--durations=0",
+ "--cov-report=term",
+ f"--cov-fail-under={cov_fail_under_rate}",
+ f"--cov={str(coverage_path)}",
+ ]
+
+ with Popen(p_open_list_arguments, stdout=PIPE, bufsize=1,
+ universal_newlines=True) as p:
+ for line in p.stdout:
+ print(line, end='')
+ if is_test:
+ raise KeyboardInterrupt("is_test_interrupt")
diff --git a/src/server/BreCal/brecal_utils/time_handling.py b/src/server/BreCal/brecal_utils/time_handling.py
new file mode 100644
index 0000000..7571a67
--- /dev/null
+++ b/src/server/BreCal/brecal_utils/time_handling.py
@@ -0,0 +1,21 @@
+import datetime
+
+def difference_to_then(event_time, tgt_time=None, make_absolute=False):
+ """
+ measures the difference between {tgt_time} and {event_time}. this function automatically converts the datetime.timedelta object to seconds.
+ tgt_time defaults to {now}, if it is not specified.
+
+ Note: using divmod(time_diff, interval_duration) may be interesting to determine, how many units of {interval_duration} have passed.
+ e.g.,
+ divmod(time_diff, 3600) returns a float of hours. This will then return a tuple
+
+ options:
+ make_absolute: bool. Whether to return an absolute difference
+
+ Returns: time_diff (float)
+ """
+ tgt_time = tgt_time or datetime.datetime.now()
+ time_diff = tgt_time - event_time
+ if make_absolute:
+ return abs(time_diff.total_seconds())
+ return time_diff.total_seconds()
diff --git a/src/server/BreCal/connection_data.json b/src/server/BreCal/connection_data.json
deleted file mode 100644
index 16b58c0..0000000
--- a/src/server/BreCal/connection_data.json
+++ /dev/null
@@ -1,10 +0,0 @@
-{
-"host" : "localhost",
-"port" : 33306,
-"user" : "ds",
-"password" : "HalloWach_2323XXL!!",
-"pool_name" : "brecal_pool",
-"pool_size" : 20,
-"database" : "bremen_calling",
-"autocommit" : true
-}
\ No newline at end of file
diff --git a/src/server/BreCal/database/__init__.py b/src/server/BreCal/database/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/src/server/BreCal/database/enums.py b/src/server/BreCal/database/enums.py
new file mode 100644
index 0000000..e038643
--- /dev/null
+++ b/src/server/BreCal/database/enums.py
@@ -0,0 +1,38 @@
+from enum import Enum
+
+class ParticipantType(Enum):
+ """determines the type of a participant"""
+ NONE = 0
+ BSMD = 1
+ TERMINAL = 2
+ PILOT = 4
+ AGENCY = 8
+ MOORING = 16
+ PORT_ADMINISTRATION = 32
+ TUG = 64
+
+class ShipcallType(Enum):
+ """determines the type of a shipcall, as this changes the applicable validation rules"""
+ INCOMING = 1
+ OUTGOING = 2
+ SHIFTING = 3
+
+class ParticipantwiseTimeDelta():
+ """stores the time delta for every participant, which triggers the validation rules in the rule set '0001'"""
+ AGENCY = 1200.0 # 20 h * 60 min/h = 1200 min
+ MOORING = 960.0 # 16 h * 60 min/h = 960 min
+ PILOT = 960.0 # 16 h * 60 min/h = 960 min
+ PORT_ADMINISTRATION = 960.0 # 16 h * 60 min/h = 960 min
+ TUG = 960.0 # 16 h * 60 min/h = 960 min
+ TERMINAL = 960.0 # 16 h * 60 min/h = 960 min
+
+class StatusFlags(Enum):
+ """
+ these enumerators ensure that each traffic light validation rule state corresponds to a value, which will be used in the ValidationRules object to identify
+ the necessity of notifications.
+ """
+ NONE = 0
+ GREEN = 1
+ YELLOW = 2
+ RED = 3
+
diff --git a/src/server/BreCal/database/sql_handler.py b/src/server/BreCal/database/sql_handler.py
new file mode 100644
index 0000000..3ae0e27
--- /dev/null
+++ b/src/server/BreCal/database/sql_handler.py
@@ -0,0 +1,204 @@
+import numpy as np
+import pandas as pd
+import datetime
+from BreCal.schemas.model import Shipcall, Ship, Participant, Berth, User, Times
+from BreCal.database.enums import ParticipantType
+
+def pandas_series_to_data_model():
+ return
+
+class SQLHandler():
+ """
+ An object that reads SQL queries from the sql_connection and stores it in pandas DataFrames. The object can read all available tables
+ at once into memory, when providing 'read_all=True'.
+
+ # #TODO_initialization: shipcall_tug_map, user_role_map & role_securable_map might be mapped to the respective dataframes
+ """
+ def __init__(self, sql_connection, read_all=False):
+ self.sql_connection = sql_connection
+ self.all_schemas = self.get_all_schemas_from_mysql()
+ self.build_str_to_model_dict()
+
+ if read_all:
+ self.read_all(self.all_schemas)
+
+ def get_all_schemas_from_mysql(self):
+ with self.sql_connection.cursor(buffered=True) as cursor:
+ cursor.execute("SHOW TABLES")
+ schema = cursor.fetchall()
+ all_schemas = [schem[0] for schem in schema]
+ return all_schemas
+
+ def build_str_to_model_dict(self):
+ """
+ creates a simple dictionary, which maps a string to a data object
+ e.g.,
+ 'ship'->BreCal.schemas.model.Ship object
+ """
+ self.str_to_model_dict = {
+ "shipcall":Shipcall, "ship":Ship, "participant":Participant, "berth":Berth, "user":User, "times":Times
+ }
+ return
+
+ def read_mysql_table_to_df(self, table_name:str):
+ """determine a {table_name}, which will be read from a mysql server. returns a pandas DataFrame with the respective data"""
+ df = pd.read_sql(sql=f"SELECT * FROM {table_name}", con=self.sql_connection)
+ return df
+
+ def mysql_to_df(self, query):
+ """provide an arbitrary sql query that should be read from a mysql server {sql_connection}. returns a pandas DataFrame with the obtained data"""
+ df = pd.read_sql(query, self.sql_connection).convert_dtypes()
+ df = df.set_index('id', inplace=False) # avoid inplace updates, so the raw sql remains unchanged
+ return df
+
+ def read_all(self, all_schemas):
+ # create a dictionary, which maps every mysql schema to pandas DataFrames
+ self.df_dict = self.build_full_mysql_df_dict(all_schemas)
+
+ # update the 'participants' column in 'shipcall'
+ self.initialize_shipcall_participant_list()
+ return
+
+ def build_full_mysql_df_dict(self, all_schemas):
+ """given a list of strings {all_schemas}, every schema will be read as individual pandas DataFrames to a dictionary with the respective keys. returns: dictionary {schema_name:pd.DataFrame}"""
+ mysql_df_dict = {}
+ for schem in all_schemas:
+ query = f"SELECT * FROM {schem}"
+ mysql_df_dict[schem] = self.mysql_to_df(query)
+ return mysql_df_dict
+
+ def initialize_shipcall_participant_list(self):
+ """
+ iteratively applies the .get_participants method to each shipcall.
+ the function updates the 'participants' column.
+ """
+ # 1.) get all shipcalls
+ df = self.df_dict.get('shipcall')
+
+ # 2.) iterate over each individual shipcall, obtain the id (pandas calls it 'name')
+ # and apply the 'get_participants' method, which returns a list
+ # if the shipcall_id exists, the list contains ids
+ # otherwise, return a blank list
+ df['participants'] = df.apply(
+ lambda x: self.get_participants(x.name),
+ axis=1)
+ return
+
+ def standardize_model_str(self, model_str:str)->str:
+ """check if the 'model_str' is valid and apply lowercasing to the string"""
+ model_str = model_str.lower()
+ assert model_str in list(self.df_dict.keys()), f"cannot find the requested 'model_str' in mysql: {model_str}"
+ return model_str
+
+ def get_data(self, id:int, model_str:str):
+ """
+ obtains {id} from the respective mysql database and builds a data model from that.
+ the id should match the 'id'-column in the mysql schema.
+ returns: data model, such as Ship, Shipcall, etc.
+
+ e.g.,
+ data = self.get_data(0,"shipcall")
+ returns a Shipcall object
+ """
+ model_str = self.standardize_model_str(model_str)
+
+ df = self.df_dict.get(model_str)
+ data = self.df_loc_to_data_model(df, id, model_str)
+ return data
+
+ def get_all(self, model_str:str)->list:
+ """
+ given a model string (e.g., 'shipcall'), return a list of all
+ data models of that type from the sql
+ """
+ model_str = self.standardize_model_str(model_str)
+ all_ids = self.df_dict.get(model_str).index
+
+ all_data = [
+ self.get_data(_aid, model_str)
+ for _aid in all_ids
+ ]
+ return all_data
+
+ def df_loc_to_data_model(self, df, id, model_str, loc_type:str="loc"):
+ assert len(df)>0, f"empty dataframe"
+
+ # get a pandas series from the dataframe
+ series = df.loc[id] if loc_type=="loc" else df.iloc[id]
+
+ # get the respective data model object
+ data_model = self.str_to_model_dict.get(model_str,None)
+ assert data_model is not None, f"could not find the requested model_str: {model_str}"
+
+ # build 'data' and fill the data model object
+ # convert the 'id' to an integer, so the np.uint64 (used by pandas) is convertible to mysql
+ data = {**{'id':int(id)}, **series.to_dict()} # 'id' must be added manually, as .to_dict does not contain the index, which was set with .set_index
+ data = data_model(**data)
+ return data
+
+ def get_times_for_participant_type(self, df_times, participant_type:int):
+ filtered_series = df_times.loc[df_times["participant_type"]==participant_type]
+ assert len(filtered_series)<=1, f"found multiple results"
+ times = self.df_loc_to_data_model(filtered_series, id=0, model_str='times', loc_type="iloc") # use iloc! to retrieve the first result
+ return times
+
+ def dataframe_to_data_model_list(self, df, model_str)->list:
+ model_str = self.standardize_model_str(model_str)
+
+ all_ids = df.index
+ all_data = [
+ self.df_loc_to_data_model(df, _aid, model_str)
+ for _aid in all_ids
+ ]
+ return all_data
+
+ def get_participants(self, shipcall_id:id)->list:
+ """
+ given a {shipcall_id}, obtain the respective list of participants.
+ when there are no participants, return a blank list
+
+ returns: participant_id_list, where every element is an int
+ """
+ df = self.df_dict.get("shipcall_participant_map")
+ df = df.set_index('shipcall_id', inplace=False)
+
+ # the 'if' call is needed to ensure, that no Exception is raised, when the shipcall_id is not present in the df
+ participant_id_list = df.loc[shipcall_id, "participant_id"].to_list() if shipcall_id in list(df.index) else []
+ return participant_id_list
+
+ def get_times_of_shipcall(self, shipcall)->pd.DataFrame:
+ df_times = self.df_dict.get('times') # -> pd.DataFrame
+ df_times = df_times.loc[df_times["shipcall_id"]==shipcall.id]
+ return df_times
+
+ def get_times_for_agency(self, non_null_column=None)->pd.DataFrame:
+ """
+ options:
+ non_null_column:
+ None or str. If provided, the 'non_null_column'-column of the dataframe will be filtered,
+ so only entries with provided values are returned (filters all NaN and NaT entries)
+ """
+ # get all times
+ df_times = self.df_dict.get('times') # -> pd.DataFrame
+
+ # filter out all NaN and NaT entries
+ if non_null_column is not None:
+ df_times = df_times.loc[~df_times[non_null_column].isnull()] # NOT null filter
+
+ # filter by the agency participant_type
+ times_agency = df_times.loc[df_times["participant_type"]==ParticipantType.AGENCY.value]
+ return times_agency
+
+ def filter_df_by_key_value(self, df, key, value)->pd.DataFrame:
+ return df.loc[df[key]==value]
+
+ def get_unique_ship_counts(self, all_df_times:pd.DataFrame, query:str, rounding:str="min", maximum_threshold=3):
+ """given a dataframe of all agency times, get all unique ship counts, their values (datetime) and the string tags. returns a tuple (values,unique,counts)"""
+ # get values and optional: rounding
+ values = all_df_times.loc[:, query]
+ if rounding is not None:
+ values = values.dt.round(rounding) # e.g., 'min'
+
+ unique, counts = np.unique(values, return_counts=True)
+ violation_state = np.any(np.greater(counts, maximum_threshold))
+ return (values, unique, counts)
diff --git a/src/server/BreCal/database/update_database.py b/src/server/BreCal/database/update_database.py
new file mode 100644
index 0000000..0e5e5ac
--- /dev/null
+++ b/src/server/BreCal/database/update_database.py
@@ -0,0 +1,102 @@
+import json
+import pydapper
+import pandas as pd
+import mysql.connector
+
+from BreCal.database.sql_handler import SQLHandler
+from BreCal.validators.validation_rules import ValidationRules
+from BreCal.schemas.model import Shipcall
+
+def update_shipcall_in_mysql_database(sql_connection, shipcall:Shipcall, relevant_keys:list = ["evaluation", "evaluation_message"]):
+ """
+ given an individual schemaModel (e.g., Shipcall.__dict__), update the entry within the mysql database
+
+ options:
+ sql_connection: an instance of mysql.connector.connect
+ shipcall: a Shipcall data model
+ relevant_keys: a list of the keys to be updated. Should never contain 'id', which is immutable
+
+ returns: (query, affected_rows)
+ """
+ assert not "id" in relevant_keys, f"the 'id' key should never be updated."
+ schemaModel = shipcall.__dict__
+
+ commands = pydapper.using(sql_connection)
+ sentinel = object()
+ theshipcall = commands.query_single_or_default("SELECT * FROM shipcall where id = ?id?", sentinel, param={"id" : schemaModel["id"]})
+
+ if theshipcall is sentinel:
+ return json.dumps("no such record"), 404, {'Content-Type': 'application/json; charset=utf-8'}
+
+ query = build_mysql_query_to_update_shipcall(shipcall=shipcall, relevant_keys=relevant_keys)
+ affected_rows = commands.execute(query, param=schemaModel)
+ return (query, affected_rows)
+
+def build_mysql_query_to_update_shipcall(shipcall, relevant_keys:list):
+ """builds a mysql query, which updates the shipcall table. In particular, the provided shipcall will be updated for each key in {relevant_keys}"""
+ schemaModel = shipcall.__dict__
+
+ # prepare prefix and suffix. Then build the body of the query
+ prefix = "UPDATE shipcall SET "
+ suffix = "where id = ?id?"
+ body = ", ".join([f"{key} = ?{key}? " for key in schemaModel.keys() if (key in relevant_keys)]) # .join ignores the first ', ', which equals the 'isNotFirst' boolean-loop
+
+ # build query
+ query = f"{prefix}{body}{suffix}"
+ return query
+
+def update_all_shipcalls_in_mysql_database(sql_connection, sql_handler:SQLHandler, shipcall_df:pd.DataFrame)->None:
+ """
+ iterates over each shipcall_id in a shipcall dataframe, builds Shipcall data models and updates those in the sql database, which
+ is located in {sql_connection}
+
+ options:
+ sql_connection: an instance of mysql.connector.connect
+ sql_handler: an SQLHandler instance
+ shipcall_df: dataframe, which stores the data that is used to retrieve the shipcall data models (that are then updated in the database)
+ """
+ for shipcall_id in shipcall_df.index:
+ shipcall = sql_handler.df_loc_to_data_model(df=shipcall_df, id=shipcall_id, model_str="shipcall")
+ update_shipcall_in_mysql_database(sql_connection, shipcall=shipcall, relevant_keys = ["evaluation", "evaluation_message"])
+ return
+
+def evaluate_shipcall_state(mysql_connector_instance, shipcall_id:int=None, debug=False)->pd.DataFrame:
+ """
+ options:
+ mysql_connector_instance: an instance created by the mysql.connector.connect() call. It is advised to use Python's context manager to close the connection after finished.
+ e.g.,
+ with mysql.connector.connect(**mysql_connection_data) as mysql_connector_instance:
+ evaluate_shipcall_state(mysql_connector_instance)
+ returns None
+
+ """
+ sql_handler = SQLHandler(sql_connection=mysql_connector_instance, read_all=True)
+ vr = ValidationRules(sql_handler)
+
+ shipcall_df = sql_handler.df_dict.get("shipcall")
+
+ if shipcall_id is not None:
+ shipcall_df = shipcall_df.loc[[shipcall_id]]
+
+ # placeholder: filter shipcalls. For example, exclude historic entries.
+ shipcall_df = vr.evaluate_shipcalls(shipcall_df)
+
+ if debug:
+ return shipcall_df
+
+ # iterate over each shipcall in shipcall_df and update the respective entry in the mysql database
+ update_all_shipcalls_in_mysql_database(sql_connection=mysql_connector_instance, sql_handler=sql_handler, shipcall_df=shipcall_df)
+ return shipcall_df
+
+def update_shipcall_evaluation_state(mysql_connection_data:dict, shipcall_id:int=None)->pd.DataFrame:
+ """
+ single line function to connect to a mysql database (using the {mysql_connection_data}), evaluate each shipcall (bei traffic state)
+ and finally, update those in the database.
+
+ options:
+ mysql_connection_data: connection data to the mysql database (e.g., port, host, password)
+ shipcall_id: int. ID of the shipcall to be updated. Defaults to 'None'. When providing 'None', all shipcalls are updated.
+ """
+ with mysql.connector.connect(**mysql_connection_data) as mysql_connector_instance:
+ shipcall_df = evaluate_shipcall_state(mysql_connector_instance=mysql_connector_instance, shipcall_id=shipcall_id, debug=False)
+ return shipcall_df
diff --git a/src/server/BreCal/impl/berths.py b/src/server/BreCal/impl/berths.py
index 6c41ba9..7581d32 100644
--- a/src/server/BreCal/impl/berths.py
+++ b/src/server/BreCal/impl/berths.py
@@ -15,7 +15,7 @@ def GetBerths(token):
try:
pooledConnection = local_db.getPoolConnection()
commands = pydapper.using(pooledConnection)
- data = commands.query("SELECT id, name, participant_id, `lock`, created, modified, deleted FROM berth ORDER BY name", model=model.Berth)
+ data = commands.query("SELECT id, name, participant_id, `lock`, owner_id, authority_id, created, modified, deleted FROM berth WHERE deleted = 0 ORDER BY name", model=model.Berth)
pooledConnection.close()
except Exception as ex:
diff --git a/src/server/BreCal/impl/login.py b/src/server/BreCal/impl/login.py
index cef9e4c..5f1847b 100644
--- a/src/server/BreCal/impl/login.py
+++ b/src/server/BreCal/impl/login.py
@@ -26,9 +26,10 @@ def GetUser(options):
"first_name": data[0].first_name,
"last_name": data[0].last_name,
"user_name": data[0].user_name,
- "user_phone": data[0].user_phone
+ "user_phone": data[0].user_phone,
+ "user_email": data[0].user_email
}
- token = jwt_handler.generate_jwt(payload=result, lifetime=60) # generate token valid 60 mins
+ token = jwt_handler.generate_jwt(payload=result, lifetime=120) # generate token valid 60 mins
result["token"] = token # add token to user data
return json.dumps(result), 200, {'Content-Type': 'application/json; charset=utf-8'}
diff --git a/src/server/BreCal/impl/shipcalls.py b/src/server/BreCal/impl/shipcalls.py
index 2a61951..1e29dec 100644
--- a/src/server/BreCal/impl/shipcalls.py
+++ b/src/server/BreCal/impl/shipcalls.py
@@ -6,6 +6,8 @@ import pydapper
from ..schemas import model
from .. import local_db
+from BreCal.database.update_database import evaluate_shipcall_state
+
def GetShipcalls(options):
"""
No parameters, gets all entries
@@ -17,14 +19,19 @@ def GetShipcalls(options):
pooledConnection = local_db.getPoolConnection()
commands = pydapper.using(pooledConnection)
- data = commands.query("SELECT id, ship_id, type, eta, voyage, etd, arrival_berth_id, departure_berth_id, tug_required, pilot_required, " +
- "flags, pier_side, bunkering, replenishing_terminal, replenishing_lock, draft, tidal_window_from, tidal_window_to, rain_sensitive_cargo, recommended_tugs, " +
- "anchored, moored_lock, canceled, created, modified FROM shipcall WHERE eta IS NULL OR eta >= DATE(NOW() - INTERVAL 2 DAY) " +
- "ORDER BY eta", model=model.Shipcall)
+ query = ("SELECT id, ship_id, type, eta, voyage, etd, arrival_berth_id, departure_berth_id, tug_required, pilot_required, "
+ "flags, pier_side, bunkering, replenishing_terminal, replenishing_lock, draft, tidal_window_from, tidal_window_to, rain_sensitive_cargo, recommended_tugs, "
+ "anchored, moored_lock, canceled, evaluation, evaluation_message, created, modified FROM shipcall WHERE ((type = 1 OR type = 2) AND eta >= DATE(NOW() - INTERVAL %d DAY)"
+ "OR (type = 3 AND etd >= DATE(NOW() - INTERVAL %d DAY))) "
+ "ORDER BY eta") % (options["past_days"], options["past_days"])
+
+ data = commands.query(query, model=model.Shipcall)
for shipcall in data:
- participant_query = "SELECT participant_id FROM shipcall_participant_map WHERE shipcall_id=?shipcall_id?";
+ participant_query = "SELECT participant_id, type FROM shipcall_participant_map WHERE shipcall_id=?shipcall_id?";
for record in commands.query(participant_query, model=dict, param={"shipcall_id" : shipcall.id}, buffered=False):
- shipcall.participants.append(record["participant_id"])
+ # model.Participant_Assignment = model.Participant_Assignment()
+ pa = model.Participant_Assignment(record["participant_id"], record["type"])
+ shipcall.participants.append(pa)
pooledConnection.close()
@@ -63,6 +70,10 @@ def PostShipcalls(schemaModel):
continue
if key == "modified":
continue
+ if key == "evaluation":
+ continue
+ if key == "evaluation_message":
+ continue
if isNotFirst:
query += ","
isNotFirst = True
@@ -78,6 +89,10 @@ def PostShipcalls(schemaModel):
continue
if key == "modified":
continue
+ if key == "evaluation":
+ continue
+ if key == "evaluation_message":
+ continue
if isNotFirst:
query += ","
isNotFirst = True
@@ -88,11 +103,12 @@ def PostShipcalls(schemaModel):
new_id = commands.execute_scalar("select last_insert_id()")
# add participant assignments
- # TODO: make sure there are not two participants of the same type
+ pquery = "INSERT INTO shipcall_participant_map (shipcall_id, participant_id, type) VALUES (?shipcall_id?, ?participant_id?, ?type?)"
+ for participant_assignment in schemaModel["participants"]:
+ commands.execute(pquery, param={"shipcall_id" : new_id, "participant_id" : participant_assignment["participant_id"], "type" : participant_assignment["type"]})
- pquery = "INSERT INTO shipcall_participant_map (shipcall_id, participant_id) VALUES (?shipcall_id?, ?participant_id?)"
- for participant_id in schemaModel["participants"]:
- commands.execute(pquery, param={"shipcall_id" : new_id, "participant_id" : participant_id})
+ # apply 'Traffic Light' evaluation to obtain 'GREEN', 'YELLOW' or 'RED' evaluation state. The function internally updates the mysql database
+ evaluate_shipcall_state(mysql_connector_instance=pooledConnection, shipcall_id=new_id) # new_id (last insert id) refers to the shipcall id
pooledConnection.close()
@@ -137,6 +153,10 @@ def PutShipcalls(schemaModel):
continue
if key == "modified":
continue
+ if key == "evaluation":
+ continue
+ if key == "evaluation_message":
+ continue
if isNotFirst:
query += ", "
isNotFirst = True
@@ -145,33 +165,35 @@ def PutShipcalls(schemaModel):
query += "WHERE id = ?id?"
affected_rows = commands.execute(query, param=schemaModel)
- pquery = "SELECT id, participant_id FROM shipcall_participant_map where shipcall_id = ?id?"
+ pquery = "SELECT id, participant_id, type FROM shipcall_participant_map where shipcall_id = ?id?"
pdata = commands.query(pquery,param={"id" : schemaModel["id"]}) # existing list of assignments
# loop across passed participant ids, creating entries for those not present in pdata
- # TODO: make sure there are not two participants of the same type
- for participant_id in schemaModel["participants"]:
+ for participant_assignment in schemaModel["participants"]:
found_participant = False
for elem in pdata:
- if elem["participant_id"] == participant_id:
+ if elem["participant_id"] == participant_assignment["participant_id"] and elem["type"] == participant_assignment["type"]:
found_participant = True
break
if not found_participant:
- nquery = "INSERT INTO shipcall_participant_map (shipcall_id, participant_id) VALUES (?shipcall_id?, ?participant_id?)"
- commands.execute(nquery, param={"shipcall_id" : schemaModel["id"], "participant_id" : participant_id})
+ nquery = "INSERT INTO shipcall_participant_map (shipcall_id, participant_id, type) VALUES (?shipcall_id?, ?participant_id?, ?type?)"
+ commands.execute(nquery, param={"shipcall_id" : schemaModel["id"], "participant_id" : participant_assignment["participant_id"], "type" : participant_assignment["type"]})
# loop across existing pdata entries, deleting those not present in participant list
for elem in pdata:
found_participant = False
- for participant_id in schemaModel["participants"]:
- if(participant_id == elem["participant_id"]):
+ for participant_assignment in schemaModel["participants"]:
+ if(participant_assignment["participant_id"] == elem["participant_id"] and participant_assignment["type"] == elem["type"]):
found_participant = True
break;
if not found_participant:
dquery = "DELETE FROM shipcall_participant_map WHERE id = ?existing_id?"
commands.execute(dquery, param={"existing_id" : elem["id"]})
+ # apply 'Traffic Light' evaluation to obtain 'GREEN', 'YELLOW' or 'RED' evaluation state. The function internally updates the mysql database
+ evaluate_shipcall_state(mysql_connector_instance=pooledConnection, shipcall_id=schemaModel["id"]) # schemaModel["id"] refers to the shipcall id
+
pooledConnection.close()
return json.dumps({"id" : schemaModel["id"]}), 200
diff --git a/src/server/BreCal/impl/times.py b/src/server/BreCal/impl/times.py
index def3cfe..56e4c3f 100644
--- a/src/server/BreCal/impl/times.py
+++ b/src/server/BreCal/impl/times.py
@@ -5,6 +5,8 @@ import pydapper
from ..schemas import model
from .. import local_db
+from BreCal.database.update_database import evaluate_shipcall_state
+
def GetTimes(options):
"""
:param options: A dictionary containing all the paramters for the Operations
@@ -80,6 +82,9 @@ def PostTimes(schemaModel):
commands.execute(query, schemaModel)
new_id = commands.execute_scalar("select last_insert_id()")
+ # apply 'Traffic Light' evaluation to obtain 'GREEN', 'YELLOW' or 'RED' evaluation state. The function internally updates the mysql database 'shipcall'
+ evaluate_shipcall_state(mysql_connector_instance=pooledConnection, shipcall_id=schemaModel["shipcall_id"]) # every times data object refers to the 'shipcall_id'
+
pooledConnection.close()
return json.dumps({"id" : new_id}), 201, {'Content-Type': 'application/json; charset=utf-8'}
@@ -122,12 +127,16 @@ def PutTimes(schemaModel):
affected_rows = commands.execute(query, param=schemaModel)
+ # apply 'Traffic Light' evaluation to obtain 'GREEN', 'YELLOW' or 'RED' evaluation state. The function internally updates the mysql database 'shipcall'
+ evaluate_shipcall_state(mysql_connector_instance=pooledConnection, shipcall_id=schemaModel["shipcall_id"]) # every times data object refers to the 'shipcall_id'
+
pooledConnection.close()
- if affected_rows == 1:
- return json.dumps({"id" : schemaModel["id"]}), 200, {'Content-Type': 'application/json; charset=utf-8'}
+ # if affected_rows == 1: # this doesn't work as expected
- return json.dumps("no such record"), 404, {'Content-Type': 'application/json; charset=utf-8'}
+ return json.dumps({"id" : schemaModel["id"]}), 200, {'Content-Type': 'application/json; charset=utf-8'}
+
+ # return json.dumps("no such record"), 404, {'Content-Type': 'application/json; charset=utf-8'}
except Exception as ex:
logging.error(ex)
diff --git a/src/server/BreCal/impl/user.py b/src/server/BreCal/impl/user.py
index ece0d5f..699e4bf 100644
--- a/src/server/BreCal/impl/user.py
+++ b/src/server/BreCal/impl/user.py
@@ -27,7 +27,7 @@ def PutUser(schemaModel):
return json.dumps("no such record"), 404, {'Content-Type': 'application/json; charset=utf-8'}
# see if we need to update public fields
- if "first_name" in schemaModel or "last_name" in schemaModel or "user_phone" in schemaModel:
+ if "first_name" in schemaModel or "last_name" in schemaModel or "user_phone" in schemaModel or "user_email" in schemaModel:
query = "UPDATE user SET "
isNotFirst = False
for key in schemaModel.keys():
diff --git a/src/server/BreCal/local_db.py b/src/server/BreCal/local_db.py
index 5b8c631..4afd51b 100644
--- a/src/server/BreCal/local_db.py
+++ b/src/server/BreCal/local_db.py
@@ -4,15 +4,19 @@ import logging
import json
import os
-connection_pool = None
+config_path = None
-def initPool():
+def initPool(instancePath):
try:
+ global config_path
+ if(config_path == None):
+ config_path = os.path.join(instancePath,'../../../secure/connection_data_test.json');
+
+ print (config_path)
- config_path = './src/server/BreCal/connection_data.json'
- print (os.getcwd())
if not os.path.exists(config_path):
print ('cannot find ' + config_path)
+ print("instance path", instancePath)
exit(1)
f = open(config_path);
@@ -31,7 +35,7 @@ def initPool():
print(e)
def getPoolConnection():
- config_path = './src/server/BreCal/connection_data.json'
+ global config_path
f = open(config_path);
connection_data = json.load(f)
return mysql.connector.connect(**connection_data)
\ No newline at end of file
diff --git a/src/server/BreCal/schemas/__init__.py b/src/server/BreCal/schemas/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/src/server/BreCal/schemas/model.py b/src/server/BreCal/schemas/model.py
index 9671492..905d412 100644
--- a/src/server/BreCal/schemas/model.py
+++ b/src/server/BreCal/schemas/model.py
@@ -18,6 +18,8 @@ class Berth(Schema):
name: str
participant_id: int
lock: bool
+ owner_id: int
+ authority_id: int
created: datetime
modified: datetime
deleted: bool
@@ -57,6 +59,10 @@ class Participant(Schema):
class ParticipantList(Participant):
pass
+class ParticipantAssignmentSchema(Schema):
+ participant_id = fields.Int()
+ type = fields.Int()
+
class ShipcallSchema(Schema):
def __init__(self):
super().__init__(unknown=None)
@@ -65,7 +71,7 @@ class ShipcallSchema(Schema):
id = fields.Int()
ship_id = fields.Int()
type = fields.Int()
- eta = fields.DateTime()
+ eta = fields.DateTime(Required = False, allow_none=True)
voyage = fields.Str(Required = False, allow_none=True)
etd = fields.DateTime(Required = False, allow_none=True)
arrival_berth_id = fields.Int(Required = False, allow_none=True)
@@ -85,10 +91,22 @@ class ShipcallSchema(Schema):
anchored = fields.Bool(Required = False, allow_none=True)
moored_lock = fields.Bool(Required = False, allow_none=True)
canceled = fields.Bool(Required = False, allow_none=True)
- participants = fields.List(fields.Int)
+ evaluation = fields.Int(Required = False, allow_none=True)
+ evaluation_message = fields.Str(Required = False, allow_none=True)
+ participants = fields.List(fields.Nested(ParticipantAssignmentSchema))
created = fields.DateTime(Required = False, allow_none=True)
modified = fields.DateTime(Required = False, allow_none=True)
+@dataclass
+class Participant_Assignment:
+ def __init__(self, participant_id, type):
+ self.participant_id = participant_id
+ self.type = type
+ pass
+
+ participant_id: int
+ type: int
+
@dataclass
class Shipcall:
@@ -115,9 +133,11 @@ class Shipcall:
anchored: bool
moored_lock: bool
canceled: bool
+ evaluation: int
+ evaluation_message: str
created: datetime
modified: datetime
- participants: List[int] = field(default_factory=list)
+ participants: List[Participant_Assignment] = field(default_factory=list)
class ShipcallId(Schema):
pass
@@ -157,11 +177,12 @@ class UserSchema(Schema):
super().__init__(unknown=None)
pass
id = fields.Int(required=True)
- first_name = fields.Str(required=False)
- last_name = fields.Str(required=False)
- user_phone = fields.Str(required=False)
- old_password = fields.Str(required=False)
- new_password = fields.Str(required=False)
+ first_name = fields.Str(Required=False, allow_none=True)
+ last_name = fields.Str(required=False, allow_none=True)
+ user_phone = fields.Str(required=False, allow_none=True)
+ user_email = fields.Str(required=False, allow_none=True)
+ old_password = fields.Str(required=False, allow_none=True)
+ new_password = fields.Str(required=False, allow_none=True)
@dataclass
class Times:
diff --git a/src/server/BreCal/services/__init__.py b/src/server/BreCal/services/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/src/server/BreCal/stubs/__init__.py b/src/server/BreCal/stubs/__init__.py
new file mode 100644
index 0000000..83dd2ed
--- /dev/null
+++ b/src/server/BreCal/stubs/__init__.py
@@ -0,0 +1,5 @@
+
+def generate_uuid1_int():
+ """# TODO: clarify, what kind of integer ID is used in mysql. Generates a proxy ID, which is used in the stubs"""
+ from uuid import uuid1
+ return uuid1().int>>64
diff --git a/src/server/BreCal/stubs/berth.py b/src/server/BreCal/stubs/berth.py
new file mode 100644
index 0000000..240bcbe
--- /dev/null
+++ b/src/server/BreCal/stubs/berth.py
@@ -0,0 +1,31 @@
+import datetime
+from BreCal.stubs import generate_uuid1_int
+from BreCal.schemas.model import Berth
+
+def get_berth_simple():
+ berth_id = generate_uuid1_int() # uid?
+
+ # Note: #TODO: name, participant_id & lock state are arbitrary
+ name = "Avangard Dalben"
+ participant_id = 1# e.g., Avangard
+ lock = False
+ owner_id = 1 # e.g., Avangard
+ authority_id = 1 # e.g., Avangard
+
+ created = datetime.datetime.now()
+ modified = created+datetime.timedelta(seconds=10)
+ deleted = modified+datetime.timedelta(seconds=3)
+
+ berth = Berth(
+ berth_id,
+ name,
+ participant_id,
+ lock,
+ owner_id,
+ authority_id,
+ created,
+ modified,
+ deleted,
+ )
+ return berth
+
diff --git a/src/server/BreCal/stubs/notification.py b/src/server/BreCal/stubs/notification.py
new file mode 100644
index 0000000..63df90f
--- /dev/null
+++ b/src/server/BreCal/stubs/notification.py
@@ -0,0 +1,49 @@
+import datetime
+from BreCal.stubs import generate_uuid1_int
+from BreCal.schemas.model import Notification
+
+
+def get_notification_simple():
+ """creates a default notification, where 'created' is now, and modified is now+10 seconds"""
+ notification_id = generate_uuid1_int() # uid?
+ times_id = generate_uuid1_int() # uid?
+ acknowledged = False
+ level = 10
+ type = 0
+ message = "hello world"
+ created = datetime.datetime.now()
+ modified = created+datetime.timedelta(seconds=10)
+
+ notification = Notification(
+ notification_id,
+ times_id,
+ acknowledged,
+ level,
+ type,
+ message,
+ created,
+ modified
+ )
+ return notification
+
+def get_notification_in_the_past(created_delta_seconds, modified_delta_seconds, acknowledged=False):
+ """
+ creates a notification of the past, where the
+ 'created' date is {created_delta_seconds} seconds ago
+ 'modified' date is {modified_delta_seconds} seconds ago
+
+ for example, if datetime.datetime.now() returns
+ now = datetime.datetime(2023, 9, 15, 7, 25, 50, 733644)), then calling this function
+ as get_notification_modified_in_the_past(2*60, 1*60) provides
+ 'created':datetime.datetime(2023, 9, 15, 7, 23, 50, 733644) (two minutes ago)
+ 'modified':datetime.datetime(2023, 9, 15, 7, 24, 50, 733644) (one minute ago)
+
+ optionally, one can also overwrite the 'acknowledged' attribute
+ returns notification
+ """
+ notification = get_notification_simple()
+ notification.created = datetime.datetime.now()-datetime.timedelta(seconds=created_delta_seconds)
+ notification.modified = datetime.datetime.now()-datetime.timedelta(seconds=modified_delta_seconds)
+ notification.acknowledged = acknowledged
+ return notification
+
diff --git a/src/server/BreCal/stubs/participant.py b/src/server/BreCal/stubs/participant.py
new file mode 100644
index 0000000..38f303c
--- /dev/null
+++ b/src/server/BreCal/stubs/participant.py
@@ -0,0 +1,32 @@
+import datetime
+from BreCal.stubs import generate_uuid1_int
+from BreCal.schemas.model import Participant
+
+def get_participant_simple():
+ participant_id = generate_uuid1_int()
+
+ # #TODO: role_type and flags are arbitrary
+ name = "Max Mustermann"
+ street = "Musterstrasse 1"
+ postal_code = "12345"
+ city = "Bremen"
+ role_type = 1 # integer
+ flags = 0 # integer. unclear
+
+ created = datetime.datetime.now()
+ modified = created+datetime.timedelta(seconds=10)
+ deleted = modified+datetime.timedelta(seconds=3)
+
+ participant = Participant(
+ participant_id,
+ name,
+ street,
+ postal_code,
+ city,
+ role_type,
+ flags,
+ created,
+ modified,
+ deleted
+ )
+ return participant
diff --git a/src/server/BreCal/stubs/roles.py b/src/server/BreCal/stubs/roles.py
new file mode 100644
index 0000000..e69de29
diff --git a/src/server/BreCal/stubs/ship.py b/src/server/BreCal/stubs/ship.py
new file mode 100644
index 0000000..4ab288e
--- /dev/null
+++ b/src/server/BreCal/stubs/ship.py
@@ -0,0 +1,38 @@
+import datetime
+from BreCal.stubs import generate_uuid1_int
+from BreCal.schemas.model import Ship
+
+def get_ship_simple():
+ ship_id = generate_uuid1_int()
+ name = "african halcyon".upper() # 'Schiffe_sample_format.xlsx' uses .upper() for every ship
+ imo = 9343613 # assert str(len(imo))==7
+ callsign = 1234567 # up to 7 characters. assert str(len(callsign))<=7
+ participant_id = generate_uuid1_int()
+ length = 177.13 # assert 0>length<=500
+ width = 28.4 # assert 0>width<=500
+ is_tug = False
+ bollard_pull = None # only if is_tug
+ participant_id = None # only if is_tug
+ eni = "01234567" # Alternative to IMO. Dynamic assertion? assert len(str(eni))==8
+
+ created = datetime.datetime.now()
+ modified = created+datetime.timedelta(seconds=10)
+ deleted = modified+datetime.timedelta(seconds=3)
+
+ ship = Ship(
+ ship_id,
+ name,
+ imo,
+ callsign,
+ participant_id,
+ length,
+ width,
+ is_tug,
+ bollard_pull,
+ eni,
+ created,
+ modified,
+ deleted
+ )
+ return ship
+
diff --git a/src/server/BreCal/stubs/shipcall.py b/src/server/BreCal/stubs/shipcall.py
new file mode 100644
index 0000000..c76a8e9
--- /dev/null
+++ b/src/server/BreCal/stubs/shipcall.py
@@ -0,0 +1,81 @@
+import datetime
+from BreCal.stubs import generate_uuid1_int
+from BreCal.schemas.model import Shipcall
+from dataclasses import field
+
+def get_shipcall_simple():
+ # only used for the stub
+ base_time = datetime.datetime.now()
+
+ shipcall_id = generate_uuid1_int()
+ ship_id = generate_uuid1_int()
+
+ eta = base_time+datetime.timedelta(hours=3, minutes=12)
+ role_type = 1
+ voyage = "987654321"
+ etd = base_time+datetime.timedelta(hours=6, minutes=12) # should never be before eta
+
+ arrival_berth_id = generate_uuid1_int()
+ departure_berth_id = generate_uuid1_int()
+
+ tug_required = False
+ pilot_required = False
+
+ flags = 0 # #TODO_shipcall_flags. What is meant here? What should be tested?
+ pier_side = False # whether a ship will be fixated on the pier side. en: pier side, de: Anlegestelle. From 'BremenCalling_Datenmodell.xlsx': gedreht/ungedreht
+ bunkering = False # #TODO_bunkering_unclear
+ replenishing_terminal = False # en: replenishing terminal, de: Nachfüll-Liegeplatz
+ replenishing_lock = False # en: replenishing lock, de: Nachfüllschleuse
+
+ draft = 0.12 # #TODO_draft_value: clarify, what 'draft' means and what kind of values are to be expected
+
+ # tidal window: built in a way, where ETA and ETD are in-between the window
+ # #TODO_tidal_window_source: are these windows taken from a database or provided by the user? How do they know this?
+ tidal_window_from = base_time+datetime.timedelta(hours=2, minutes=12)
+ tidal_window_to = base_time+datetime.timedelta(hours=7, minutes=12)
+ rain_sensitive_cargo = False
+ recommended_tugs = 2 # assert 0eta (for berth) & lock
+ # note 2: times are currently computed as a sequence of (eta_berth -> lock_time -> etd_berth -> zone_entry). The deltas are arbitrary
+ times_id = generate_uuid1_int()
+
+ eta_berth = base_time+datetime.timedelta(hours=1, minutes=12)
+ eta_berth_fixed = False
+
+ lock_time = eta_berth+datetime.timedelta(hours=0, minutes=50)
+ lock_time_fixed = False
+
+ etd_berth = lock_time+datetime.timedelta(hours=0, minutes=45)
+ etd_berth_fixed = False
+
+ zone_entry = etd_berth+datetime.timedelta(hours=0, minutes=15)
+ zone_entry_fixed = False
+
+ operations_start = zone_entry+datetime.timedelta(hours=1, minutes=30)
+ operations_end = operations_start+datetime.timedelta(hours=4, minutes=30)
+
+ remarks = "" # assert len(remarks)<{max_len_threshold}
+
+ participant_id = generate_uuid1_int()
+ shipcall_id = generate_uuid1_int()
+
+ berth_id = generate_uuid1_int()
+ berth_info = ""
+ pier_side = True
+ participant_type = None
+
+ created = datetime.datetime.now()
+ modified = created+datetime.timedelta(seconds=10)
+
+ times = Times(
+ id=times_id,
+ eta_berth=eta_berth,
+ eta_berth_fixed=eta_berth_fixed,
+ etd_berth=etd_berth,
+ etd_berth_fixed=etd_berth_fixed,
+ lock_time=lock_time,
+ lock_time_fixed=lock_time_fixed,
+ zone_entry=zone_entry,
+ zone_entry_fixed=zone_entry_fixed,
+ operations_start=operations_start,
+ operations_end=operations_end,
+ remarks=remarks,
+ participant_id=participant_id,
+ berth_id=berth_id,
+ berth_info=berth_info,
+ pier_side=pier_side,
+ participant_type=participant_type,
+ shipcall_id=shipcall_id,
+ created=created,
+ modified=modified,
+ )
+ return times
diff --git a/src/server/BreCal/stubs/times_mooring.py b/src/server/BreCal/stubs/times_mooring.py
new file mode 100644
index 0000000..e69de29
diff --git a/src/server/BreCal/stubs/times_pilot.py b/src/server/BreCal/stubs/times_pilot.py
new file mode 100644
index 0000000..e69de29
diff --git a/src/server/BreCal/stubs/times_portauthority.py b/src/server/BreCal/stubs/times_portauthority.py
new file mode 100644
index 0000000..e69de29
diff --git a/src/server/BreCal/stubs/times_terminal.py b/src/server/BreCal/stubs/times_terminal.py
new file mode 100644
index 0000000..e69de29
diff --git a/src/server/BreCal/stubs/user.py b/src/server/BreCal/stubs/user.py
new file mode 100644
index 0000000..e469c55
--- /dev/null
+++ b/src/server/BreCal/stubs/user.py
@@ -0,0 +1,35 @@
+import bcrypt
+import datetime
+from BreCal.stubs import generate_uuid1_int
+from BreCal.schemas.model import User
+
+
+def get_user_simple():
+ user_id = generate_uuid1_int()
+ participant_id = generate_uuid1_int() # should be taken from the database
+
+ first_name = "Max"
+ last_name = "Mustermann"
+ user_name = "maxm123"
+ user_email = "max.mustermann@brecal.de"
+ user_phone = "0173123456" # formatting?
+ password_hash = bcrypt.hashpw("123456".encode('utf-8'), bcrypt.gensalt( 12 )).decode('utf8')
+ api_key = bcrypt.hashpw("apikey123".encode('utf-8'), bcrypt.gensalt( 12 )).decode('utf8')
+
+ created = datetime.datetime.now()
+ modified = created+datetime.timedelta(seconds=10)
+
+ user = User(
+ user_id,
+ participant_id,
+ first_name,
+ last_name,
+ user_name,
+ user_email,
+ user_phone,
+ password_hash,
+ api_key,
+ created,
+ modified
+ )
+ return user
\ No newline at end of file
diff --git a/src/server/BreCal/validators/__init__.py b/src/server/BreCal/validators/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/src/server/BreCal/validators/input_validation.py b/src/server/BreCal/validators/input_validation.py
new file mode 100644
index 0000000..188e5e4
--- /dev/null
+++ b/src/server/BreCal/validators/input_validation.py
@@ -0,0 +1,165 @@
+
+####################################### InputValidation #######################################
+
+from abc import ABC, abstractmethod
+from BreCal.schemas.model import Ship, Shipcall, Berth, User, Participant
+
+class InputValidation():
+ def __init__(self):
+ self.build_supported_models_dictionary()
+ return
+
+ def build_supported_models_dictionary(self):
+ self.supported_models = {
+ Ship:ShipValidation(),
+ Shipcall:ShipcallValidation(),
+ Berth:BerthValidation(),
+ User:UserValidation(),
+ Participant:ParticipantValidation(),
+ }
+ return
+
+ def assert_if_not_supported(self, dataclass_object):
+ assert type(dataclass_object) in self.supported_models, f"unsupported model. Found: {type(dataclass_object)}"
+ return
+
+ def verify(self, dataclass_object):
+ self.assert_if_not_supported(dataclass_object)
+
+ # determine the type of the dataclass object. The internal dictionary 'supported_models' matches the dataclass object
+ # to the respective validation protocol
+ validator = self.supported_models.get(type(dataclass_object))
+
+ # check the object based on the rules within the matched validator
+ input_validation_state = validator.check(dataclass_object)
+ return input_validation_state
+
+
+class DataclassValidation(ABC):
+ """parent class of dataclas validators, which determines the outline of every object"""
+ def __init__(self):
+ return
+
+ def check(self, dataclass_object) -> (list, bool):
+ """
+ the 'check' method provides a default style, how each dataclass object is validated. It returns a list of violations
+ and a boolean, which determines, whether the check is passed successfully
+ """
+ all_rules = self.apply_all_rules(dataclass_object)
+ violations = self.filter_violations(all_rules)
+ input_validation_state = self.evaluate(violations)
+ return (violations, input_validation_state)
+
+ @abstractmethod
+ def apply_all_rules(self, dataclass_object) -> list:
+ """
+ the 'apply_all_rules' method is mandatory for any dataclass validation object. It should execute all validation rules and
+ return a list of tuples, where each element is (output_boolean, validation_name)
+ """
+ all_rules = [(True, 'blank_validation_rule')]
+ return all_rules
+
+ def filter_violations(self, all_rules):
+ """input: all_rules, a list of tuples, where each element is (output, validation_name), which are (bool, str). """
+ # if output is False, a violation is observed
+ violations = [result[1] for result in all_rules if not result[0]]
+ return violations
+
+ def evaluate(self, violations) -> bool:
+ input_validation_state = len(violations)==0
+ return input_validation_state
+
+
+
+class ShipcallValidation(DataclassValidation):
+ """an object that validates a Shipcall dataclass object"""
+ def __init__(self):
+ super().__init__()
+ return
+
+ def apply_all_rules(self, dataclass_object) -> list:
+ """apply all input validation rules to determine, whether there are violations. returns a list of tuples (output, validation_name)"""
+ raise NotImplementedError()
+ return all_rules
+
+
+from BreCal.validators.schema_validation import ship_bollard_pull_is_defined_or_is_not_tug, ship_bollard_pull_is_none_or_in_range, ship_callsign_len_is_seven_at_maximum, ship_eni_len_is_eight, ship_imo_len_is_seven, ship_length_in_range, ship_participant_id_is_defined_or_is_not_tug, ship_participant_id_is_none_or_int, ship_width_in_range
+# skip: ship_max_draft_is_defined_or_is_not_tug, ship_max_draft_is_none_or_in_range,
+class ShipValidation(DataclassValidation):
+ """an object that validates a Ship dataclass object"""
+ def __init__(self):
+ super().__init__()
+ return
+
+ def apply_all_rules(self, dataclass_object) -> list:
+ """apply all input validation rules to determine, whether there are violations. returns a list of tuples (output, validation_name)"""
+ # skip: ship_max_draft_is_defined_or_is_not_tug, ship_max_draft_is_none_or_in_range,
+ """
+ #TODO_ship_max_draft
+ with pytest.raises(AttributeError, match="'Ship' object has no attribute 'max_draft'"):
+ assert ship_max_draft_in_range(ship)[0], f"max draft of a ship must be between 0 and 20 meters"
+ assert ship_max_draft_is_none_or_in_range(ship)[0], f"the max_draft should either be undefined or between 0 and 20 meters"
+ """
+
+ # list comprehension: every function becomes part of the loop and will be executed. Each function is wrapped and provides (output, validation_name)
+ all_rules = [
+ # tuple: (output, validation_name)
+ check_rule(dataclass_object)
+
+ for check_rule in [
+ ship_bollard_pull_is_defined_or_is_not_tug,
+ ship_bollard_pull_is_none_or_in_range,
+ ship_callsign_len_is_seven_at_maximum,
+ ship_eni_len_is_eight,
+ ship_imo_len_is_seven,
+ ship_length_in_range,
+ ship_participant_id_is_defined_or_is_not_tug,
+ ship_participant_id_is_none_or_int,
+ ship_width_in_range
+ ]
+ ]
+ return all_rules
+
+class BerthValidation(DataclassValidation):
+ """an object that validates a Berth dataclass object"""
+ def __init__(self):
+ super().__init__()
+ return
+
+ def apply_all_rules(self, dataclass_object) -> list:
+ """apply all input validation rules to determine, whether there are violations. returns a list of tuples (output, validation_name)"""
+ raise NotImplementedError()
+ return all_rules
+
+class UserValidation(DataclassValidation):
+ """an object that validates a User dataclass object"""
+ def __init__(self):
+ super().__init__()
+ return
+
+ def apply_all_rules(self, dataclass_object) -> list:
+ """apply all input validation rules to determine, whether there are violations. returns a list of tuples (output, validation_name)"""
+ raise NotImplementedError()
+ return all_rules
+
+from BreCal.validators.schema_validation import participant_postal_code_len_is_five
+class ParticipantValidation(DataclassValidation):
+ """an object that validates a Participant dataclass object"""
+ def __init__(self):
+ super().__init__()
+ return
+
+ def apply_all_rules(self, dataclass_object) -> list:
+ """apply all input validation rules to determine, whether there are violations. returns a list of tuples (output, validation_name)"""
+
+ # list comprehension: every function becomes part of the loop and will be executed. Each function is wrapped and provides (output, validation_name)
+ all_rules = [
+ # tuple: (output, validation_name)
+ check_rule(dataclass_object)
+
+ for check_rule in [
+ participant_postal_code_len_is_five,
+ ]
+ ]
+ return all_rules
+
diff --git a/src/server/BreCal/validators/schema_validation.py b/src/server/BreCal/validators/schema_validation.py
new file mode 100644
index 0000000..384b2f6
--- /dev/null
+++ b/src/server/BreCal/validators/schema_validation.py
@@ -0,0 +1,139 @@
+# wrapper: every validation function returns a tuple of (validation_state, validation_name)
+# example: validate_ship_eni_length might return the tuple (True, 'ship_eni_length')
+# thereby, one could always know, which test causes an issue
+
+####################################### general functions #######################################
+
+def validation_state_and_validation_name(validation_name):
+ """
+ can wrap arbitrary functions, so they return (output, validation_name)-tuples
+ usage example:
+ @validation_state_and_validation_name("ship_eni_length")
+ def validate_ship_eni_length(ship):
+ return length_matches_exactly(ship.eni,8)
+ """
+ def wrapper(validation_fct):
+ def decorated_fct(*args, **kwargs):
+ return (validation_fct(*args, **kwargs), validation_name)
+ return decorated_fct
+ return wrapper
+
+def value_in_range(query_value, start_range, end_range):
+ """determines, whether the query_value is greater than start_range, but smaller than end_range. Returns bool"""
+ return start_range src_time)
+ if the tgt_time is in the past, it is a negative value (tgt_time < src_time)
+
+ returns the delta between tgt_time and src_time as a float of minutes (or the optionally provided unit)
+
+ options:
+ unit: str, which defaults to 'm' (minutes). 'h' (hours) or 's' (seconds) are also common units. Determines the unit of the output time delta
+ """
+ # convert np.datetime64
+ if isinstance(src_time, pd.Timestamp):
+ src_time = src_time.to_datetime64()
+
+ if isinstance(tgt_time, pd.Timestamp):
+ tgt_time = tgt_time.to_datetime64()
+
+ if isinstance(src_time, datetime.datetime):
+ src_time = np.datetime64(src_time)
+
+ if isinstance(tgt_time, datetime.datetime):
+ tgt_time = np.datetime64(tgt_time)
+
+ delta = tgt_time - src_time
+ minute_delta = delta / np.timedelta64(1, unit)
+ return minute_delta
+
+ def time_delta_from_now_to_tgt(self, tgt_time, unit="m"):
+ return self.time_delta(datetime.datetime.now(), tgt_time=tgt_time, unit=unit)
+
+ def time_inbetween(self, query_time:datetime.datetime, start_time:datetime.datetime, end_time:datetime.datetime) -> bool:
+ """
+ checks, whether the query time is inbetween the start & end time. Returns a bool to indicate that.
+
+ Example:
+ a = datetime.datetime(2017, 5, 16, 8, 21, 10)
+ b = datetime.datetime(2017, 5, 17, 8, 21, 10)
+ c = datetime.datetime(2017, 5, 18, 8, 21, 10)
+
+ is b between a and c? -> yes. Returns True
+ is c between a and b? -> no. Returns False
+
+ returns bool
+ """
+ assert isinstance(query_time, datetime.datetime)
+ assert isinstance(start_time, datetime.datetime)
+ assert isinstance(end_time, datetime.datetime)
+
+ return start_time <= query_time <= end_time
+
+ def time_inbetween_absolute_delta(self, query_time:datetime.datetime, start_time:datetime.datetime, end_time:datetime.datetime) -> tuple:
+ """
+ similarly to self.time_inbetween, this function compares a query_time with the provided start and end time.
+ however, this function instead returns timedelta objects, which show the difference towards start and end
+
+ this function applies abs() to return only absolute deviations. Thereby, -23 becomes +23
+
+ returns: tuple(absolute_start_delta, absolute_end_delta)
+ """
+ return (abs(query_time-start_time), abs(query_time-end_time))
+
+ def compare_query_is_inbetween_list(self, query_time, list_of_other_times) -> list:
+ list_of_bools = [
+ self.time_inbetween(query_time, time_elem_begin, time_elem_end)
+ for (time_elem_begin, time_elem_end) in list_of_other_times
+ ]
+ return list_of_bools
+
+ def query_time_any_inbetween(self, query_time, list_of_other_times):
+ """
+ given a query_time element, the element will be compared to every element in a list, where each
+ element is a tuple of (start_time, end_time)
+ """
+ if len(list_of_other_times)==0:
+ # the time is not inbetween, if the provided list is empty
+ return False
+
+ list_of_bools = self.compare_query_is_inbetween_list(query_time, list_of_other_times)
+ return np.any(list_of_bools), list_of_bools
+
+
diff --git a/src/server/BreCal/validators/validation_rule_functions.py b/src/server/BreCal/validators/validation_rule_functions.py
new file mode 100644
index 0000000..81f53f3
--- /dev/null
+++ b/src/server/BreCal/validators/validation_rule_functions.py
@@ -0,0 +1,769 @@
+import inspect
+import types
+from BreCal.database.enums import ParticipantType, ShipcallType, ParticipantwiseTimeDelta
+import numpy as np
+import pandas as pd
+from BreCal.validators.time_logic import TimeLogic
+from BreCal.database.enums import StatusFlags
+#from BreCal.validators.schema_validation import validation_state_and_validation_name
+
+
+class ValidationRuleBaseFunctions():
+ """
+ Base object with individual functions, which the {ValidationRuleFunctions}-child refers to.
+ This parent class provides base functions and helps to restructure the code in a more comprehensible way.
+ """
+ def __init__(self, sql_handler):
+ self.sql_handler = sql_handler
+ self.time_logic = TimeLogic()
+
+ def check_time_delta_violation_query_time_to_now(self, query_time:pd.Timestamp, key_time:pd.Timestamp, threshold:float)->bool:
+ """
+ # base function for all validation rules in the group {0001} A-L
+
+ 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
+
+ returns a violation state depending on whether the delta is
+ Violation, if: 0 >= delta > threshold
+
+ When the key time is defined (not None), there is no violation. Returns False
+
+ options:
+ query_time: will be used to measure the time difference of 'now' until the query time
+ key_time: will be used to check, whether the respective key already has a value
+ threshold: threshold where a time difference becomes crucial. When the delta is below the threshold, a violation might occur
+ """
+ # rule is not applicable -> return 'GREEN'
+ if key_time is not None:
+ 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")
+
+ # a violation occurs, when the delta (in minutes) exceeds the specified threshold of a participant
+ # to prevent past-events from triggering violations, negative values are ignored
+ # Violation, if 0 >= delta >= threshold
+ violation_state = (delta >= 0) and (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
+
+ compares, whether the participants agree on the estimated time (of arrival or departure), depending on
+ whether the shipcall type is incoming, outgoing or shifting.
+
+ 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).
+
+ returns: violation_state (bool)
+ """
+ # shipcall type filter: consider only shipcalls, where the type matches
+ if shipcall.type != applicable_shipcall_type.value:
+ violation_state = False
+ return violation_state
+
+ # filter by participant types of interest (agency, mooring, portauthority/administration, pilot, tug)
+ participant_types = [ParticipantType.AGENCY.value, ParticipantType.MOORING.value, ParticipantType.PORT_ADMINISTRATION.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 = [type(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
+
+ # 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
+ return violation_state
+
+ def check_unique_shipcall_counts(self, query:str, rounding="min", maximum_threshold=3)->bool:
+ """
+ # base function for all validation rules in the group {0005} A&B
+
+ compares how many unique times are found for the provided {query} (e.g., "eta_berth")
+ This function rounds the results, counts the unique values and returns a boolean state, whether the {maximum_threshold} is exceeded
+ """
+ # filter the df: keep only times_agents
+ # filter out all NaN and NaT entries
+ times_agency = self.sql_handler.get_times_for_agency(non_null_column=query)
+
+ # get values and optionally round the values
+ (values, unique, counts) = self.sql_handler.get_unique_ship_counts(all_df_times=times_agency, query=query, rounding=rounding, maximum_threshold=maximum_threshold)
+
+ # when ANY of the unique values exceeds the threshold, a violation is observed
+ violation_state = np.any(np.greater(counts, maximum_threshold))
+ return violation_state
+
+
+class ValidationRuleFunctions(ValidationRuleBaseFunctions):
+ """
+ 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.
+
+ # example:
+ #def validation_rule_fct_example(self, shipcall, df_times):
+ #validation_name = inspect.currentframe().f_code.co_name
+ #return (ValidationRuleState.NONE, validation_name)
+ """
+ def __init__(self, sql_handler):
+ super().__init__(sql_handler)
+ 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
+ Type: Local Rule
+ Description: this validation checks, whether there is a missing time. When the difference between an event (e.g., the shipcall eta) is below
+ a certain threshold (e.g., 20 hours), a violation occurs
+
+ 0001-A:
+ - Checks, if times_agency.eta_berth is filled in.
+ - Measures the difference between 'now' and 'shipcall.eta'.
+ """
+ # check, if the header is filled in (agency)
+ if len(df_times.loc[df_times["participant_type"].isin([ParticipantType.AGENCY.value])]) != 1:
+ return (StatusFlags.GREEN, None)
+
+ # 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
+ key_time = times_agency.eta_berth
+ threshold = ParticipantwiseTimeDelta.AGENCY
+ 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 = inspect.currentframe().f_code.co_name
+ return (StatusFlags.YELLOW, validation_name)
+ else:
+ return (StatusFlags.GREEN, None)
+
+ def validation_rule_fct_missing_time_agency_berth_etd(self, shipcall, df_times, *args, **kwargs):
+ """
+ Code: #0001-B
+ Type: Local Rule
+ Description: this validation checks, whether there is a missing time. When the difference between an event (e.g., the shipcall eta) is below
+ a certain threshold (e.g., 20 hours), a violation occurs
+
+ 0001-B:
+ - Checks, if times_agency.etd_berth is filled in.
+ - Measures the difference between 'now' and 'shipcall.etd'.
+ """
+ # check, if the header is filled in (agency)
+ if len(df_times.loc[df_times["participant_type"].isin([ParticipantType.AGENCY.value])]) != 1:
+ return (StatusFlags.GREEN, None)
+
+ # 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
+ key_time = times_agency.etd_berth
+ threshold = ParticipantwiseTimeDelta.AGENCY
+ 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 = inspect.currentframe().f_code.co_name
+ return (StatusFlags.YELLOW, validation_name)
+ else:
+ return (StatusFlags.GREEN, None)
+
+ def validation_rule_fct_missing_time_mooring_berth_eta(self, shipcall, df_times, *args, **kwargs):
+ """
+ Code: #0001-C
+ Type: Local Rule
+ Description: this validation checks, whether there is a missing time. When the difference between an event (e.g., the shipcall eta) is below
+ a certain threshold (e.g., 20 hours), a violation occurs
+
+ 0001-C:
+ - Checks, if times_mooring.eta_berth is filled in.
+ - Measures the difference between 'now' and 'times_agency.eta_berth'.
+ """
+ # check, if the header is filled in (agency & MOORING)
+ if len(df_times.loc[df_times["participant_type"].isin([ParticipantType.AGENCY.value, ParticipantType.MOORING.value])]) != 2:
+ return (StatusFlags.GREEN, None)
+
+ # 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_mooring = self.sql_handler.get_times_for_participant_type(df_times, participant_type=ParticipantType.MOORING.value)
+
+ query_time = times_agency.eta_berth
+ key_time = times_mooring.eta_berth
+ threshold = ParticipantwiseTimeDelta.MOORING
+ 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 = inspect.currentframe().f_code.co_name
+ return (StatusFlags.YELLOW, validation_name)
+ else:
+ return (StatusFlags.GREEN, None)
+
+ def validation_rule_fct_missing_time_mooring_berth_etd(self, shipcall, df_times, *args, **kwargs):
+ """
+ Code: #0001-D
+ Type: Local Rule
+ Description: this validation checks, whether there is a missing time. When the difference between an event (e.g., the shipcall eta) is below
+ a certain threshold (e.g., 20 hours), a violation occurs
+
+ 0001-D:
+ - Checks, if times_mooring.etd_berth is filled in.
+ - Measures the difference between 'now' and 'times_agency.etd_berth'.
+ """
+ # check, if the header is filled in (agency & MOORING)
+ if len(df_times.loc[df_times["participant_type"].isin([ParticipantType.AGENCY.value, ParticipantType.MOORING.value])]) != 2:
+ return (StatusFlags.GREEN, None)
+
+ # 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_mooring = self.sql_handler.get_times_for_participant_type(df_times, participant_type=ParticipantType.MOORING.value)
+
+ query_time = times_agency.etd_berth
+ key_time = times_mooring.etd_berth
+ threshold = ParticipantwiseTimeDelta.MOORING
+ 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 = inspect.currentframe().f_code.co_name
+ return (StatusFlags.YELLOW, validation_name)
+ else:
+ return (StatusFlags.GREEN, None)
+
+ def validation_rule_fct_missing_time_portadministration_berth_eta(self, shipcall, df_times, *args, **kwargs):
+ """
+ Code: #0001-F
+ Type: Local Rule
+ Description: this validation checks, whether there is a missing time. When the difference between an event (e.g., the shipcall eta) is below
+ a certain threshold (e.g., 20 hours), a violation occurs
+
+ 0001-F:
+ - Checks, if times_port_administration.eta_berth is filled in.
+ - Measures the difference between 'now' and 'times_agency.eta_berth'.
+ """
+ # check, if the header is filled in (agency & PORT_ADMINISTRATION)
+ if len(df_times.loc[df_times["participant_type"].isin([ParticipantType.AGENCY.value, ParticipantType.PORT_ADMINISTRATION.value])]) != 2:
+ return (StatusFlags.GREEN, None)
+
+ # 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)
+
+ query_time = times_agency.eta_berth
+ key_time = times_port_administration.eta_berth
+ threshold = ParticipantwiseTimeDelta.PORT_ADMINISTRATION
+ 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 = inspect.currentframe().f_code.co_name
+ return (StatusFlags.YELLOW, validation_name)
+ else:
+ return (StatusFlags.GREEN, None)
+
+ def validation_rule_fct_missing_time_portadministration_berth_etd(self, shipcall, df_times, *args, **kwargs):
+ """
+ Code: #0001-G
+ Type: Local Rule
+ Description: this validation checks, whether there is a missing time. When the difference between an event (e.g., the shipcall eta) is below
+ a certain threshold (e.g., 20 hours), a violation occurs
+
+ 0001-G:
+ - Checks, if times_port_administration.etd_berth is filled in.
+ - Measures the difference between 'now' and 'times_agency.etd_berth'.
+ """
+ # check, if the header is filled in (agency & PORT_ADMINISTRATION)
+ if len(df_times.loc[df_times["participant_type"].isin([ParticipantType.AGENCY.value, ParticipantType.PORT_ADMINISTRATION.value])]) != 2:
+ return (StatusFlags.GREEN, None)
+
+ # 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)
+
+ query_time = times_agency.etd_berth
+ key_time = times_port_administration.etd_berth
+ threshold = ParticipantwiseTimeDelta.PORT_ADMINISTRATION
+ 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 = inspect.currentframe().f_code.co_name
+ return (StatusFlags.YELLOW, validation_name)
+ else:
+ return (StatusFlags.GREEN, None)
+
+ def validation_rule_fct_missing_time_pilot_berth_eta(self, shipcall, df_times, *args, **kwargs):
+ """
+ Code: #0001-H
+ Type: Local Rule
+ Description: this validation checks, whether there is a missing time. When the difference between an event (e.g., the shipcall eta) is below
+ a certain threshold (e.g., 20 hours), a violation occurs
+
+ 0001-H:
+ - Checks, if times_pilot.eta_berth is filled in.
+ - Measures the difference between 'now' and 'times_agency.eta_berth'.
+ """
+ # check, if the header is filled in (agency & PILOT)
+ if len(df_times.loc[df_times["participant_type"].isin([ParticipantType.AGENCY.value, ParticipantType.PILOT.value])]) != 2:
+ return (StatusFlags.GREEN, None)
+
+ # 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)
+
+ query_time = times_agency.eta_berth
+ key_time = times_pilot.eta_berth
+ 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 = inspect.currentframe().f_code.co_name
+ return (StatusFlags.YELLOW, validation_name)
+ else:
+ return (StatusFlags.GREEN, None)
+
+ def validation_rule_fct_missing_time_pilot_berth_etd(self, shipcall, df_times, *args, **kwargs):
+ """
+ Code: #0001-I
+ Type: Local Rule
+ Description: this validation checks, whether there is a missing time. When the difference between an event (e.g., the shipcall eta) is below
+ a certain threshold (e.g., 20 hours), a violation occurs
+
+ 0001-I:
+ - Checks, if times_pilot.etd_berth is filled in.
+ - Measures the difference between 'now' and 'times_agency.etd_berth'.
+ """
+ # check, if the header is filled in (agency & PILOT)
+ if len(df_times.loc[df_times["participant_type"].isin([ParticipantType.AGENCY.value, ParticipantType.PILOT.value])]) != 2:
+ return (StatusFlags.GREEN, None)
+
+ # 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)
+
+ query_time = times_agency.etd_berth
+ key_time = times_pilot.etd_berth
+ 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 = inspect.currentframe().f_code.co_name
+ return (StatusFlags.YELLOW, validation_name)
+ else:
+ return (StatusFlags.GREEN, None)
+
+ def validation_rule_fct_missing_time_tug_berth_eta(self, shipcall, df_times, *args, **kwargs):
+ """
+ Code: #0001-J
+ Type: Local Rule
+ Description: this validation checks, whether there is a missing time. When the difference between an event (e.g., the shipcall eta) is below
+ a certain threshold (e.g., 20 hours), a violation occurs
+
+ 0001-J:
+ - Checks, if times_tug.eta_berth is filled in.
+ - Measures the difference between 'now' and 'times_agency.eta_berth'.
+ """
+ # check, if the header is filled in (agency & TUG)
+ if len(df_times.loc[df_times["participant_type"].isin([ParticipantType.AGENCY.value, ParticipantType.TUG.value])]) != 2:
+ return (StatusFlags.GREEN, None)
+
+ # 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)
+
+ query_time = times_agency.eta_berth
+ key_time = times_tug.eta_berth
+ 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 = inspect.currentframe().f_code.co_name
+ return (StatusFlags.YELLOW, validation_name)
+ else:
+ return (StatusFlags.GREEN, None)
+
+ def validation_rule_fct_missing_time_tug_berth_etd(self, shipcall, df_times, *args, **kwargs):
+ """
+ Code: #0001-K
+ Type: Local Rule
+ Description: this validation checks, whether there is a missing time. When the difference between an event (e.g., the shipcall eta) is below
+ a certain threshold (e.g., 20 hours), a violation occurs
+
+ 0001-K:
+ - Checks, if times_tug.etd_berth is filled in.
+ - Measures the difference between 'now' and 'times_agency.etd_berth'.
+ """
+ # check, if the header is filled in (agency & TUG)
+ if len(df_times.loc[df_times["participant_type"].isin([ParticipantType.AGENCY.value, ParticipantType.TUG.value])]) != 2:
+ return (StatusFlags.GREEN, None)
+
+ # 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)
+
+ query_time = times_agency.etd_berth
+ key_time = times_tug.etd_berth
+ 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 = inspect.currentframe().f_code.co_name
+ return (StatusFlags.YELLOW, validation_name)
+ else:
+ return (StatusFlags.GREEN, None)
+
+ def validation_rule_fct_missing_time_terminal_berth_eta(self, shipcall, df_times, *args, **kwargs):
+ """
+ Code: #0001-L
+ Type: Local Rule
+ Description: this validation checks, whether there is a missing time. When the difference between an event (e.g., the shipcall eta) is below
+ a certain threshold (e.g., 20 hours), a violation occurs
+
+ 0001-L:
+ - Checks, if times_terminal.eta_berth is filled in.
+ - Measures the difference between 'now' and 'times_agency.eta_berth'.
+ """
+ # check, if the header is filled in (agency & terminal)
+ if len(df_times.loc[df_times["participant_type"].isin([ParticipantType.AGENCY.value, ParticipantType.TERMINAL.value])]) != 2:
+ return (StatusFlags.GREEN, None)
+
+ # 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)
+
+ query_time = times_agency.eta_berth
+ key_time = times_terminal.eta_berth
+ 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 = inspect.currentframe().f_code.co_name
+ return (StatusFlags.YELLOW, validation_name)
+ else:
+ return (StatusFlags.GREEN, None)
+
+ def validation_rule_fct_missing_time_terminal_berth_etd(self, shipcall, df_times, *args, **kwargs):
+ """
+ Code: #0001-K
+ Type: Local Rule
+ Description: this validation checks, whether there is a missing time. When the difference between an event (e.g., the shipcall eta) is below
+ a certain threshold (e.g., 20 hours), a violation occurs
+
+ 0001-K:
+ - Checks, if times_terminal.etd_berth is filled in.
+ - Measures the difference between 'now' and 'times_agency.etd_berth'.
+ """
+ # check, if the header is filled in (agency & terminal)
+ if len(df_times.loc[df_times["participant_type"].isin([ParticipantType.AGENCY.value, ParticipantType.TERMINAL.value])]) != 2:
+ return (StatusFlags.GREEN, None)
+
+ # 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)
+
+ query_time = times_agency.etd_berth
+ key_time = times_terminal.etd_berth
+ 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 = inspect.currentframe().f_code.co_name
+ return (StatusFlags.YELLOW, validation_name)
+ else:
+ return (StatusFlags.GREEN, None)
+
+
+ def validation_rule_fct_shipcall_incoming_participants_disagree_on_eta(self, shipcall, df_times, *args, **kwargs):
+ """
+ Code: #0002-A
+ Type: Local Rule
+ Description: this validation checks, whether the participants expect different ETA times
+ 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,
+ applicable_shipcall_type=ShipcallType.INCOMING
+ )
+
+ if violation_state:
+ validation_name = inspect.currentframe().f_code.co_name
+ return (StatusFlags.RED, validation_name)
+ else:
+ return (StatusFlags.GREEN, None)
+
+ def validation_rule_fct_shipcall_outgoing_participants_disagree_on_etd(self, shipcall, df_times, *args, **kwargs):
+ """
+ Code: #0002-B
+ Type: Local Rule
+ Description: this validation checks, whether the participants expect different ETA times
+ 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,
+ applicable_shipcall_type=ShipcallType.OUTGOING
+ )
+
+ if violation_state:
+ validation_name = inspect.currentframe().f_code.co_name
+ return (StatusFlags.RED, validation_name)
+ else:
+ return (StatusFlags.GREEN, None)
+
+ def validation_rule_fct_shipcall_shifting_participants_disagree_on_eta_or_etd(self, shipcall, df_times, *args, **kwargs):
+ """
+ Code: #0002-C
+ Type: Local Rule
+ Description: this validation checks, whether the participants expect different ETA or ETD times
+ Filter: only applies to shifting shipcalls
+ """
+ violation_state_eta = self.check_participants_agree_on_estimated_time(
+ shipcall = shipcall,
+
+ query="eta_berth",
+ df_times=df_times,
+ applicable_shipcall_type=ShipcallType.SHIFTING
+ )
+
+ violation_state_etd = self.check_participants_agree_on_estimated_time(
+ shipcall = shipcall,
+
+ 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
+ # functionally, this is the same as individually comparing all times for the participants
+ # times_agency.eta_berth==times_mooring.eta_berth==times_portadministration.eta_berth==times_pilot.eta_berth==times_tug.eta_berth
+ # times_agency.etd_berth==times_mooring.etd_berth==times_portadministration.etd_berth==times_pilot.etd_berth==times_tug.etd_berth
+ violation_state = (violation_state_eta) or (violation_state_etd)
+
+ if violation_state:
+ validation_name = inspect.currentframe().f_code.co_name
+ return (StatusFlags.RED, validation_name)
+ else:
+ return (StatusFlags.GREEN, None)
+
+ def validation_rule_fct_eta_time_not_in_operation_window(self, shipcall, df_times, *args, **kwargs):
+ """
+ Code: #0003-A
+ Type: Local Rule
+ Description: this validation checks, whether the ETA time is between the provided operations window of the terminal
+
+ query time: eta_berth (times_agency)
+ start_time & end_time: operations_start & operations_end (times_terminal)
+ """
+ # check, if the header is filled in (agency & terminal)
+ if len(df_times.loc[df_times["participant_type"].isin([ParticipantType.AGENCY.value, ParticipantType.TERMINAL.value])]) != 2:
+ return (StatusFlags.GREEN, None)
+
+ # 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)
+
+ if (times_terminal.operations_end is pd.NaT) or (times_agency.etd_berth is pd.NaT):
+ return (StatusFlags.GREEN, None)
+
+ # check, whether the start of operations is AFTER the estimated arrival time
+ violation_state = times_terminal.operations_start times_agency.etd_berth
+
+ if violation_state:
+ validation_name = inspect.currentframe().f_code.co_name
+ return (StatusFlags.RED, validation_name)
+ else:
+ return (StatusFlags.GREEN, None)
+
+ def validation_rule_fct_eta_time_not_in_tidal_window(self, shipcall, df_times, *args, **kwargs):
+ """
+ Code: #0004-A
+ Type: Local Rule
+ Description: this validation checks, whether the ETA time is between the provided tidal window
+
+ query time: eta_berth (times_agency)
+ start_time & end_time: tidal_window_from & tidal_window_to (shipcall)
+ """
+ # check, if the header is filled in (agency)
+ if len(df_times.loc[df_times["participant_type"].isin([ParticipantType.AGENCY.value])]) != 1:
+ return (StatusFlags.GREEN, None)
+ times_agency = self.sql_handler.get_times_for_participant_type(df_times, participant_type=ParticipantType.AGENCY.value)
+
+ # requirements: tidal window (from & to) is filled in
+ if (shipcall.tidal_window_from is pd.NaT) or (shipcall.tidal_window_to is pd.NaT) or (df_times.eta_berth is pd.NaT):
+ return (StatusFlags.GREEN, None)
+
+ # check, whether the query time is between start & end time
+ # a violation is observed, when the is NOT between start & end
+ violation_state = not self.time_logic.time_inbetween(query_time=times_agency.eta_berth, start_time=shipcall.tidal_window_from, end_time=shipcall.tidal_window_to)
+
+ if violation_state:
+ validation_name = inspect.currentframe().f_code.co_name
+ return (StatusFlags.RED, validation_name)
+ else:
+ return (StatusFlags.GREEN, None)
+
+ def validation_rule_fct_etd_time_not_in_tidal_window(self, shipcall, df_times, *args, **kwargs):
+ """
+ Code: #0004-B
+ Type: Local Rule
+ Description: this validation checks, whether the ETD time is between the provided tidal window
+
+ query time: eta_berth (times_agency)
+ start_time & end_time: tidal_window_from & tidal_window_to (shipcall)
+ """
+ # check, if the header is filled in (agency)
+ if len(df_times.loc[df_times["participant_type"].isin([ParticipantType.AGENCY.value])]) != 1:
+ return (StatusFlags.GREEN, None)
+ times_agency = self.sql_handler.get_times_for_participant_type(df_times, participant_type=ParticipantType.AGENCY.value)
+
+ # requirements: tidal window (from & to) is filled in
+ if (shipcall.tidal_window_from is pd.NaT) or (shipcall.tidal_window_to is pd.NaT) or (df_times.etd_berth is pd.NaT):
+ return (StatusFlags.GREEN, None)
+
+ # check, whether the query time is between start & end time
+ # a violation is observed, when the is NOT between start & end
+ violation_state = not self.time_logic.time_inbetween(query_time=times_agency.etd_berth, start_time=shipcall.tidal_window_from, end_time=shipcall.tidal_window_to)
+
+ if violation_state:
+ validation_name = inspect.currentframe().f_code.co_name
+ return (StatusFlags.RED, validation_name)
+ else:
+ return (StatusFlags.GREEN, None)
+
+ def validation_rule_fct_too_many_identical_eta_times(self, shipcall, df_times, rounding = "min", maximum_threshold = 3, *args, **kwargs):
+ """
+ Code: #0005-A
+ Type: Global Rule
+ Description: this validation rule checks, whether there are too many shipcalls with identical ETA times.
+ """
+ # when ANY of the unique values exceeds the threshold, a violation is observed
+ query = "eta_berth"
+ violation_state = self.check_unique_shipcall_counts(query, rounding=rounding, maximum_threshold=maximum_threshold)
+
+ if violation_state:
+ validation_name = inspect.currentframe().f_code.co_name
+ return (StatusFlags.YELLOW, validation_name)
+ else:
+ return (StatusFlags.GREEN, None)
+
+ def validation_rule_fct_too_many_identical_etd_times(self, shipcall, df_times, rounding = "min", maximum_threshold = 3, *args, **kwargs):
+ """
+ Code: #0005-B
+ Type: Global Rule
+ Description: this validation rule checks, whether there are too many shipcalls with identical ETD times.
+ """
+ # when ANY of the unique values exceeds the threshold, a violation is observed
+ query = "etd_berth"
+ violation_state = self.check_unique_shipcall_counts(query, rounding=rounding, maximum_threshold=maximum_threshold)
+
+ if violation_state:
+ validation_name = inspect.currentframe().f_code.co_name
+ return (StatusFlags.YELLOW, validation_name)
+ else:
+ return (StatusFlags.GREEN, None)
+
+ def validation_rule_fct_agency_and_terminal_berth_id_disagreement(self, shipcall, df_times, *args, **kwargs):
+ """
+ Code: #0006-A
+ Type: Local Rule
+ Description: This validation rule checks, whether agency and terminal agree with their designated berth place by checking berth_id.
+ """
+ # check, if the header is filled in (agency & terminal)
+ if len(df_times.loc[df_times["participant_type"].isin([ParticipantType.AGENCY.value, ParticipantType.TERMINAL.value])]) != 2:
+ return (StatusFlags.GREEN, None)
+
+ 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)
+
+ violation_state = times_agency.berth_id!=times_terminal.berth_id
+
+ if violation_state:
+ validation_name = inspect.currentframe().f_code.co_name
+ return (StatusFlags.YELLOW, validation_name)
+ else:
+ return (StatusFlags.GREEN, None)
+
+ def validation_rule_fct_agency_and_terminal_pier_side_disagreement(self, shipcall, df_times, *args, **kwargs):
+ """
+ Code: #0006-B
+ Type: Local Rule
+ Description: This validation rule checks, whether agency and terminal agree with their designated pier side by checking pier_side.
+ """
+ # check, if the header is filled in (agency & terminal)
+ if len(df_times.loc[df_times["participant_type"].isin([ParticipantType.AGENCY.value, ParticipantType.TERMINAL.value])]) != 2:
+ return (StatusFlags.GREEN, None)
+
+ 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)
+
+ violation_state = times_agency.pier_side!=times_terminal.pier_side
+
+ if violation_state:
+ validation_name = inspect.currentframe().f_code.co_name
+ return (StatusFlags.YELLOW, validation_name)
+ else:
+ return (StatusFlags.GREEN, None)
+
+
diff --git a/src/server/BreCal/validators/validation_rules.py b/src/server/BreCal/validators/validation_rules.py
new file mode 100644
index 0000000..7e7fcef
--- /dev/null
+++ b/src/server/BreCal/validators/validation_rules.py
@@ -0,0 +1,128 @@
+import copy
+import numpy as np
+import pandas as pd
+from BreCal.database.enums import StatusFlags
+from BreCal.validators.validation_rule_functions import ValidationRuleFunctions
+from BreCal.schemas.model import Shipcall
+
+
+class ValidationRules(ValidationRuleFunctions):
+ """
+ An object that determines the traffic light state for validation and notification. The provided feedback ('green', 'yellow', 'red')
+ determines, whether the state is critical. It uses ValidationRuleState enumerations.
+ In case of a critical validation state, the user's input prompt may be interrupted and the user may be warned.
+ In case of a critical notification state, the respective users will be automatically notified after n seconds. (#TODO_n_seconds_delay)
+ """
+ def __init__(self, sql_handler): # use the entire data that is provided for this query (e.g., json input)
+ super().__init__(sql_handler)
+
+ self.validation_state = self.determine_validation_state()
+ # currently flagged: notification_state initially was based on using one ValidationRules object for each query. This is deprecated.
+ # self.notification_state = self.determine_notification_state() # (state:str, should_notify:bool)
+ return
+
+ def evaluate(self, shipcall):
+ """
+ 1.) prepare df_times, which every validation rule tends to use
+ calling this only once saves a lot of computational overhead
+ 2.) apply all validation rules
+ returns: (evaluation_state, violations)
+ """
+ # prepare df_times, which every validation rule tends to use
+ df_times = self.sql_handler.df_dict.get('times') # -> pd.DataFrame
+
+ # filter by shipcall id
+ df_times = self.sql_handler.get_times_of_shipcall(shipcall)
+
+ # apply all validation rules
+ # list of tuples, where each element is (state, msg)
+ evaluation_results = [elem(shipcall, df_times) for elem in self.get_validation_rule_functions()]
+
+ # filter out all 'None' results, which indicate that no violation occured.
+ evaluation_results = [evaluation_result for evaluation_result in evaluation_results if evaluation_result[1] is not None]
+
+ """ # deprecated
+ # check, if ANY of the evaluation results (evaluation_state) is larger than the .GREEN state. This means, that .YELLOW and .RED
+ # would return 'True'. Numpy arrays and functions are used to accelerate the comparison.
+ # np.any returns a boolean.
+ #evaluation_state = not np.any(np.greater(np.array([result[0] for result in evaluation_results]), ValidationRuleState.GREEN))
+ """
+ # check, what the maximum state flag is and return it
+ evaluation_state = np.max(np.array([result[0].value for result in evaluation_results])) if len(evaluation_results)>0 else 1
+ evaluation_verbosity = [result[1] for result in evaluation_results]
+ return (evaluation_state, evaluation_verbosity)
+
+ def evaluation_verbosity(self, evaluation_state, evaluation_results):
+ """This function suggestions verbosity for the evaluation results. Based on 'True'/'False' evaluation outcome, the returned string is different."""
+ if evaluation_state:
+ return f"OK! The validation was successful. There are no rule violations."
+ else:
+ verbose_string = "These are:" + "\n\t".join(evaluation_results) # every element of the list will be displayed in a new line with a tab
+ return f"FAILED VALIDATION. There have been {len(evaluation_results)} violations. {verbose_string}"
+
+ def evaluate_shipcall_from_df(self, x):
+ shipcall = Shipcall(**{**{'id':x.name}, **x.to_dict()})
+ evaluation_state, violations = self.evaluate(shipcall)
+ return evaluation_state, violations
+
+ def evaluate_shipcalls(self, shipcall_df:pd.DataFrame)->pd.DataFrame:
+ """apply 'evaluate_shipcall_from_df' to each individual shipcall in {shipcall_df}. Returns shipcall_df ('evaluation' and 'evaluation_message' are updated)"""
+ results = shipcall_df.apply(lambda x: self.evaluate_shipcall_from_df(x), axis=1).values
+
+ # unbundle individual results. evaluation_state becomes an integer, violation
+ evaluation_state = [StatusFlags(res[0]).value for res in results]
+ violations = [",".join(res[1]) if len(res[1])>0 else None for res in results]
+
+ shipcall_df.loc[:,"evaluation"] = evaluation_state
+ shipcall_df.loc[:,"evaluation_message"] = violations
+ return shipcall_df
+
+ def determine_validation_state(self) -> str:
+ """
+ this method determines the validation state of a shipcall. The state is either ['green', 'yellow', 'red'] and signals,
+ whether an entry causes issues within the workflow of users.
+
+ returns: validation_state_new (str)
+ """
+ (validation_state_new, description) = self.undefined_method()
+ # should there also be notifications for critical validation states? In principle, the traffic light itself provides that notification.
+ self.validation_state = validation_state_new
+ return validation_state_new
+
+ def determine_notification_state(self) -> (str, bool):
+ """
+ this method determines state changes in the notification state. When the state is changed to yellow or red,
+ a user is notified about it. The only exception for this rule is when the state was yellow or red before,
+ as the user has then already been notified.
+
+ returns: notification_state_new (str), should_notify (bool)
+ """
+ (state_new, description) = self.undefined_method() # determine the successor
+ should_notify = self.identify_notification_state_change(state_new)
+ self.notification_state = state_new # overwrite the predecessor
+ return state_new, should_notify
+
+ def identify_notification_state_change(self, state_new) -> bool:
+ """
+ determines, whether the observed state change should trigger a notification.
+ internally, this function maps a color string to an integer and determines, if the successor state is more severe than the predecessor.
+
+ state changes trigger a notification in the following cases:
+ green -> yellow
+ green -> red
+ yellow -> red
+
+ (none -> yellow) or (none -> red)
+ due to the values in the enumeration objects, the states are mapped to provide this function.
+ green=1, yellow=2, red=3, none=1. Hence, critical changes can be observed by simply checking with "greater than".
+
+ returns bool, whether a notification should be triggered
+ """
+ # state_old is always considered at least 'Green' (1)
+ state_old = max(copy.copy(self.notification_state) if "notification_state" in list(self.__dict__.keys()) else StatusFlags.NONE, StatusFlags.GREEN.value)
+ return state_new.value > state_old.value
+
+ def undefined_method(self) -> str:
+ """this function should apply the ValidationRules to the respective .shipcall, in regards to .times"""
+ # #TODO_traffic_state
+ return (StatusFlags.GREEN, False) # (state:str, should_notify:bool)
diff --git a/src/server/flaskapp.wsgi b/src/server/flaskapp.wsgi
index 1dc7818..e734f70 100644
--- a/src/server/flaskapp.wsgi
+++ b/src/server/flaskapp.wsgi
@@ -1,8 +1,12 @@
+import os
import sys
import logging
-sys.path.insert(0, '/var/www/brecal/server')
-sys.path.insert(0, '/var/www/brecal/venv/lib/python3.10/site-packages/')
+sys.path.insert(0, '/var/www/brecal_test/src/server')
+sys.path.insert(0, '/var/www/venv/lib/python3.10/site-packages/')
+
+# set the key
+os.environ['SECRET_KEY'] = 'zdiTz8P3jXOc7jztIQAoelK4zztyuCpJ'
# Set up logging
logging.basicConfig(stream=sys.stderr, level=logging.DEBUG)
diff --git a/src/server/requirements.txt b/src/server/requirements.txt
index ca817e1..8b7f3ad 100644
--- a/src/server/requirements.txt
+++ b/src/server/requirements.txt
@@ -3,11 +3,21 @@ Flask==1.1.2
itsdangerous==1.1.0
Jinja2==2.11.2
MarkupSafe==1.1.1
-marshmallow==3.9.1
+marshmallow>=3.9.1
webargs==6.1.1
Werkzeug==1.0.1
pydapper[mysql-connector-python]
marshmallow-dataclass
bcrypt
-jwt
-flask-jwt-extended
\ No newline at end of file
+pyjwt
+flask-jwt-extended
+numpy
+pandas
+tqdm
+schedule
+
+pytest
+pytest-cov
+coverage
+
+../server/.
diff --git a/src/server/tests/__init__.py b/src/server/tests/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/src/server/tests/api/__init__.py b/src/server/tests/api/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/src/server/tests/brecal_utils/__init__.py b/src/server/tests/brecal_utils/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/src/server/tests/brecal_utils/test_test_handling.py b/src/server/tests/brecal_utils/test_test_handling.py
new file mode 100644
index 0000000..9b9e74a
--- /dev/null
+++ b/src/server/tests/brecal_utils/test_test_handling.py
@@ -0,0 +1,52 @@
+import unittest
+import pytest
+
+def test_execute_coverage_test():
+ """
+ executes {execute_coverage_test} to check, whether reporting works as expected
+ """
+ import os
+ import BreCal.brecal_utils
+
+ from BreCal.brecal_utils.file_handling import get_project_root
+ from BreCal.brecal_utils.test_handling import execute_coverage_test
+
+ # find the root folder 'server'
+ root_dir = BreCal.brecal_utils.__file__
+ root_dir = get_project_root("server", root_dir=root_dir)
+
+ # find the test path, the library path and the coverage report path
+ tests_path = os.path.join(root_dir, "tests")
+ coverage_path = os.path.join(root_dir, "BreCal")
+ report_path = os.path.join(root_dir, "coverage_reports")
+
+ with pytest.raises(KeyboardInterrupt, match="is_test_interrupt"):
+ execute_coverage_test(tests_path=tests_path, coverage_path=coverage_path, cov_report_dst_dir=report_path, cov_fail_under_rate=0, is_test=1)
+ return
+
+def test_execute_coverage_test_no_report():
+ """
+ executes {execute_coverage_test} to check, whether the function also works without reporting
+ """
+ import os
+ import BreCal.brecal_utils
+
+ from BreCal.brecal_utils.file_handling import get_project_root
+ from BreCal.brecal_utils.test_handling import execute_coverage_test
+
+ # find the root folder 'server'
+ root_dir = BreCal.brecal_utils.__file__
+ root_dir = get_project_root("server", root_dir=root_dir)
+
+ # find the test path, the library path and the coverage report path
+ tests_path = os.path.join(root_dir, "tests")
+ coverage_path = os.path.join(root_dir, "BreCal")
+ report_path = os.path.join(root_dir, "coverage_reports")
+
+ with pytest.raises(KeyboardInterrupt, match="is_test_interrupt"):
+ execute_coverage_test(tests_path=tests_path, coverage_path=coverage_path, cov_report_dst_dir=None, cov_fail_under_rate=0, is_test=1)
+ return
+
+
+if __name__=="__main__":
+ pass
diff --git a/src/server/tests/brecal_utils/test_time_handling.py b/src/server/tests/brecal_utils/test_time_handling.py
new file mode 100644
index 0000000..b154dc8
--- /dev/null
+++ b/src/server/tests/brecal_utils/test_time_handling.py
@@ -0,0 +1,52 @@
+import pytest
+
+def test_difference_to_then_tgt_time_none():
+ import math
+ import datetime
+ from BreCal import difference_to_then
+
+ difference_in_seconds = 42
+ event_time = datetime.datetime.now() - datetime.timedelta(seconds=difference_in_seconds)
+ event_time_diff = difference_to_then(event_time) # tgt_time = datetime.datetime.now()
+
+ # {difference_to_then} internally creates a .now() time, when the {then_time} is not defined
+ # hence, the difference will never be exactly 42 seconds due to slight latency
+ # math.isclose allows deviations up to 0.05 seconds
+ assert math.isclose(42, event_time_diff, abs_tol=0.05), f"both times are reasonably close"
+ return
+
+def test_difference_to_then_tgt_time_not_none():
+ import math
+ import datetime
+ from BreCal import difference_to_then
+
+ difference_in_seconds = 42
+ event_time = datetime.datetime(2000, 1, 1, 0, 0, 0)
+ tgt_time = event_time - datetime.timedelta(seconds=difference_in_seconds)
+ event_time_diff = difference_to_then(event_time, tgt_time)
+
+ # tgt time is -42 seconds, as it is 42 seconds before event_time
+ assert event_time_diff==-42, f"event time difference is incorrect"
+ return
+
+def test_difference_to_then_tgt_time_not_none_make_absolute():
+ import math
+ import datetime
+ from BreCal import difference_to_then
+
+ difference_in_seconds = 42
+ event_time = datetime.datetime(2000, 1, 1, 0, 0, 0)
+ tgt_time = event_time - datetime.timedelta(seconds=difference_in_seconds)
+ event_time_diff = difference_to_then(event_time, tgt_time, make_absolute=True) # difference: -42. make_absolute: +42
+
+ # tgt time is -42 seconds, as it is 42 seconds before event_time. However, we are interested in an absolute value
+ assert event_time_diff==42, f"event time difference is incorrect"
+ return
+
+
+if __name__=="__main__":
+ test_difference_to_then_tgt_time_none()
+ test_difference_to_then_tgt_time_not_none()
+ test_difference_to_then_tgt_time_not_none_make_absolute()
+
+
diff --git a/src/server/tests/impl/__init__.py b/src/server/tests/impl/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/src/server/tests/schemas/__init__.py b/src/server/tests/schemas/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/src/server/tests/services/__init__.py b/src/server/tests/services/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/src/server/tests/stubs/__init__.py b/src/server/tests/stubs/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/src/server/tests/stubs/test_stub_objects.py b/src/server/tests/stubs/test_stub_objects.py
new file mode 100644
index 0000000..b7a387a
--- /dev/null
+++ b/src/server/tests/stubs/test_stub_objects.py
@@ -0,0 +1,59 @@
+import pytest
+
+def test_build_stub_berth():
+ from BreCal.schemas.model import Berth
+ from BreCal.stubs.berth import get_berth_simple
+ berth = get_berth_simple()
+ assert isinstance(berth, Berth)
+ return
+
+def test_build_stub_participant():
+ from BreCal.schemas.model import Participant
+ from BreCal.stubs.participant import get_participant_simple
+ participant = get_participant_simple()
+ assert isinstance(participant, Participant)
+ return
+
+def test_build_stub_user():
+ from BreCal.schemas.model import User
+ from BreCal.stubs.user import get_user_simple
+ user = get_user_simple()
+ assert isinstance(user, User)
+ return
+
+def test_build_stub_ship():
+ from BreCal.schemas.model import Ship
+ from BreCal.stubs.ship import get_ship_simple
+ ship = get_ship_simple()
+ assert isinstance(ship, Ship)
+ return
+
+def test_build_stub_shipcall():
+ from BreCal.schemas.model import Shipcall
+ from BreCal.stubs.shipcall import get_shipcall_simple
+ shipcall = get_shipcall_simple()
+ assert isinstance(shipcall, Shipcall)
+ return
+
+def test_build_stub_times():
+ from BreCal.schemas.model import Times
+ from BreCal.stubs.times_full import get_times_full_simple
+ times = get_times_full_simple()
+ assert isinstance(times, Times)
+ return
+
+def test_build_stub_notification():
+ from BreCal.schemas.model import Notification
+ from BreCal.stubs.notification import get_notification_simple
+ notification = get_notification_simple()
+ assert isinstance(notification, Notification)
+
+if __name__=="__main__":
+ test_build_stub_berth()
+ test_build_stub_participant()
+ test_build_stub_berth()
+ test_build_stub_user()
+ test_build_stub_ship()
+ test_build_stub_shipcall()
+ test_build_stub_times()
+ test_build_stub_notification()
diff --git a/src/server/tests/test_create_app.py b/src/server/tests/test_create_app.py
new file mode 100644
index 0000000..652ae3d
--- /dev/null
+++ b/src/server/tests/test_create_app.py
@@ -0,0 +1,21 @@
+import pytest
+
+def test_create_app():
+ """
+
+ """
+ import os
+ import sys
+ from BreCal import get_project_root
+
+ project_root = get_project_root("brecal")
+ lib_location = os.path.join(project_root, "src", "server")
+ sys.path.append(lib_location)
+
+ from BreCal import create_app
+ os.chdir(os.path.join(lib_location,"BreCal")) # set the current directory to ~/brecal/src/server/BreCal, so the config is found
+ application = create_app()
+ return
+
+if __name__=="__main__":
+ test_create_app()
diff --git a/src/server/tests/test_import_modules.py b/src/server/tests/test_import_modules.py
new file mode 100644
index 0000000..754772b
--- /dev/null
+++ b/src/server/tests/test_import_modules.py
@@ -0,0 +1,86 @@
+import pytest
+
+def test_import_tqdm_tqdm():
+ """tqdm is a neat utility library for simple display of progress in loops"""
+ from tqdm import tqdm
+ return
+
+def test_import_numpy():
+ """numpy is useful to evaluate multiple entries simultaneously, as boolean operations (e.g., greater than) are efficiently handled"""
+ import numpy as np
+ return
+
+def test_import_pandas():
+ """pandas is useful to handle dataframes and read from .csv or .json files, which can be collected into joint DataFrame objects"""
+ import pandas as pd
+ return
+
+def test_import_flask():
+ """flask is a WSGI framework for quick and easy design of web-based applications"""
+ import flask
+ from flask import Flask, Blueprint, request
+ return
+
+def test_import_flask_specific_objects():
+ """common flask objects, such as the Flask api object, the Blueprint and requests"""
+ from flask import Flask, Blueprint, request
+ return
+
+
+
+def test_import_mysql_connector():
+ """the 'mysql.connector' Object is used for the BreCal server database"""
+ import mysql.connector
+ return
+
+def test_import_pydapper():
+ """is a library that provides convenient methods for database related work"""
+ import pydapper
+ return
+
+def test_import_webargs():
+ """currently used in ~/brecal/src/server/BreCal/api/berths.py"""
+ import webargs
+ from webargs.flaskparser import parser
+ return
+
+def test_import_mashmallow():
+ """currently used in ~/brecal/src/server/BreCal/api/shipcalls.py"""
+ import marshmallow
+ from marshmallow import Schema, fields
+ return
+
+def test_import_flask_jwt_extended():
+ """currently used in ~/brecal/src/server/BreCal/api/login.py"""
+ import flask_jwt_extended
+ from flask_jwt_extended import create_access_token
+ return
+
+def test_import_pyjwt():
+ """currently used in ~/brecal/src/server/BreCal/services/jwt_handler.py"""
+ import jwt
+ return
+
+def test_import_bcrypt():
+ """currently used in ~/brecal/src/server/BreCal/impl/login.py"""
+ import bcrypt
+ return
+
+def test_import_math():
+ """math.isclose can be interesting to measure differences between two times (e.g., to ignore milliseconds)"""
+ import math
+ math.isclose
+ return
+
+def test_import_datetime():
+ """datetime is the default library for times"""
+ import datetime
+ datetime.datetime.now()
+ return
+
+
+if __name__=="__main__":
+ test_import_tqdm_tqdm()
+ test_import_pandas()
+ test_import_flask()
+
diff --git a/src/server/tests/validators/__init__.py b/src/server/tests/validators/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/src/server/tests/validators/test_input_validation.py b/src/server/tests/validators/test_input_validation.py
new file mode 100644
index 0000000..1626a64
--- /dev/null
+++ b/src/server/tests/validators/test_input_validation.py
@@ -0,0 +1,63 @@
+import pytest
+
+@pytest.fixture()
+def build_input_validation():
+ from BreCal.validators.input_validation import InputValidation
+ iv = InputValidation()
+ return locals()
+
+
+def test_build_input_validation():
+ from BreCal.validators.input_validation import InputValidation
+ iv = InputValidation()
+ return
+
+def test_all_models_are_supported(build_input_validation):
+ iv = build_input_validation["iv"]
+
+ from BreCal.stubs.ship import get_ship_simple
+ ship = get_ship_simple()
+ iv.assert_if_not_supported(ship)
+
+ from BreCal.stubs.shipcall import get_shipcall_simple
+ shipcall = get_shipcall_simple()
+ iv.assert_if_not_supported(shipcall)
+
+ from BreCal.stubs.berth import get_berth_simple
+ berth = get_berth_simple()
+ iv.assert_if_not_supported(berth)
+
+ from BreCal.stubs.participant import get_participant_simple
+ participant = get_participant_simple()
+ iv.assert_if_not_supported(participant)
+
+ from BreCal.stubs.user import get_user_simple
+ user = get_user_simple()
+ iv.assert_if_not_supported(user)
+
+ # placeholder: how to handle times?
+ return
+
+def test_ship_input_validation(build_input_validation):
+ iv = build_input_validation["iv"]
+
+ from BreCal.stubs.ship import get_ship_simple
+ ship = get_ship_simple()
+ violations, state = iv.verify(ship)
+ assert state, f"found violations: {violations}"
+ return
+
+def test_participant_input_validation(build_input_validation):
+ iv = build_input_validation["iv"]
+
+ from BreCal.stubs.participant import get_participant_simple
+ participant = get_participant_simple()
+ violations, state = iv.verify(participant)
+ assert state, f"found violations: {violations}"
+ return
+
+
+
+if __name__=="__main__":
+ pass
+
diff --git a/src/server/tests/validators/test_schema_validation_berth.py b/src/server/tests/validators/test_schema_validation_berth.py
new file mode 100644
index 0000000..1ddc239
--- /dev/null
+++ b/src/server/tests/validators/test_schema_validation_berth.py
@@ -0,0 +1,14 @@
+import pytest
+from BreCal.stubs.berth import get_berth_simple
+
+def test_berth():
+ with pytest.raises(ValueError, match="#TODO: copied from ships."):
+ berth = get_berth_simple()
+
+ raise ValueError("#TODO: copied from ships.")
+ from BreCal.validators.schema_validation import test____
+ ship = get_ship_simple()
+ ship.length = 234
+ assert ship_length_in_range(ship)[0], f"ship length must be between 0 and 500 meters"
+ return
+
diff --git a/src/server/tests/validators/test_schema_validation_participant.py b/src/server/tests/validators/test_schema_validation_participant.py
new file mode 100644
index 0000000..eaf746b
--- /dev/null
+++ b/src/server/tests/validators/test_schema_validation_participant.py
@@ -0,0 +1,28 @@
+import pytest
+from BreCal.stubs.participant import get_participant_simple
+
+def test_participant_postal_code_len_is_five():
+ from BreCal.validators.schema_validation import participant_postal_code_len_is_five
+
+ participant = get_participant_simple()
+ assert participant_postal_code_len_is_five(participant)[0], f"the postal code should be exactly 5 numbers"
+ return
+
+def test_participant_postal_code_len_is_six_should_assert():
+ from BreCal.validators.schema_validation import participant_postal_code_len_is_five
+
+ participant = get_participant_simple()
+ participant.postal_code = "123456"
+ with pytest.raises(AssertionError, match="the postal code should be exactly 5 numbers"):
+ assert participant_postal_code_len_is_five(participant)[0], f"the postal code should be exactly 5 numbers"
+ return
+
+# TODO_postal_code_zero -> assert? Is postal_code mandatory?
+
+
+
+
+if __name__=="__main__":
+ test_participant_postal_code_len_is_five()
+ test_participant_postal_code_len_is_six_should_assert()
+
diff --git a/src/server/tests/validators/test_schema_validation_ship.py b/src/server/tests/validators/test_schema_validation_ship.py
new file mode 100644
index 0000000..a364c96
--- /dev/null
+++ b/src/server/tests/validators/test_schema_validation_ship.py
@@ -0,0 +1,270 @@
+import pytest
+from BreCal.stubs.ship import get_ship_simple
+
+def test_ship_length_valid_range_234_is_valid():
+ from BreCal.validators.schema_validation import ship_length_in_range
+ ship = get_ship_simple()
+ ship.length = 234
+ assert ship_length_in_range(ship)[0], f"ship length must be between 0 and 500 meters"
+ return
+
+def test_ship_length_maximum_not_valid_range():
+ from BreCal.validators.schema_validation import ship_length_in_range
+ ship = get_ship_simple()
+ ship.length = 500
+ with pytest.raises(AssertionError):
+ assert ship_length_in_range(ship)[0], f"ship length must be between 0 and 500 meters, but is 500"
+ return
+
+def test_ship_length_minimum_not_valid_range():
+ from BreCal.validators.schema_validation import ship_length_in_range
+ ship = get_ship_simple()
+ ship.length = 0
+ with pytest.raises(AssertionError):
+ assert ship_length_in_range(ship)[0], f"ship length must be between 0 and 500 meters, but is 0"
+ return
+
+def test_ship_width_valid_range_137_is_valid():
+ from BreCal.validators.schema_validation import ship_width_in_range
+ ship = get_ship_simple()
+ ship.width = 137
+ assert ship_width_in_range(ship)[0], f"ship width must be between 0 and 500 meters"
+ return
+
+def test_ship_width_maximum_not_valid_range():
+ from BreCal.validators.schema_validation import ship_width_in_range
+ ship = get_ship_simple()
+ ship.width = 500
+ with pytest.raises(AssertionError):
+ assert ship_width_in_range(ship)[0], f"ship width must be between 0 and 500 meters, but is 500"
+ return
+
+def test_ship_width_minimum_not_valid_range():
+ from BreCal.validators.schema_validation import ship_width_in_range
+ ship = get_ship_simple()
+ ship.width = 0
+ with pytest.raises(AssertionError):
+ assert ship_width_in_range(ship)[0], f"ship width must be between 0 and 500 meters, but is 0"
+ return
+
+# not tug: values can be None and raise no error
+def test_ship_bollard_pull_is_none_and_not_tug():
+ from BreCal.validators.schema_validation import ship_bollard_pull_is_none_or_in_range
+ ship = get_ship_simple()
+ ship.is_tug = False
+ ship.bollard_pull = None
+ assert ship_bollard_pull_is_none_or_in_range(ship)[0], f"the bollard_pull should either be undefined or between 0 and 500 meters"
+ return
+
+def test_ship_participant_id_is_none_and_not_tug():
+ from BreCal.validators.schema_validation import ship_participant_id_is_none_or_int
+ ship = get_ship_simple()
+ ship.is_tug = False
+ ship.participant_id = None
+ assert ship_participant_id_is_none_or_int(ship)[0], f"the participant_id should either be undefined or an integer id"
+ return
+
+def test_ship_max_draft_is_none_and_not_tug():
+ from BreCal.validators.schema_validation import ship_max_draft_is_none_or_in_range
+ ship = get_ship_simple()
+ ship.is_tug = False
+ ship.max_draft = None
+ assert ship_max_draft_is_none_or_in_range(ship)[0], f"the max_draft should either be undefined or between 0 and 20 meters"
+ return
+
+
+# tug: values must be set, and are set. all tests should be accepted without assertion
+def test_ship_is_tug_bollard_pull_is_not_none():
+ from BreCal.validators.schema_validation import ship_bollard_pull_is_none_or_in_range
+ ship = get_ship_simple()
+ ship.is_tug = True
+ ship.bollard_pull = 311
+ assert ship_bollard_pull_is_none_or_in_range(ship)[0], f"the bollard_pull should either be undefined or between 0 and 500 meters"
+ return
+
+
+def test_ship_is_tug_max_draft_is_not_none():
+ from BreCal.validators.schema_validation import ship_max_draft_is_none_or_in_range
+ ship = get_ship_simple()
+ ship.is_tug = True
+ ship.max_draft = 17
+ assert ship_max_draft_is_none_or_in_range(ship)[0], f"the max_draft should either be undefined or between 0 and 20 meters"
+ return
+
+def test_ship_is_tug_participant_id_is_not_none():
+ from BreCal.validators.schema_validation import ship_participant_id_is_none_or_int
+ from BreCal.stubs import generate_uuid1_int
+ ship = get_ship_simple()
+ ship.is_tug = True
+ ship.participant_id = generate_uuid1_int()
+ assert ship_participant_id_is_none_or_int(ship)[0], f"the participant_id should either be undefined or an integer id"
+ return
+
+def test_ship_is_tug_participant_id_is_str_and_fails():
+ from BreCal.validators.schema_validation import ship_participant_id_is_none_or_int
+ # note: this is an artificial test case. However, it ensures that operators using the backend cannot create an id incorrectly
+ from BreCal.stubs import generate_uuid1_int
+ ship = get_ship_simple()
+ ship.is_tug = True
+ ship.participant_id = str(generate_uuid1_int())
+ with pytest.raises(AssertionError):
+ assert ship_participant_id_is_none_or_int(ship)[0], f"the participant_id should either be None or int, but is str"
+ return
+
+
+# tug: values must be set, but are not. all tests should raise AssertionError
+def test_ship_is_tug_bollard_pull_but_is_none_fails():
+ from BreCal.validators.schema_validation import ship_bollard_pull_is_defined_or_is_not_tug
+ ship = get_ship_simple()
+ ship.is_tug = True
+ ship.bollard_pull = None
+ with pytest.raises(AssertionError):
+ assert ship_bollard_pull_is_defined_or_is_not_tug(ship)[0], f"the bollard_pull cannot be None, if the ship is a tug"
+ return
+
+def test_ship_is_tug_max_draft_but_is_none_fails():
+ from BreCal.validators.schema_validation import ship_max_draft_is_defined_or_is_not_tug
+ ship = get_ship_simple()
+ ship.is_tug = True
+ ship.max_draft = None
+ with pytest.raises(AssertionError):
+ assert ship_max_draft_is_defined_or_is_not_tug(ship)[0], f"the max_draft cannot be None, if the ship is a tug"
+ return
+
+def test_ship_is_tug_participant_id_but_is_none_fails():
+ from BreCal.validators.schema_validation import ship_participant_id_is_defined_or_is_not_tug
+ ship = get_ship_simple()
+ ship.is_tug = True
+ ship.participant_id = None
+ with pytest.raises(AssertionError):
+ assert ship_participant_id_is_defined_or_is_not_tug(ship)[0], f"the participant_id cannot be None, if the ship is a tug"
+ return
+
+
+# tug: values must be in valid range
+# # sequence: 1.) is valid, 2.) is too small, 3.) is too large
+def test_ship_is_tug_bollard_pull_in_range_311_valid():
+ from BreCal.validators.schema_validation import ship_bollard_pull_is_none_or_in_range
+ ship = get_ship_simple()
+ ship.is_tug = True
+ ship.bollard_pull = 311
+ assert ship_bollard_pull_is_none_or_in_range(ship)[0], f"the bollard_pull must be 00, f"must return at least one method!"
+ return
+
+
+
+
+def test_validation_rule_fct_agency_and_terminal_pier_side_disagreement(build_sql_proxy_connection):
+ """#0006-A validation_rule_fct_agency_and_terminal_pier_side_disagreement"""
+ import pandas as pd
+
+ from BreCal.stubs.times_full import get_times_full_simple
+ from BreCal.stubs.shipcall import get_shipcall_simple
+ from BreCal.database.enums import ParticipantType
+ from BreCal.database.enums import StatusFlags
+
+ vr = build_sql_proxy_connection["vr"]
+ shipcall = get_shipcall_simple()
+ t1 = get_times_full_simple()
+ t2 = get_times_full_simple()
+
+ # roles: agency & terminal
+ t1.participant_type = ParticipantType.AGENCY.value
+ t2.participant_type = ParticipantType.TERMINAL.value
+
+ # disagreement
+ t1.pier_side = True
+ t2.pier_side = False
+
+ time_objects = [t1, t2]
+ df_times = pd.DataFrame.from_records([to_.__dict__ for to_ in time_objects])
+ df_times.set_index('id',inplace=True)
+
+ (state, description) = vr.validation_rule_fct_agency_and_terminal_pier_side_disagreement(shipcall, df_times)
+ assert state.value > StatusFlags.GREEN.value, f"a violation must be identified"
+ assert description is not None, f"a violation description must be identified"
+ return
+
+
+def test_validation_rule_fct_agency_and_terminal_pier_side_agreement(build_sql_proxy_connection):
+ """#0006-A validation_rule_fct_agency_and_terminal_pier_side_disagreement"""
+ import pandas as pd
+
+ from BreCal.stubs.times_full import get_times_full_simple
+ from BreCal.stubs.shipcall import get_shipcall_simple
+ from BreCal.database.enums import ParticipantType
+ from BreCal.database.enums import StatusFlags
+
+ vr = build_sql_proxy_connection["vr"]
+ shipcall = get_shipcall_simple()
+ t1 = get_times_full_simple()
+ t2 = get_times_full_simple()
+
+ # roles: agency & terminal
+ t1.participant_type = ParticipantType.AGENCY.value
+ t2.participant_type = ParticipantType.TERMINAL.value
+
+ # agreement
+ t1.pier_side = True
+ t2.pier_side = True
+
+ time_objects = [t1, t2]
+ df_times = pd.DataFrame.from_records([to_.__dict__ for to_ in time_objects])
+ df_times.set_index('id',inplace=True)
+
+ (state, description) = vr.validation_rule_fct_agency_and_terminal_pier_side_disagreement(shipcall, df_times)
+ assert state.value == StatusFlags.GREEN.value, f"no violation should be observed"
+ assert description is None, f"no violation should be observed"
+ return
+
+
+
+
+def test_validation_rule_fct_agency_and_terminal_berth_id_disagreement(build_sql_proxy_connection):
+ """#0006-B validation_rule_fct_agency_and_terminal_pier_side_disagreement"""
+ import pandas as pd
+
+ from BreCal.stubs.times_full import get_times_full_simple
+ from BreCal.stubs.shipcall import get_shipcall_simple
+ from BreCal.database.enums import ParticipantType
+ from BreCal.database.enums import StatusFlags
+
+ vr = build_sql_proxy_connection["vr"]
+ shipcall = get_shipcall_simple()
+ t1 = get_times_full_simple()
+ t2 = get_times_full_simple()
+
+ # roles: agency & terminal
+ t1.participant_type = ParticipantType.AGENCY.value
+ t2.participant_type = ParticipantType.TERMINAL.value
+
+ # disagreement
+ t1.berth_id = 1
+ t2.berth_id = 2
+
+ time_objects = [t1, t2]
+ df_times = pd.DataFrame.from_records([to_.__dict__ for to_ in time_objects])
+ df_times.set_index('id',inplace=True)
+
+ (state, description) = vr.validation_rule_fct_agency_and_terminal_berth_id_disagreement(shipcall, df_times)
+ assert state.value > StatusFlags.GREEN.value, f"a violation must be identified"
+ assert description is not None, f"a violation description must be identified"
+ return
+
+def test_validation_rule_fct_agency_and_terminal_berth_id_agreement(build_sql_proxy_connection):
+ """#0006-B validation_rule_fct_agency_and_terminal_pier_side_disagreement"""
+ import pandas as pd
+
+ from BreCal.stubs.times_full import get_times_full_simple
+ from BreCal.stubs.shipcall import get_shipcall_simple
+ from BreCal.database.enums import ParticipantType
+ from BreCal.database.enums import StatusFlags
+
+ vr = build_sql_proxy_connection["vr"]
+ shipcall = get_shipcall_simple()
+ t1 = get_times_full_simple()
+ t2 = get_times_full_simple()
+
+ # roles: agency & terminal
+ t1.participant_type = ParticipantType.AGENCY.value
+ t2.participant_type = ParticipantType.TERMINAL.value
+
+ # agreement
+ t1.berth_id = 21
+ t2.berth_id = 21
+
+ time_objects = [t1, t2]
+ df_times = pd.DataFrame.from_records([to_.__dict__ for to_ in time_objects])
+ df_times.set_index('id',inplace=True)
+
+ (state, description) = vr.validation_rule_fct_agency_and_terminal_berth_id_disagreement(shipcall, df_times)
+ assert state.value == StatusFlags.GREEN.value, f"no violation should be observed"
+ assert description is None, f"no violation should be observed"
+ return
+
+
+
+
diff --git a/src/server/tests/validators/test_validation_rule_state.py b/src/server/tests/validators/test_validation_rule_state.py
new file mode 100644
index 0000000..4ed9b2c
--- /dev/null
+++ b/src/server/tests/validators/test_validation_rule_state.py
@@ -0,0 +1,26 @@
+import pytest
+from BreCal.database.enums import StatusFlags
+
+def test_validation_rule_state_green_is_1():
+ assert StatusFlags.GREEN.value==1
+ return
+
+def test_validation_rule_state_yellow_is_2():
+ assert StatusFlags.YELLOW.value==2
+ return
+
+def test_validation_rule_state_red_is_3():
+ assert StatusFlags.RED.value==3
+ return
+
+def test_validation_rule_state_order():
+ # Red 3, Yellow 2, Green 1, None 0
+ # red>yellow>green>none
+ assert StatusFlags.RED.value>StatusFlags.YELLOW.value
+ assert StatusFlags.YELLOW.value>StatusFlags.GREEN.value
+ assert StatusFlags.GREEN.value>StatusFlags.NONE.value
+ return
+
+if __name__=="__main__":
+ pass
+