Merge branch 'feature/extra_time_logic' into release/1.5.0

This commit is contained in:
Daniel Schick 2024-11-14 11:58:30 +01:00
commit 4870c81783
12 changed files with 248 additions and 269 deletions

View File

@ -8,8 +8,8 @@
<SignAssembly>True</SignAssembly> <SignAssembly>True</SignAssembly>
<StartupObject>BreCalClient.App</StartupObject> <StartupObject>BreCalClient.App</StartupObject>
<AssemblyOriginatorKeyFile>..\..\misc\brecal.snk</AssemblyOriginatorKeyFile> <AssemblyOriginatorKeyFile>..\..\misc\brecal.snk</AssemblyOriginatorKeyFile>
<AssemblyVersion>1.5.0.8</AssemblyVersion> <AssemblyVersion>1.5.0.12</AssemblyVersion>
<FileVersion>1.5.0.8</FileVersion> <FileVersion>1.5.0.12</FileVersion>
<Title>Bremen calling client</Title> <Title>Bremen calling client</Title>
<Description>A Windows WPF client for the Bremen calling API.</Description> <Description>A Windows WPF client for the Bremen calling API.</Description>
<ApplicationIcon>containership.ico</ApplicationIcon> <ApplicationIcon>containership.ico</ApplicationIcon>

View File

@ -205,25 +205,21 @@ namespace BreCalClient
case ShipcallType.Departure: case ShipcallType.Departure:
isEnabled &= this.comboBoxDepartureBerth.SelectedItem != null; isEnabled &= this.comboBoxDepartureBerth.SelectedItem != null;
isEnabled &= this.datePickerETD.Value.HasValue; isEnabled &= this.datePickerETD.Value.HasValue;
if(this.datePickerETD.Value.HasValue) isEnabled &= !(this.datePickerETD.Value.IsTooOld() && this.datePickerETD.Value != this.ShipcallModel.Shipcall?.Etd);
isEnabled &= (this.datePickerETD.Value.Value > DateTime.Now);
isEnabled &= !this.datePickerETD.Value.IsTooFar(); isEnabled &= !this.datePickerETD.Value.IsTooFar();
break; break;
case ShipcallType.Arrival: case ShipcallType.Arrival:
isEnabled &= this.comboBoxArrivalBerth.SelectedItem != null; isEnabled &= this.comboBoxArrivalBerth.SelectedItem != null;
isEnabled &= this.datePickerETA.Value.HasValue; isEnabled &= this.datePickerETA.Value.HasValue;
if(this.datePickerETA.Value.HasValue) isEnabled &= !(this.datePickerETA.Value.IsTooOld() && this.datePickerETA.Value != this.ShipcallModel.Shipcall?.Eta);
isEnabled &= (this.datePickerETA.Value.Value > DateTime.Now);
isEnabled &= !this.datePickerETA.Value.IsTooFar(); isEnabled &= !this.datePickerETA.Value.IsTooFar();
break; break;
case ShipcallType.Shifting: case ShipcallType.Shifting:
isEnabled &= ((this.comboBoxDepartureBerth.SelectedItem != null) && (this.comboBoxArrivalBerth.SelectedItem != null)); isEnabled &= ((this.comboBoxDepartureBerth.SelectedItem != null) && (this.comboBoxArrivalBerth.SelectedItem != null));
isEnabled &= this.datePickerETD.Value.HasValue; isEnabled &= this.datePickerETD.Value.HasValue;
isEnabled &= this.datePickerETA.Value.HasValue; isEnabled &= this.datePickerETA.Value.HasValue;
if (this.datePickerETD.Value.HasValue) isEnabled &= !(this.datePickerETD.Value.IsTooOld() && this.datePickerETD.Value != this.ShipcallModel.Shipcall?.Etd);
isEnabled &= (this.datePickerETD.Value.Value > DateTime.Now); isEnabled &= !(this.datePickerETA.Value.IsTooOld() && this.datePickerETA.Value != this.ShipcallModel.Shipcall?.Eta);
if (this.datePickerETA.Value.HasValue)
isEnabled &= (this.datePickerETA.Value.Value > DateTime.Now);
if (this.datePickerETA.Value.HasValue && this.datePickerETD.Value.HasValue) if (this.datePickerETA.Value.HasValue && this.datePickerETD.Value.HasValue)
isEnabled &= (this.datePickerETA.Value.Value > this.datePickerETD.Value.Value); isEnabled &= (this.datePickerETA.Value.Value > this.datePickerETD.Value.Value);
isEnabled &= !this.datePickerETD.Value.IsTooFar(); isEnabled &= !this.datePickerETD.Value.IsTooFar();

View File

@ -4,7 +4,6 @@
using BreCalClient.misc.Model; using BreCalClient.misc.Model;
using System; using System;
using System.Runtime.Serialization;
using System.Windows; using System.Windows;
using static BreCalClient.Extensions; using static BreCalClient.Extensions;
@ -97,46 +96,40 @@ namespace BreCalClient
{ {
message = ""; message = "";
if (this.datePickerETA.Value.HasValue && (this.datePickerETA.Value.Value < DateTime.Now) && (this.datePickerETA_End.Value == null)) if ((this.datePickerETA.Value != this.Times.EtaBerth) || (this.datePickerETA_End.Value != this.Times.EtaIntervalEnd)) // something has changed
{ {
message = BreCalClient.Resources.Resources.textETAInThePast; if (datePickerETA.Value.IsTooOld() || datePickerETA_End.Value.IsTooOld())
return false; {
message = BreCalClient.Resources.Resources.textETAInThePast;
return false;
}
if (this.datePickerETA.Value.HasValue && this.datePickerETA_End.Value.HasValue && this.datePickerETA.Value > this.datePickerETA_End.Value)
{
message = BreCalClient.Resources.Resources.textEndValueBeforeStartValue;
return false;
}
} }
if(this.datePickerETA_End.Value.HasValue && this.datePickerETA_End.Value < DateTime.Now) if((this.datePickerTidalWindowFrom.Value != this.ShipcallModel.Shipcall?.TidalWindowFrom) || (this.datePickerTidalWindowTo.Value != this.ShipcallModel.Shipcall?.TidalWindowTo)) // something has changed
{ {
message = BreCalClient.Resources.Resources.textETAInThePast; if(datePickerTidalWindowTo.Value.IsTooOld() || this.datePickerTidalWindowFrom.Value.IsTooOld())
return false; {
} message = BreCalClient.Resources.Resources.textTideTimesInThePast;
return false;
}
if(this.datePickerETA.Value.HasValue && this.datePickerETA_End.Value.HasValue && this.datePickerETA.Value > this.datePickerETA_End.Value) if (this.datePickerTidalWindowFrom.Value.HasValue && this.datePickerTidalWindowTo.Value.HasValue && this.datePickerTidalWindowFrom.Value > this.datePickerTidalWindowTo.Value)
{ {
message = BreCalClient.Resources.Resources.textEndValueBeforeStartValue; message = BreCalClient.Resources.Resources.textEndValueBeforeStartValue;
return false; return false;
} }
if (this.datePickerTidalWindowFrom.Value.HasValue && (this.datePickerTidalWindowFrom.Value.Value < DateTime.Now) && (this.datePickerTidalWindowTo.Value == null)) if ((this.datePickerTidalWindowFrom.Value.HasValue && !this.datePickerTidalWindowTo.Value.HasValue) || (!this.datePickerTidalWindowFrom.Value.HasValue && this.datePickerTidalWindowTo.Value.HasValue))
{ {
message = BreCalClient.Resources.Resources.textTideTimesInThePast; message = BreCalClient.Resources.Resources.textTidalBothValues;
return false; return false;
} }
if (this.datePickerTidalWindowTo.Value.HasValue && this.datePickerTidalWindowTo.Value < DateTime.Now)
{
message = BreCalClient.Resources.Resources.textTideTimesInThePast;
return false;
}
if (this.datePickerTidalWindowFrom.Value.HasValue && this.datePickerTidalWindowTo.Value.HasValue && this.datePickerTidalWindowFrom.Value > this.datePickerTidalWindowTo.Value)
{
message = BreCalClient.Resources.Resources.textEndValueBeforeStartValue;
return false;
}
if((this.datePickerTidalWindowFrom.Value.HasValue && !this.datePickerTidalWindowTo.Value.HasValue) || (!this.datePickerTidalWindowFrom.Value.HasValue && this.datePickerTidalWindowTo.Value.HasValue))
{
message = BreCalClient.Resources.Resources.textTidalBothValues;
return false;
} }
if(this.datePickerETA.Value.IsTooFar() || this.datePickerETA_End.Value.IsTooFar() || this.datePickerTidalWindowFrom.Value.IsTooFar() || this.datePickerTidalWindowTo.Value.IsTooFar()) if(this.datePickerETA.Value.IsTooFar() || this.datePickerETA_End.Value.IsTooFar() || this.datePickerTidalWindowFrom.Value.IsTooFar() || this.datePickerTidalWindowTo.Value.IsTooFar())
@ -145,8 +138,7 @@ namespace BreCalClient
return false; return false;
} }
if((this.datePickerETA_End.Value.HasValue && !this.datePickerETA.Value.HasValue) || if((this.datePickerETA_End.Value.HasValue && !this.datePickerETA.Value.HasValue) || (this.datePickerTidalWindowTo.Value.HasValue && !this.datePickerTidalWindowFrom.Value.HasValue))
(this.datePickerTidalWindowTo.Value.HasValue && !this.datePickerTidalWindowFrom.Value.HasValue))
{ {
message = BreCalClient.Resources.Resources.textStartTimeMissing; message = BreCalClient.Resources.Resources.textStartTimeMissing;
return false; return false;

View File

@ -4,15 +4,8 @@
using BreCalClient.misc.Model; using BreCalClient.misc.Model;
using System; using System;
using System.Text.RegularExpressions;
using System.Windows; using System.Windows;
using System.Windows.Controls.Primitives;
using System.Windows.Controls;
using Xceed.Wpf.Toolkit;
using static BreCalClient.Extensions; using static BreCalClient.Extensions;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Media;
namespace BreCalClient namespace BreCalClient
{ {
@ -107,16 +100,13 @@ namespace BreCalClient
{ {
message = ""; message = "";
if (this.datePickerETD.Value.HasValue && (this.datePickerETD.Value.Value < DateTime.Now) && (this.datePickerETD_End.Value == null)) if((this.datePickerETD.Value != this.Times.EtdBerth) || (this.datePickerETD_End.Value != this.Times.EtdIntervalEnd))
{ {
message = BreCalClient.Resources.Resources.textETDInThePast; if (datePickerETD.Value.IsTooOld() || datePickerETD_End.Value.IsTooOld())
return false; {
} message = BreCalClient.Resources.Resources.textETDInThePast;
return false;
if (this.datePickerETD_End.Value.HasValue && this.datePickerETD_End.Value < DateTime.Now) }
{
message = BreCalClient.Resources.Resources.textETDInThePast;
return false;
} }
if (this.datePickerETD.Value.HasValue && this.datePickerETD_End.Value.HasValue && this.datePickerETD.Value > this.datePickerETD_End.Value) if (this.datePickerETD.Value.HasValue && this.datePickerETD_End.Value.HasValue && this.datePickerETD.Value > this.datePickerETD_End.Value)
@ -125,16 +115,13 @@ namespace BreCalClient
return false; return false;
} }
if (this.datePickerTidalWindowFrom.Value.HasValue && (this.datePickerTidalWindowFrom.Value.Value < DateTime.Now) && (this.datePickerTidalWindowTo.Value == null)) if((this.datePickerTidalWindowFrom.Value != this.ShipcallModel.Shipcall?.TidalWindowFrom) || (this.datePickerTidalWindowTo.Value != this.ShipcallModel.Shipcall?.TidalWindowTo))
{ {
message = BreCalClient.Resources.Resources.textTideTimesInThePast; if (this.datePickerTidalWindowTo.Value.IsTooOld() || this.datePickerTidalWindowFrom.Value.IsTooOld())
return false; {
} message = BreCalClient.Resources.Resources.textTideTimesInThePast;
return false;
if (this.datePickerTidalWindowTo.Value.HasValue && this.datePickerTidalWindowTo.Value < DateTime.Now) }
{
message = BreCalClient.Resources.Resources.textTideTimesInThePast;
return false;
} }
if (this.datePickerTidalWindowFrom.Value.HasValue && this.datePickerTidalWindowTo.Value.HasValue && this.datePickerTidalWindowFrom.Value > this.datePickerTidalWindowTo.Value) if (this.datePickerTidalWindowFrom.Value.HasValue && this.datePickerTidalWindowTo.Value.HasValue && this.datePickerTidalWindowFrom.Value > this.datePickerTidalWindowTo.Value)
@ -155,8 +142,7 @@ namespace BreCalClient
return false; return false;
} }
if((this.datePickerETD_End.Value.HasValue && !this.datePickerETD.Value.HasValue) || if((this.datePickerETD_End.Value.HasValue && !this.datePickerETD.Value.HasValue) || (this.datePickerTidalWindowTo.Value.HasValue && !this.datePickerTidalWindowFrom.Value.HasValue))
(this.datePickerTidalWindowTo.Value.HasValue && !this.datePickerTidalWindowFrom.Value.HasValue))
{ {
message = BreCalClient.Resources.Resources.textStartTimeMissing; message = BreCalClient.Resources.Resources.textStartTimeMissing;
return false; return false;

View File

@ -97,16 +97,14 @@ namespace BreCalClient
{ {
message = ""; message = "";
if (this.datePickerETA.Value.HasValue && (this.datePickerETA.Value.Value < DateTime.Now) && (this.datePickerETA_End.Value == null))
{
message = BreCalClient.Resources.Resources.textETAInThePast;
return false;
}
if (this.datePickerETA_End.Value.HasValue && this.datePickerETA_End.Value < DateTime.Now) if((this.datePickerETA.Value != this.Times.EtaBerth) || (this.datePickerETA_End.Value != this.Times.EtaIntervalEnd))
{ {
message = BreCalClient.Resources.Resources.textETAInThePast; if (this.datePickerETA.Value.IsTooOld() && this.datePickerETA_End.Value.IsTooOld())
return false; {
message = BreCalClient.Resources.Resources.textETAInThePast;
return false;
}
} }
if (this.datePickerETA.Value.HasValue && this.datePickerETA_End.Value.HasValue && this.datePickerETA.Value > this.datePickerETA_End.Value) if (this.datePickerETA.Value.HasValue && this.datePickerETA_End.Value.HasValue && this.datePickerETA.Value > this.datePickerETA_End.Value)
@ -115,16 +113,13 @@ namespace BreCalClient
return false; return false;
} }
if (this.datePickerETD.Value.HasValue && (this.datePickerETD.Value.Value < DateTime.Now) && (this.datePickerETD_End.Value == null)) if((this.datePickerETD.Value != this.Times.EtdBerth) || (this.datePickerETD_End.Value != this.Times.EtdIntervalEnd))
{ {
message = BreCalClient.Resources.Resources.textETDInThePast; if (this.datePickerETD.Value.IsTooOld() || this.datePickerETD_End.Value.IsTooOld())
return false; {
} message = BreCalClient.Resources.Resources.textETDInThePast;
return false;
if (this.datePickerETD_End.Value.HasValue && this.datePickerETD_End.Value < DateTime.Now) }
{
message = BreCalClient.Resources.Resources.textETDInThePast;
return false;
} }
if (this.datePickerETD.Value.HasValue && this.datePickerETD_End.Value.HasValue && this.datePickerETD.Value > this.datePickerETD_End.Value) if (this.datePickerETD.Value.HasValue && this.datePickerETD_End.Value.HasValue && this.datePickerETD.Value > this.datePickerETD_End.Value)
@ -133,16 +128,13 @@ namespace BreCalClient
return false; return false;
} }
if (this.datePickerTidalWindowFrom.Value.HasValue && (this.datePickerTidalWindowFrom.Value.Value < DateTime.Now) && (this.datePickerTidalWindowTo.Value == null)) if((this.datePickerTidalWindowFrom.Value != this.ShipcallModel.Shipcall?.TidalWindowFrom) || (this.datePickerTidalWindowTo.Value != this.ShipcallModel.Shipcall?.TidalWindowTo))
{ {
message = BreCalClient.Resources.Resources.textTideTimesInThePast; if (this.datePickerTidalWindowFrom.Value.IsTooOld() && this.datePickerTidalWindowTo.Value.IsTooOld())
return false; {
} message = BreCalClient.Resources.Resources.textTideTimesInThePast;
return false;
if (this.datePickerTidalWindowTo.Value.HasValue && this.datePickerTidalWindowTo.Value < DateTime.Now) }
{
message = BreCalClient.Resources.Resources.textTideTimesInThePast;
return false;
} }
if (this.datePickerTidalWindowFrom.Value.HasValue && this.datePickerTidalWindowTo.Value.HasValue && this.datePickerTidalWindowFrom.Value > this.datePickerTidalWindowTo.Value) if (this.datePickerTidalWindowFrom.Value.HasValue && this.datePickerTidalWindowTo.Value.HasValue && this.datePickerTidalWindowFrom.Value > this.datePickerTidalWindowTo.Value)

View File

@ -5,7 +5,6 @@
using BreCalClient.misc.Model; using BreCalClient.misc.Model;
using System; using System;
using System.Runtime.Serialization;
using System.Windows; using System.Windows;
using System.Windows.Media.Imaging; using System.Windows.Media.Imaging;
using Xceed.Wpf.Toolkit; using Xceed.Wpf.Toolkit;
@ -99,16 +98,13 @@ namespace BreCalClient
message = ""; message = "";
if (this.datePickerETABerth.Value.HasValue && (this.datePickerETABerth.Value.Value < DateTime.Now) && (this.datePickerETABerth_End.Value == null) && (this.datePickerETABerth.Value != this.Times.EtaBerth)) if ((this.datePickerETABerth.Value != this.Times.EtaBerth) || (this.datePickerETABerth_End.Value != this.Times.EtaIntervalEnd))
{ {
message = BreCalClient.Resources.Resources.textETAInThePast; if (this.datePickerETABerth.Value.IsTooOld() || this.datePickerETABerth_End.Value.IsTooOld())
return false; {
} message = BreCalClient.Resources.Resources.textETAInThePast;
return false;
if (this.datePickerETABerth_End.Value.HasValue && this.datePickerETABerth_End.Value < DateTime.Now && this.datePickerETABerth_End.Value != this.Times.EtaIntervalEnd) }
{
message = BreCalClient.Resources.Resources.textETAInThePast;
return false;
} }
if (this.datePickerETABerth.Value.HasValue && this.datePickerETABerth_End.Value.HasValue && this.datePickerETABerth.Value > this.datePickerETABerth_End.Value) if (this.datePickerETABerth.Value.HasValue && this.datePickerETABerth_End.Value.HasValue && this.datePickerETABerth.Value > this.datePickerETABerth_End.Value)
@ -117,16 +113,13 @@ namespace BreCalClient
return false; return false;
} }
if (this.datePickerETDBerth.Value.HasValue && (this.datePickerETDBerth.Value.Value < DateTime.Now) && (this.datePickerETABerth_End.Value == null) && (this.datePickerETDBerth.Value != this.Times.EtdBerth)) if((this.datePickerETDBerth.Value != this.Times.EtdBerth) || (this.datePickerETDBerth_End.Value != this.Times.EtdIntervalEnd))
{ {
message = BreCalClient.Resources.Resources.textETDInThePast; if(this.datePickerETDBerth.Value.IsTooOld() || this.datePickerETDBerth_End.Value.IsTooOld())
return false; {
} message = BreCalClient.Resources.Resources.textETDInThePast;
return false;
if (this.datePickerETDBerth_End.Value.HasValue && this.datePickerETDBerth_End.Value < DateTime.Now && this.datePickerETDBerth_End.Value != this.Times.EtdIntervalEnd) }
{
message = BreCalClient.Resources.Resources.textETDInThePast;
return false;
} }
if (this.datePickerETDBerth.Value.HasValue && this.datePickerETDBerth_End.Value.HasValue && this.datePickerETDBerth.Value > this.datePickerETDBerth_End.Value) if (this.datePickerETDBerth.Value.HasValue && this.datePickerETDBerth_End.Value.HasValue && this.datePickerETDBerth.Value > this.datePickerETDBerth_End.Value)
@ -135,13 +128,13 @@ namespace BreCalClient
return false; return false;
} }
if (this.datePickerLockTime.Value.HasValue && (this.datePickerLockTime.Value.Value < DateTime.Now) && (this.datePickerLockTime.Value != this.Times.LockTime)) if (this.datePickerLockTime.Value.IsTooOld() && (this.datePickerLockTime.Value != this.Times.LockTime))
{ {
message = BreCalClient.Resources.Resources.textLockTimeInThePast; message = BreCalClient.Resources.Resources.textLockTimeInThePast;
return false; return false;
} }
if (this.datePickerZoneEntry.Value.HasValue && this.datePickerZoneEntry.Value < DateTime.Now && this.datePickerZoneEntry.Value != this.Times.ZoneEntry) if (this.datePickerZoneEntry.Value.IsTooOld() && (this.datePickerZoneEntry.Value != this.Times.ZoneEntry))
{ {
message = BreCalClient.Resources.Resources.textZoneEntryInThePast; message = BreCalClient.Resources.Resources.textZoneEntryInThePast;
return false; return false;
@ -154,8 +147,7 @@ namespace BreCalClient
return false; return false;
} }
if((this.datePickerETABerth_End.Value.HasValue && !this.datePickerETABerth.Value.HasValue) || if((this.datePickerETABerth_End.Value.HasValue && !this.datePickerETABerth.Value.HasValue) || (this.datePickerETDBerth_End.Value.HasValue && !this.datePickerETDBerth.Value.HasValue))
(this.datePickerETDBerth_End.Value.HasValue && !this.datePickerETDBerth.Value.HasValue))
{ {
message = BreCalClient.Resources.Resources.textStartTimeMissing; message = BreCalClient.Resources.Resources.textStartTimeMissing;
return false; return false;

View File

@ -108,16 +108,13 @@ namespace BreCalClient
message = ""; message = "";
if (this.datePickerOperationStart.Value.HasValue && (this.datePickerOperationStart.Value.Value < DateTime.Now) && (this.datePickerOperationStart_End.Value == null)) if((this.datePickerOperationStart.Value != this.Times.OperationsStart) || (this.datePickerOperationStart_End.Value != this.Times.EtaIntervalEnd))
{ {
message = BreCalClient.Resources.Resources.textOperationStartInThePast; if(this.datePickerOperationStart.Value.IsTooOld() || this.datePickerOperationStart_End.Value.IsTooOld())
return false; {
} message = BreCalClient.Resources.Resources.textOperationStartInThePast;
return false;
if (this.datePickerOperationStart_End.Value.HasValue && this.datePickerOperationStart_End.Value < DateTime.Now) }
{
message = BreCalClient.Resources.Resources.textOperationStartInThePast;
return false;
} }
if (this.datePickerOperationStart.Value.HasValue && this.datePickerOperationStart_End.Value.HasValue && this.datePickerOperationStart.Value > this.datePickerOperationStart_End.Value) if (this.datePickerOperationStart.Value.HasValue && this.datePickerOperationStart_End.Value.HasValue && this.datePickerOperationStart.Value > this.datePickerOperationStart_End.Value)
@ -126,16 +123,13 @@ namespace BreCalClient
return false; return false;
} }
if (this.datePickerOperationEnd.Value.HasValue && (this.datePickerOperationEnd.Value.Value < DateTime.Now) && (this.datePickerOperationEnd_End.Value == null)) if ((this.datePickerOperationEnd.Value != this.Times.OperationsEnd) || (this.datePickerOperationEnd_End.Value != this.Times.EtdIntervalEnd))
{ {
message = BreCalClient.Resources.Resources.textOperationEndInThePast; if(this.datePickerOperationEnd.Value.IsTooOld() || this.datePickerOperationEnd_End.Value.IsTooOld())
return false; {
} message = BreCalClient.Resources.Resources.textOperationEndInThePast;
return false;
if (this.datePickerOperationEnd_End.Value.HasValue && this.datePickerOperationEnd_End.Value < DateTime.Now) }
{
message = BreCalClient.Resources.Resources.textOperationEndInThePast;
return false;
} }
if (this.datePickerOperationEnd.Value.HasValue && this.datePickerOperationEnd_End.Value.HasValue && this.datePickerOperationEnd.Value > this.datePickerOperationEnd_End.Value) if (this.datePickerOperationEnd.Value.HasValue && this.datePickerOperationEnd_End.Value.HasValue && this.datePickerOperationEnd.Value > this.datePickerOperationEnd_End.Value)
@ -150,8 +144,7 @@ namespace BreCalClient
return false; return false;
} }
if((this.datePickerOperationEnd_End.Value.HasValue && !this.datePickerOperationEnd.Value.HasValue) || if((this.datePickerOperationEnd_End.Value.HasValue && !this.datePickerOperationEnd.Value.HasValue) || (this.datePickerOperationStart_End.Value.HasValue && !this.datePickerOperationStart.Value.HasValue))
(this.datePickerOperationStart_End.Value.HasValue && !this.datePickerOperationStart.Value.HasValue))
{ {
message = BreCalClient.Resources.Resources.textStartTimeMissing; message = BreCalClient.Resources.Resources.textStartTimeMissing;
return false; return false;

View File

@ -69,6 +69,14 @@ namespace BreCalClient
return datetime > DateTime.Now.AddYears(1); return datetime > DateTime.Now.AddYears(1);
} }
public static bool IsTooOld(this DateTime? datetime)
{
if (datetime == null) return false;
{
return datetime < DateTime.Now.AddDays(-1);
}
}
public static bool IsTypeFlagSet(this Participant participant, ParticipantType flag) public static bool IsTypeFlagSet(this Participant participant, ParticipantType flag)
{ {
return (participant.Type & (uint)flag) != 0; return (participant.Type & (uint)flag) != 0;

View File

@ -74,7 +74,7 @@ def validate_posted_shipcall_data(user_data:dict, loadedModel:dict, content:dict
# existance checks in content # existance checks in content
# datetime checks in loadedModel (datetime.datetime objects). Dates should be in the future. # datetime checks in loadedModel (datetime.datetime objects). Dates should be in the future.
time_now = datetime.datetime.now() time_now = datetime.datetime.now() - datetime.timedelta(days=1)
type_ = loadedModel.get("type", int(ShipcallType.undefined)) type_ = loadedModel.get("type", int(ShipcallType.undefined))
if int(type_)==int(ShipcallType.undefined): if int(type_)==int(ShipcallType.undefined):
raise ValidationError({"type":f"providing 'type' is mandatory. Missing key!"}) raise ValidationError({"type":f"providing 'type' is mandatory. Missing key!"})
@ -85,7 +85,7 @@ def validate_posted_shipcall_data(user_data:dict, loadedModel:dict, content:dict
if content.get("arrival_berth_id", None) is None: if content.get("arrival_berth_id", None) is None:
raise ValidationError({"arrival_berth_id":f"providing 'arrival_berth_id' is mandatory. Missing key!"}) raise ValidationError({"arrival_berth_id":f"providing 'arrival_berth_id' is mandatory. Missing key!"})
if not eta >= time_now: if not eta >= time_now:
raise ValidationError({"eta":f"'eta' must be in the future. Incorrect datetime provided."}) raise ValidationError({"eta":f"'eta' is too far in the past. Incorrect datetime provided."})
elif int(type_)==int(ShipcallType.departure): elif int(type_)==int(ShipcallType.departure):
etd = loadedModel.get("etd") etd = loadedModel.get("etd")
if (content.get("etd", None) is None): if (content.get("etd", None) is None):
@ -93,7 +93,7 @@ def validate_posted_shipcall_data(user_data:dict, loadedModel:dict, content:dict
if content.get("departure_berth_id", None) is None: if content.get("departure_berth_id", None) is None:
raise ValidationError({"departure_berth_id":f"providing 'departure_berth_id' is mandatory. Missing key!"}) raise ValidationError({"departure_berth_id":f"providing 'departure_berth_id' is mandatory. Missing key!"})
if not etd >= time_now: if not etd >= time_now:
raise ValidationError({"etd":f"'etd' must be in the future. Incorrect datetime provided."}) raise ValidationError({"etd":f"'etd' is too far in the past. Incorrect datetime provided."})
elif int(type_)==int(ShipcallType.shifting): elif int(type_)==int(ShipcallType.shifting):
eta = loadedModel.get("eta") eta = loadedModel.get("eta")
etd = loadedModel.get("etd") etd = loadedModel.get("etd")
@ -103,17 +103,17 @@ def validate_posted_shipcall_data(user_data:dict, loadedModel:dict, content:dict
if (content.get("arrival_berth_id", None) is None) or (content.get("departure_berth_id", None) is None): if (content.get("arrival_berth_id", None) is None) or (content.get("departure_berth_id", None) is None):
raise ValidationError({"arrival_berth_id_or_departure_berth_id":f"providing 'arrival_berth_id' & 'departure_berth_id' is mandatory. Missing key!"}) raise ValidationError({"arrival_berth_id_or_departure_berth_id":f"providing 'arrival_berth_id' & 'departure_berth_id' is mandatory. Missing key!"})
if (not eta >= time_now) or (not etd >= time_now) or (not eta >= etd): if (not eta >= time_now) or (not etd >= time_now) or (not eta >= etd):
raise ValidationError({"eta_or_etd":f"'eta' and 'etd' must be in the future. Incorrect datetime provided."}) raise ValidationError({"eta_or_etd":f"'eta' and 'etd' are too far in the past. Incorrect datetime provided."})
tidal_window_from = loadedModel.get("tidal_window_from", None) tidal_window_from = loadedModel.get("tidal_window_from", None)
tidal_window_to = loadedModel.get("tidal_window_to", None) tidal_window_to = loadedModel.get("tidal_window_to", None)
if tidal_window_to is not None: if tidal_window_to is not None:
if not tidal_window_to >= time_now: if not tidal_window_to >= time_now:
raise ValidationError({"tidal_window_to":f"'tidal_window_to' must be in the future. Incorrect datetime provided."}) raise ValidationError({"tidal_window_to":f"'tidal_window_to' is too far in the past. Incorrect datetime provided."})
if tidal_window_from is not None: if tidal_window_from is not None:
if not tidal_window_from >= time_now: if not tidal_window_from >= time_now:
raise ValidationError({"tidal_window_from":f"'tidal_window_from' must be in the future. Incorrect datetime provided."}) raise ValidationError({"tidal_window_from":f"'tidal_window_from' is too far in the past. Incorrect datetime provided."})
# #TODO: assert tidal_window_from > tidal_window_to # #TODO: assert tidal_window_from > tidal_window_to

View File

@ -124,11 +124,14 @@ class InputValidationShipcall():
if check_if_int_is_valid_flag(flags_value, enum_object=ParticipantFlag): if check_if_int_is_valid_flag(flags_value, enum_object=ParticipantFlag):
raise ValidationError({"flags":f"incorrect value provided for 'flags'. Must be a valid combination of the flags."}) raise ValidationError({"flags":f"incorrect value provided for 'flags'. Must be a valid combination of the flags."})
existing_shipcall = None
if is_put_data: if is_put_data:
# the type of a shipcall may not be changed. It can only be set with the initial POST-request.
InputValidationShipcall.check_shipcall_type_is_unchanged(loadedModel)
InputValidationShipcall.check_times_are_in_future(loadedModel, content) existing_shipcall = InputValidationShipcall.get_shipcall_by_id(loadedModel.get("id"))
# the type of a shipcall may not be changed. It can only be set with the initial POST-request.
InputValidationShipcall.check_shipcall_type_is_unchanged(loadedModel, existing_shipcall)
InputValidationShipcall.check_times_are_in_future(loadedModel, content, existing_shipcall)
# some arguments must not be provided # some arguments must not be provided
InputValidationShipcall.check_forbidden_arguments(content, forbidden_keys=forbidden_keys) InputValidationShipcall.check_forbidden_arguments(content, forbidden_keys=forbidden_keys)
@ -255,15 +258,17 @@ class InputValidationShipcall():
raise ValidationError({"participants":f"every participant id and type should be listed only once. Found multiple entries for one of the participants."}) raise ValidationError({"participants":f"every participant id and type should be listed only once. Found multiple entries for one of the participants."})
@staticmethod @staticmethod
def check_shipcall_type_is_unchanged(loadedModel:dict): def check_shipcall_type_is_unchanged(loadedModel:dict, existing_shipcall:object):
# the type of a shipcall may only be set on POST requests. Afterwards, shipcall types may not be changed. if int(loadedModel["type"]) != int(existing_shipcall.type):
query = SQLQuery.get_shipcall_by_id()
shipcall = execute_sql_query_standalone(query=query, model=Shipcall, param={"id":loadedModel.get("id")}, command_type="single")
if int(loadedModel["type"]) != int(shipcall.type):
raise ValidationError({"type":f"The shipcall type may only be set in the initial POST-request. Afterwards, changing the shipcall type is not allowed."}) # @pytest.raises raise ValidationError({"type":f"The shipcall type may only be set in the initial POST-request. Afterwards, changing the shipcall type is not allowed."}) # @pytest.raises
return return
@staticmethod
def get_shipcall_by_id(shipcall_id:int):
query = SQLQuery.get_shipcall_by_id()
shipcall = execute_sql_query_standalone(query=query, model=Shipcall, param={"id":shipcall_id}, command_type="single")
return shipcall
@staticmethod @staticmethod
def check_forbidden_arguments(content:dict, forbidden_keys=["evaluation", "evaluation_message"]): def check_forbidden_arguments(content:dict, forbidden_keys=["evaluation", "evaluation_message"]):
""" """
@ -324,13 +329,13 @@ class InputValidationShipcall():
return return
@staticmethod @staticmethod
def check_times_are_in_future(loadedModel:dict, content:dict): def check_times_are_in_future(loadedModel:dict, content:dict, existing_shipcall:object):
""" """
Dates should be in the future. Depending on the ShipcallType, specific values should be checked Dates should be in the future. Depending on the ShipcallType, specific values should be checked
Perfornms datetime checks in the loadedModel (datetime.datetime objects). Performs datetime checks in the loadedModel (datetime.datetime objects).
""" """
# obtain the current datetime to check, whether the provided values are in the future # obtain the current datetime to check, whether the provided values are after ref time
time_now = datetime.datetime.now() time_ref = datetime.datetime.now() - datetime.timedelta(days=1)
type_ = loadedModel.get("type", ShipcallType.undefined.name) type_ = loadedModel.get("type", ShipcallType.undefined.name)
if isinstance(type_, str): # convert the name string to a ShipcallType data model if isinstance(type_, str): # convert the name string to a ShipcallType data model
@ -346,16 +351,29 @@ class InputValidationShipcall():
etd = loadedModel.get("etd") etd = loadedModel.get("etd")
tidal_window_from = loadedModel.get("tidal_window_from", None) tidal_window_from = loadedModel.get("tidal_window_from", None)
tidal_window_to = loadedModel.get("tidal_window_to", None) tidal_window_to = loadedModel.get("tidal_window_to", None)
existing_eta = None
existing_etd = None
existing_tidal_window_from = None
existing_tidal_window_to = None
# Estimated arrival or departure times if existing_shipcall is not None:
InputValidationShipcall.check_times_in_future_based_on_type(type_, time_now, eta, etd) existing_eta = existing_shipcall.eta
existing_etd = existing_shipcall.etd
existing_tidal_window_from = existing_shipcall.tidal_window_from
existing_tidal_window_to = existing_shipcall.tidal_window_to
if eta != existing_eta or etd != existing_etd:
# Estimated arrival or departure times
InputValidationShipcall.check_times_in_future_based_on_type(type_, time_ref, eta, etd)
if tidal_window_from != existing_tidal_window_from or tidal_window_to != existing_tidal_window_to:
# Tidal Window
InputValidationShipcall.check_tidal_window_in_future(type_, time_ref, tidal_window_from, tidal_window_to)
# Tidal Window
InputValidationShipcall.check_tidal_window_in_future(type_, time_now, tidal_window_from, tidal_window_to)
return return
@staticmethod @staticmethod
def check_times_in_future_based_on_type(type_, time_now, eta, etd): def check_times_in_future_based_on_type(type_, time_ref, eta, etd):
""" """
checks, whether the ETA & ETD times are in the future. checks, whether the ETA & ETD times are in the future.
based on the type, this function checks: based on the type, this function checks:
@ -366,7 +384,7 @@ class InputValidationShipcall():
if (eta is None) and (etd is None): if (eta is None) and (etd is None):
return return
time_in_a_year = time_now.replace(time_now.year + 1) time_in_a_year = datetime.datetime.now().replace(datetime.datetime.now().year + 1)
if type_ is None: if type_ is None:
raise ValidationError({"type":f"when providing 'eta' or 'etd', one must provide the type of the shipcall, so the datetimes can be verified."}) raise ValidationError({"type":f"when providing 'eta' or 'etd', one must provide the type of the shipcall, so the datetimes can be verified."})
@ -381,8 +399,8 @@ class InputValidationShipcall():
if eta is None: # null values -> no violation if eta is None: # null values -> no violation
return return
if not eta > time_now: if not eta > time_ref:
raise ValidationError({"eta":f"'eta' must be in the future. Incorrect datetime provided. Current Time: {time_now}. ETA: {eta}."}) raise ValidationError({"eta":f"'eta' is too far in the past. Incorrect datetime provided. Current Time: {time_ref}. ETA: {eta}."})
if etd is not None: if etd is not None:
raise ValidationError({"etd":f"'etd' should not be set when the shipcall type is 'arrival'."}) raise ValidationError({"etd":f"'etd' should not be set when the shipcall type is 'arrival'."})
if eta > time_in_a_year: if eta > time_in_a_year:
@ -392,8 +410,9 @@ class InputValidationShipcall():
if etd is None: # null values -> no violation if etd is None: # null values -> no violation
return return
if not etd > time_now: if not etd > time_ref:
raise ValidationError({"etd":f"'etd' must be in the future. Incorrect datetime provided. Current Time: {time_now}. ETD: {etd}."}) raise ValidationError({"etd":f"'etd' is too far in the past. Incorrect datetime provided. Current Time: {time_ref}. ETD: {etd}."})
if eta is not None: if eta is not None:
raise ValidationError({"eta":f"'eta' should not be set when the shipcall type is 'departure'."}) raise ValidationError({"eta":f"'eta' should not be set when the shipcall type is 'departure'."})
if etd > time_in_a_year: if etd > time_in_a_year:
@ -408,8 +427,8 @@ class InputValidationShipcall():
# rules, a user is only allowed to provide *both* values. # rules, a user is only allowed to provide *both* values.
raise ValidationError({"eta_or_etd":f"For shifting shipcalls one should always provide, both, eta and etd."}) raise ValidationError({"eta_or_etd":f"For shifting shipcalls one should always provide, both, eta and etd."})
if (not eta > time_now) or (not etd > time_now): if (not eta > time_ref) or (not etd > time_ref):
raise ValidationError({"eta_or_etd":f"'eta' and 'etd' must be in the future. Incorrect datetime provided. Current Time: {time_now}. ETA: {eta}. ETD: {etd}"}) raise ValidationError({"eta_or_etd":f"'eta' and 'etd' is too far in the past. Incorrect datetime provided. Current Time: {time_ref}. ETA: {eta}. ETD: {etd}"})
if (not etd < eta): if (not etd < eta):
raise ValidationError({"eta_or_etd":f"The estimated time of departure ('etd') must take place *before the estimated time of arrival ('eta'). The ship cannot arrive, before it has departed. Found: ETD: {etd}, ETA: {eta}"}) raise ValidationError({"eta_or_etd":f"The estimated time of departure ('etd') must take place *before the estimated time of arrival ('eta'). The ship cannot arrive, before it has departed. Found: ETD: {etd}, ETA: {eta}"})
@ -423,19 +442,18 @@ class InputValidationShipcall():
return return
@staticmethod @staticmethod
def check_tidal_window_in_future(type_, time_now, tidal_window_from, tidal_window_to): def check_tidal_window_in_future(type_, time_ref, tidal_window_from, tidal_window_to):
time_in_a_year = time_now.replace(time_now.year + 1)
time_in_a_year = datetime.datetime.now().replace(datetime.datetime.now().year + 1)
if tidal_window_to is not None: if tidal_window_to is not None:
if not tidal_window_to >= time_now: if not tidal_window_to >= time_ref:
raise ValidationError({"tidal_window_to":f"'tidal_window_to' must be in the future. Incorrect datetime provided."}) raise ValidationError({"tidal_window_to":f"'tidal_window_to' is too far in the past. Incorrect datetime provided."})
if tidal_window_to > time_in_a_year: if tidal_window_to > time_in_a_year:
raise ValidationError({"tidal_window_to":f"'tidal_window_to' is more than a year in the future. Found: {tidal_window_to}."}) raise ValidationError({"tidal_window_to":f"'tidal_window_to' is more than a year in the future. Found: {tidal_window_to}."})
if tidal_window_from is not None: if tidal_window_from is not None:
if not tidal_window_from >= time_now: if not tidal_window_from >= time_ref:
raise ValidationError({"tidal_window_from":f"'tidal_window_from' must be in the future. Incorrect datetime provided."}) raise ValidationError({"tidal_window_from":f"'tidal_window_from' is too far in the past. Incorrect datetime provided."})
if tidal_window_from > time_in_a_year: if tidal_window_from > time_in_a_year:
raise ValidationError({"tidal_window_from":f"'tidal_window_from' is more than a year in the future. Found: {tidal_window_from}."}) raise ValidationError({"tidal_window_from":f"'tidal_window_from' is more than a year in the future. Found: {tidal_window_from}."})

View File

@ -414,6 +414,8 @@ class InputValidationTimes():
# commonly used in the PUT-request # commonly used in the PUT-request
if loadedModel is not None: if loadedModel is not None:
(shipcall_id, times_assigned_participant) = InputValidationTimes.prepare_authority_check_for_put_request(loadedModel) (shipcall_id, times_assigned_participant) = InputValidationTimes.prepare_authority_check_for_put_request(loadedModel)
else:
loadedModel = get_times_data_for_id(times_id)
# commonly used in the DELETE-request # commonly used in the DELETE-request
if times_id is not None: if times_id is not None:

View File

@ -226,17 +226,17 @@ def test_shipcall_post_request_fails_when_type_arrival_and_not_in_future(get_stu
# accept # accept
post_data = original_post_data.copy() post_data = original_post_data.copy()
post_data["type"] = ShipcallType.arrival.name post_data["type"] = ShipcallType.arrival.name
post_data["eta"] = (datetime.datetime.now() + datetime.timedelta(hours=3)).isoformat() post_data["eta"] = (datetime.datetime.now() + datetime.timedelta(days=2)).isoformat()
response = requests.post(f"{url}/shipcalls", headers={"Content-Type":"text", "Authorization":f"Bearer {token}"}, json=post_data) response = requests.post(f"{url}/shipcalls", headers={"Content-Type":"text", "Authorization":f"Bearer {token}"}, json=post_data)
assert response.status_code == 201 assert response.status_code == 201
# error # error
post_data = original_post_data.copy() post_data = original_post_data.copy()
post_data["type"] = ShipcallType.arrival.name post_data["type"] = ShipcallType.arrival.name
post_data["eta"] = (datetime.datetime.now() - datetime.timedelta(hours=3)).isoformat() post_data["eta"] = (datetime.datetime.now() - datetime.timedelta(days=2)).isoformat()
response = requests.post(f"{url}/shipcalls", headers={"Content-Type":"text", "Authorization":f"Bearer {token}"}, json=post_data) response = requests.post(f"{url}/shipcalls", headers={"Content-Type":"text", "Authorization":f"Bearer {token}"}, json=post_data)
with pytest.raises(ValidationError, match="must be in the future. Incorrect datetime provided"): with pytest.raises(ValidationError, match="is too far in the past. Incorrect datetime provided"):
assert response.status_code==400 assert response.status_code==400
raise ValidationError(response.json()) raise ValidationError(response.json())
return return
@ -256,10 +256,10 @@ def test_shipcall_post_request_fails_when_type_departure_and_not_in_future(get_s
# error # error
post_data = original_post_data.copy() post_data = original_post_data.copy()
post_data["type"] = ShipcallType.departure.name post_data["type"] = ShipcallType.departure.name
post_data["etd"] = (datetime.datetime.now() - datetime.timedelta(hours=3)).isoformat() post_data["etd"] = (datetime.datetime.now() - datetime.timedelta(days=3)).isoformat()
response = requests.post(f"{url}/shipcalls", headers={"Content-Type":"text", "Authorization":f"Bearer {token}"}, json=post_data) response = requests.post(f"{url}/shipcalls", headers={"Content-Type":"text", "Authorization":f"Bearer {token}"}, json=post_data)
with pytest.raises(ValidationError, match="must be in the future. Incorrect datetime provided"): with pytest.raises(ValidationError, match="is too far in the past. Incorrect datetime provided"):
assert response.status_code==400 assert response.status_code==400
raise ValidationError(response.json()) raise ValidationError(response.json())
return return
@ -280,11 +280,11 @@ def test_shipcall_post_request_fails_when_type_shifting_and_not_in_future(get_st
# error # error
post_data = original_post_data.copy() post_data = original_post_data.copy()
post_data["type"] = ShipcallType.shifting.name post_data["type"] = ShipcallType.shifting.name
post_data["etd"] = (datetime.datetime.now() - datetime.timedelta(hours=3)).isoformat() post_data["etd"] = (datetime.datetime.now() - datetime.timedelta(days=3)).isoformat()
post_data["eta"] = (datetime.datetime.now() + datetime.timedelta(hours=3,minutes=1)).isoformat() post_data["eta"] = (datetime.datetime.now() + datetime.timedelta(hours=3,minutes=1)).isoformat()
response = requests.post(f"{url}/shipcalls", headers={"Content-Type":"text", "Authorization":f"Bearer {token}"}, json=post_data) response = requests.post(f"{url}/shipcalls", headers={"Content-Type":"text", "Authorization":f"Bearer {token}"}, json=post_data)
with pytest.raises(ValidationError, match="must be in the future. Incorrect datetime provided"): with pytest.raises(ValidationError, match="is too far in the past. Incorrect datetime provided"):
assert response.status_code==400 assert response.status_code==400
raise ValidationError(response.json()) raise ValidationError(response.json())
return return