ENI-2 Version Work in Progress mit der Validierung, einige kleinere Korrekturen

This commit is contained in:
Daniel Schick 2017-09-11 18:59:11 +00:00
parent f8a9ad6be6
commit 707b5c9179
38 changed files with 593 additions and 163 deletions

View File

@ -32,6 +32,7 @@ namespace ENI2
private Dictionary<Object, Message.NotificationClass> _controlClassDict = new Dictionary<object, Message.NotificationClass>();
private Dictionary<Message.NotificationClass, Message> _typeMessageDict = new Dictionary<Message.NotificationClass, Message>();
private List<Message> _controlMessages = new List<Message>();
#endregion
@ -56,10 +57,15 @@ namespace ENI2
public event Action<int> JumpToListElementRequest;
/// <summary>
/// Mit diesem Event kann ein Listen-Element einen Reload der gesamten Anmeldung auslösen (ob das so eine tolle Idee ist.)
/// Mit diesem Event kann ein Listen-Element einen Reload der gesamten Anmeldung auslösen
/// </summary>
public event Action RequestReload;
/// <summary>
/// Damit kann ein Listenelement eine Validierung der gesamten Anmeldung auslösen (inkl. Highlighting)
/// </summary>
public event Action RequestValidate;
/// <summary>
/// Eine in der Detailansicht enthaltene Meldeklasse hat sich geändert
/// </summary>
@ -132,6 +138,11 @@ namespace ENI2
this.RequestReload?.Invoke();
}
protected virtual void OnRequestValidate()
{
this.RequestValidate?.Invoke();
}
protected virtual void OnControlCacheReset(string messageGroupName)
{
this.ResetControlCache?.Invoke(messageGroupName);

View File

@ -26,11 +26,16 @@ namespace ENI2
private MessageCore _core;
private List<MessageGroup> _listBoxList = new List<MessageGroup>();
private List<Message> _messages;
private Dictionary<string, DetailBaseControl> controlCache = new Dictionary<string, DetailBaseControl>();
private Dictionary<string, DetailBaseControl> controlCache = new Dictionary<string, DetailBaseControl>();
private Dictionary<Message.NotificationClass, string> messageClassControlDict = new Dictionary<Message.NotificationClass, string>();
private Guid userId = Guid.NewGuid(); // remove THIS!!
private object messageListLock = new object();
private HighlightService highlightService = new HighlightService();
// Validation
protected List<MessageError> _vErrors = new List<MessageError>();
protected List<MessageViolation> _vViolations = new List<MessageViolation>();
#endregion
#region Properties
@ -128,6 +133,7 @@ namespace ENI2
detailControl.RequestReload += DetailControl_RequestReload;
detailControl.NotificationClassChanged += DetailControl_NotificationClassChanged;
detailControl.ResetControlCache += DetailControl_ResetControlCache;
detailControl.RequestValidate += DetailControl_RequestValidate;
detailControl.Initialize();
detailControl.IsEnabled = !this.LockedByOtherUser;
@ -159,7 +165,7 @@ namespace ENI2
detailView.Children.Add(controlCache[mg.MessageGroupName]);
}
}
}
private void DetailControl_ResetControlCache(string messageGroupName)
{
@ -284,14 +290,115 @@ namespace ENI2
// if the entity has been highlighted (through remote change detection), reset this here
this.OnHighlightReset();
}
}
private void DetailControl_RequestValidate()
{
this._vErrors.Clear();
this._vViolations.Clear();
// TODO: clear highlighting
RuleEngine ruleEngine = new RuleEngine();
foreach (Message aMessage in _messages)
{
List<MessageError> errors = new List<MessageError>();
List<MessageViolation> violations = new List<MessageViolation>();
ruleEngine.ValidateMessage(aMessage, out errors, out violations);
string messageGroup = this.MessageGroupForMessage(aMessage);
if (messageGroup != null)
{
foreach (MessageError me in errors)
me.MessageGroupName = messageGroup;
foreach (MessageViolation mv in violations)
mv.MessageGroupName = messageGroup;
}
this._vErrors.AddRange(errors);
this._vViolations.AddRange(violations);
}
foreach (MessageError me in this._vErrors)
{
this.highlightService.HighlightError(me, this.GetContainerForMessageGroupName(me.MessageGroupName));
}
foreach (MessageViolation mv in this._vViolations)
{
this.highlightService.HighlightViolation(mv, this.GetContainerForMessageGroupName(mv.MessageGroupName));
}
}
#endregion
#region private / protected methods
protected virtual void OnHighlightReset()
{
this.HighlightReset?.Invoke(this.Core);
}
private DependencyObject GetContainerForMessageGroupName(string messageGroupName)
{
if (controlCache.ContainsKey(messageGroupName))
return controlCache[messageGroupName];
return null;
}
protected string MessageGroupForMessage(Message mh)
{
if (mh == null) return null;
switch(mh.MessageNotificationClass)
{
case Message.NotificationClass.ATA:
case Message.NotificationClass.TIEFA:
case Message.NotificationClass.POBA:
case Message.NotificationClass.BKRA:
return Properties.Resources.textArrivalNotification;
case Message.NotificationClass.BPOL:
case Message.NotificationClass.CREW:
case Message.NotificationClass.CREWD:
case Message.NotificationClass.PAS:
case Message.NotificationClass.PASD:
return Properties.Resources.textBorderPolice;
case Message.NotificationClass.HAZA:
return Properties.Resources.textDGArrival;
case Message.NotificationClass.HAZD:
return Properties.Resources.textDGDeparture;
case Message.NotificationClass.ATD:
case Message.NotificationClass.TIEFD:
case Message.NotificationClass.POBD:
case Message.NotificationClass.BKRD:
return Properties.Resources.textDepartureNotification;
case Message.NotificationClass.MDH:
return Properties.Resources.textMDH;
case Message.NotificationClass.NOA_NOD:
return Properties.Resources.textOverview;
case Message.NotificationClass.AGNT:
return Properties.Resources.textPortCall;
case Message.NotificationClass.NAME:
case Message.NotificationClass.INFO:
case Message.NotificationClass.SERV:
case Message.NotificationClass.LADG:
return Properties.Resources.textPortNotification;
case Message.NotificationClass.PRE72H:
return Properties.Resources.textPSC72h;
case Message.NotificationClass.SEC:
return Properties.Resources.textSecurity;
case Message.NotificationClass.STAT:
return Properties.Resources.textShipData;
case Message.NotificationClass.TOWA:
case Message.NotificationClass.TOWD:
return Properties.Resources.textTowage;
case Message.NotificationClass.WAS:
return Properties.Resources.textWaste;
}
return null;
}
#endregion
}
}

View File

@ -75,10 +75,10 @@
<CheckBox Name="checkBoxWasMedicalConsulted" IsChecked="{Binding MedicalConsulted}" Grid.Row="8" Grid.Column="3" VerticalAlignment="Center"/>
<CheckBox Name="checkBoxAwareOfConditions" IsChecked="{Binding AwareOfFurtherInfections}" Grid.Row="9" Grid.Column="1" VerticalAlignment="Center"/>
<CheckBox Name="checkBoxStowawaysOnBoard" IsChecked="{Binding StowawaysDetected}" Grid.Row="11" Grid.Column="1" VerticalAlignment="Center"/>
<TextBox Name="textBoxStowawaysJoiningLocation" Grid.Row="11" Grid.RowSpan="3" Grid.Column="3" MaxLength="100" Text="{Binding CSOLastName}" Margin="2" VerticalContentAlignment="Center"/>
<TextBox Name="textBoxStowawaysJoiningLocation" Grid.Row="11" Grid.RowSpan="3" Grid.Column="3" MaxLength="100" Text="{Binding StowawaysJoiningLocationText}" Margin="2" VerticalContentAlignment="Center"/>
<CheckBox Name="checkBoxSickAnimalsOrPets" IsChecked="{Binding SickAnimalOrPetOnBoard}" Grid.Row="12" Grid.Column="1" VerticalAlignment="Center"/>
<CheckBox Name="checkBoxSanitaryControlExemption" IsChecked="{Binding ValidSanitaryControlExemptionOrCertificateOnBoard}" Grid.Row="13" Grid.Column="1" VerticalAlignment="Center"/>
<TextBox Name="textBoxPlaceOfIssue" Grid.Row="14" Grid.Column="1" MaxLength="100" Text="{Binding PlaceOfIssue}" Margin="2" VerticalContentAlignment="Center"/>
<TextBox Name="textBoxPlaceOfIssue" Grid.Row="14" Grid.Column="1" MaxLength="100" Text="{Binding PlaceOfIssue}" Margin="2" />
<DatePicker Name="datePickerDateOfIssue" Grid.Row="14" Grid.Column="3" SelectedDate="{Binding DateOfIssue}" Margin="2" ContextMenu="{DynamicResource ClearContextMenu}" />
<CheckBox Name="checkBoxReinspectionSanitary" IsChecked="{Binding SanitaryControlReinspectionRequired}" Grid.Row="15" Grid.Column="1" VerticalAlignment="Center"/>
</Grid>

View File

@ -66,7 +66,7 @@
<Label HorizontalContentAlignment="Right" Grid.Row="2" Grid.Column="3" Content="{x:Static p:Resources.textETDPortOfCall}" Margin="0,0,10,0" />
<Label HorizontalContentAlignment="Right" Grid.Row="3" Grid.Column="0" Content="{x:Static p:Resources.textATAPortOfCall}" Margin="0,0,10,0" />
<Label HorizontalContentAlignment="Right" Grid.Row="3" Grid.Column="3" Content="{x:Static p:Resources.textATDPortOfCall}" Margin="0,0,10,0" />
<xctk:DateTimePicker Grid.Column="1" Grid.ColumnSpan="2" Grid.Row="2" Value="{Binding ETAToPortOfCall, Mode=TwoWay, Converter={util:UtcToLocalDateTimeConverter}}" Name="dateTimePickerETA" Format="Custom" FormatString="dd.MM.yyyy HH:mm" ShowButtonSpinner="False" VerticalContentAlignment="Center" Margin="2" AllowTextInput="False" ContextMenu="{DynamicResource ClearContextMenu}" TextAlignment="Left"/>
<xctk:DateTimePicker Grid.Column="1" Grid.ColumnSpan="2" Grid.Row="2" Value="{Binding ETAToPortOfCall, Mode=TwoWay, Converter={util:UtcToLocalDateTimeConverter}}" Name="dateTimePickerETA" Format="Custom" FormatString="dd.MM.yyyy HH:mm" ShowButtonSpinner="False" VerticalContentAlignment="Center" Margin="2" AllowTextInput="False" ContextMenu="{DynamicResource ClearContextMenu}" TextAlignment="Left" />
<xctk:DateTimePicker Grid.Column="4" Grid.ColumnSpan="2" Grid.Row="2" Value="{Binding ETDFromPortOfCall, Mode=TwoWay, Converter={util:UtcToLocalDateTimeConverter}}" Name="dateTimePickerETD" Format="Custom" FormatString="dd.MM.yyyy HH:mm" ShowButtonSpinner="False" VerticalContentAlignment="Center" Margin="2" AllowTextInput="False" ContextMenu="{DynamicResource ClearContextMenu}" TextAlignment="Left"/>
<xctk:DateTimePicker Grid.Column="1" Grid.ColumnSpan="2" Grid.Row="3" Value="{Binding ATAPortOfCall, Mode=TwoWay, Converter={util:UtcToLocalDateTimeConverter}}" Name="dateTimePickerATA" Format="Custom" FormatString="dd.MM.yyyy HH:mm" ShowButtonSpinner="False" VerticalContentAlignment="Center" Margin="2" AllowTextInput="False" ContextMenu="{DynamicResource ClearContextMenu}" TextAlignment="Left"/>
<xctk:DateTimePicker Grid.Column="4" Grid.ColumnSpan="2" Grid.Row="3" Value="{Binding ATDPortOfCall, Mode=TwoWay, Converter={util:UtcToLocalDateTimeConverter}}" Name="dateTimePickerATD" Format="Custom" FormatString="dd.MM.yyyy HH:mm" ShowButtonSpinner="False" VerticalContentAlignment="Center" Margin="2" AllowTextInput="False" ContextMenu="{DynamicResource ClearContextMenu}" TextAlignment="Left"/>
@ -95,10 +95,11 @@
<Button Name="buttonInfoCore" Margin="2" Click="buttonInfoCore_Click" BorderThickness="0" Background="Transparent">
<Image Source="../Resources/document_view.png" Margin="0,0,5,0" Height="24" />
</Button>
<!--
<Button Name="buttonErrors" Margin="2" Click="buttonErrors_Click" BorderThickness="0" Background="Transparent" Visibility="Hidden">
<Image Source="../Resources/error.png" Margin="0,0,5,0" Height="24" />
<Button Name="buttonValidate" Margin="2" Click="buttonValidate_Click" BorderThickness="0" Background="Transparent">
<Image Source="../Resources/hand_point.png" Margin="0,0,5,0" Height="24" />
</Button>
<!--
<Button Name="buttonWarnings" Margin="2" Click="buttonWarnings_Click" BorderThickness="0" Background="Transparent" Visibility="Hidden">
<Image Source="../Resources/sign_warning.png" Margin="0,0,5,0" Height="24" />
</Button>

View File

@ -12,6 +12,7 @@ using System.Timers;
using bsmd.database;
using ENI2.EditControls;
using System.Windows.Media.Imaging;
using System.Collections.Generic;
namespace ENI2.DetailViewControls
{
@ -43,7 +44,7 @@ namespace ENI2.DetailViewControls
this.RegisterDateTimePickerChange(this.dateTimePickerATD, Message.NotificationClass.ATD);
this.RegisterDateTimePickerChange(this.dateTimePickerETA, Message.NotificationClass.NOA_NOD);
this.RegisterDateTimePickerChange(this.dateTimePickerETD, Message.NotificationClass.NOA_NOD);
}
}
#region Initialize
@ -63,7 +64,7 @@ namespace ENI2.DetailViewControls
this.labelCreated.Content = this.Core.Created?.ToString();
Binding vtBinding = new Binding();
vtBinding.Source = this.Core;
vtBinding.Source = this.Core;
vtBinding.Path = this.Core.IsTransit ? new PropertyPath("TransitId") : new PropertyPath("VisitId");
vtBinding.Mode = BindingMode.TwoWay;
vtBinding.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
@ -206,7 +207,7 @@ namespace ENI2.DetailViewControls
MenuItem resetItem = new MenuItem();
resetItem.Header = Properties.Resources.textReset;
resetItem.Icon = new Image { Source = new BitmapImage(new Uri("pack://application:,,,/Resources/mail_delete.png")) };
resetItem.Click += new RoutedEventHandler(this.contextResetMessage);
resetItem.Click += new RoutedEventHandler(this.contextResetMessage);
this.dataGridMessages.ContextMenu.Items.Add(resetItem);
MenuItem systemErrorItem = new MenuItem();
@ -317,7 +318,7 @@ namespace ENI2.DetailViewControls
this.dataGridMessages.ItemsSource = this.Messages;
this._initialized = true;
}
}
#endregion
@ -515,7 +516,7 @@ namespace ENI2.DetailViewControls
{
this.OnRequestReload();
}));
}
}
private void buttonInfoCore_Click(object sender, RoutedEventArgs e)
{
@ -523,11 +524,11 @@ namespace ENI2.DetailViewControls
spvd.IsModal = false;
spvd.DisplayObject = this.Core;
spvd.Show();
}
}
private void buttonErrors_Click(object sender, RoutedEventArgs e)
{
if(this.dataGridMessages.SelectedItems.Count > 0)
if (this.dataGridMessages.SelectedItems.Count > 0)
{
Message selectedMessage = this.dataGridMessages.SelectedItems[0] as Message;
ErrorListDialog eld = new ErrorListDialog();
@ -558,6 +559,11 @@ namespace ENI2.DetailViewControls
}
}
private void buttonValidate_Click(object sender, RoutedEventArgs e)
{
this.OnRequestValidate();
}
#endregion
}

View File

@ -35,7 +35,7 @@
<MinimumRequiredVersion>3.5.1.0</MinimumRequiredVersion>
<CreateWebPageOnPublish>true</CreateWebPageOnPublish>
<WebPage>publish.html</WebPage>
<ApplicationRevision>2</ApplicationRevision>
<ApplicationRevision>3</ApplicationRevision>
<ApplicationVersion>3.6.15.%2a</ApplicationVersion>
<UseApplicationTrust>false</UseApplicationTrust>
<CreateDesktopShortcut>true</CreateDesktopShortcut>
@ -317,6 +317,7 @@
<Compile Include="Util\InverseBooleanConverter.cs" />
<Compile Include="Util\NullImageConverter.cs" />
<Compile Include="Util\UtcToLocalDateTimeConverter.cs" />
<Compile Include="Util\ValidationContext.cs" />
<Compile Include="VorgaengeControl.xaml.cs">
<DependentUpon>VorgaengeControl.xaml</DependentUpon>
</Compile>

View File

@ -38,7 +38,7 @@
<Label Name="labelPortOfDischarge" Grid.Row="4" Grid.Column="3" Content="{x:Static p:Resources.textPortOfDischarge}" HorizontalContentAlignment="Right" />
<TextBox Grid.Row="0" Grid.Column="1" Grid.ColumnSpan="2" Name="textBoxIdentifier" IsReadOnly ="True" MaxLength="40" Margin="2" VerticalContentAlignment="Center"/>
<TextBox Grid.Row="1" Grid.Column="1" Grid.ColumnSpan="3" Name="textBoxProductName" MaxLength="255" Margin="2" VerticalContentAlignment="Center" />
<TextBox Grid.Row="1" Grid.Column="1" Grid.ColumnSpan="3" Name="textBoxProductName" MaxLength="255" Margin="2" VerticalContentAlignment="Top" />
<TextBox Grid.Row="2" Grid.Column="1" Name="textBoxUNNumber" MaxLength="4" Margin="2" VerticalContentAlignment="Center" />
<TextBox Grid.Row="2" Grid.Column="4" Name="textBoxIMOClass" MaxLength="4" Margin="2" VerticalContentAlignment="Center" />
<xctk:DoubleUpDown Name="doubleUpDownQuantity" Grid.Row="3" Grid.Column="1" Margin="2" FormatString="N3" ShowButtonSpinner="False" TextAlignment="Left"/>

View File

@ -20,7 +20,7 @@
</Grid.ColumnDefinitions>
<Label Grid.Row="0" Grid.Column="0" Content="{x:Static p:Resources.textPortname}" />
<Label Grid.Row="1" Grid.Column="0" Content="{x:Static p:Resources.textETA}" />
<enictrl:LocodeControl Grid.Column="1" Grid.Row="0" x:Name="locodeControlPortName" />
<TextBox Grid.Column="1" Grid.Row="0" x:Name="textBoxPortName" MaxLength="100" Margin="2" VerticalContentAlignment="Center" />
<xctk:DateTimePicker Name="dateTimePickerETA" Grid.Column="1" Grid.Row="1" Margin="2" ShowButtonSpinner="False" Format="Custom" FormatString="dd.MM.yyyy HH:mm" VerticalContentAlignment="Center" TextAlignment="Left"/>
</Grid>

View File

@ -21,7 +21,7 @@ namespace ENI2.EditControls
InitializeComponent();
Loaded += EditPortOfItineraryDialog_Loaded; ;
AddClicked += () => { this.locodeControlPortName.Focus(); };
AddClicked += () => { this.textBoxPortName.Focus(); };
}
@ -32,7 +32,7 @@ namespace ENI2.EditControls
this.OKClicked += EditPortOfItineraryDialog_OKClicked;
// copy into fields
this.locodeControlPortName.LocodeValue = this.PortOfItinerary.PortOfItineraryLocode;
this.textBoxPortName.Text = this.PortOfItinerary.PortOfItineraryLocode;
this.dateTimePickerETA.Value = this.PortOfItinerary.PortOfItineraryETA.HasValue ? ((DateTime?) DateTime.SpecifyKind(this.PortOfItinerary.PortOfItineraryETA.Value, DateTimeKind.Utc).ToLocalTime()) : null;
this.AddVisible = true;
}
@ -40,7 +40,7 @@ namespace ENI2.EditControls
public void CopyValuesToEntity()
{
// copy back
this.PortOfItinerary.PortOfItineraryLocode = this.locodeControlPortName.LocodeValue;
this.PortOfItinerary.PortOfItineraryLocode = this.textBoxPortName.Text;
this.PortOfItinerary.PortOfItineraryName = this.PortOfItinerary.PortOfItineraryLocode.IsNullOrEmpty() ? "" : LocodeDB.PortNameFromLocode(this.PortOfItinerary.PortOfItineraryLocode);
this.PortOfItinerary.PortOfItineraryETA = this.dateTimePickerETA.Value.HasValue ? ((DateTime?)DateTime.SpecifyKind(this.dateTimePickerETA.Value.Value, DateTimeKind.Local).ToUniversalTime()) : null;
}

View File

@ -7,10 +7,10 @@
xmlns:enictrl="clr-namespace:ENI2.Controls"
xmlns:p="clr-namespace:ENI2.Properties"
mc:Ignorable="d"
Title="{x:Static p:Resources.textServ}" Height="270" Width="400" WindowStyle="SingleBorderWindow" Background="AliceBlue">
Title="{x:Static p:Resources.textServ}" Height="326" Width="400" WindowStyle="SingleBorderWindow" Background="AliceBlue">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="28" />
<RowDefinition Height="84" />
<RowDefinition Height="84" />
<RowDefinition Height="84" />
</Grid.RowDefinitions>
@ -21,7 +21,7 @@
<Label Name="labelServiceName" Grid.Row="0" Grid.Column="0" Content="{x:Static p:Resources.textServiceName}" />
<Label Name="labelServiceBeneficiary" Grid.Row="1" Grid.Column="0" Content="{x:Static p:Resources.textServiceBeneficiary}" />
<Label Name="labelServiceInvoiceRecipient" Grid.Row="2" Grid.Column="0" Content="{x:Static p:Resources.textServiceInvoiceRecipient}" />
<TextBox Grid.Row="0" Grid.Column="1" Width="auto" Name="textBoxServiceName" Margin="2" MinLines="2" MaxLength="100" VerticalContentAlignment="Center" />
<TextBox Grid.Row="0" Grid.Column="1" Width="auto" Name="textBoxServiceName" Margin="2" MinLines="2" MaxLength="100" AcceptsReturn="True" TextWrapping="Wrap" />
<TextBox Grid.Row="1" Grid.Column="1" Width="auto" Name="textBoxServiceBeneficiary" Margin="2" MinLines="2" TextWrapping="Wrap" AcceptsReturn="True" MaxLength="100" />
<TextBox Grid.Row="2" Grid.Column="1" Width="auto" Name="textBoxServiceInvoiceRecipient" Margin="2" MinLines="2" TextWrapping="Wrap" AcceptsReturn="True" MaxLength="100" />
</Grid>

View File

@ -52,7 +52,7 @@
<xctk:IntegerUpDown Grid.Row="2" Grid.Column="4" Name="integerUpDownGrossTonnage" Margin="2" ShowButtonSpinner="False" TextAlignment="Left"/>
<xctk:DoubleUpDown Grid.Row="3" Grid.Column="1" Name="doubleUpDownLength" Margin="2" ShowButtonSpinner="False" FormatString="N2" TextAlignment="Left"/>
<xctk:DoubleUpDown Grid.Row="3" Grid.Column="4" Name="doubleUpDownBeam" Margin="2" ShowButtonSpinner="False" FormatString="N2" TextAlignment="Left"/>
<TextBox Grid.Row="4" Grid.Column="1" Width="auto" Name="textBoxRemarks" Margin="2" MaxLength="100" VerticalContentAlignment="Center"/>
<TextBox Grid.Row="4" Grid.Column="1" Width="auto" Name="textBoxRemarks" Margin="2" MaxLength="100" VerticalContentAlignment="Top"/>
<TextBlock Text="Operator" FontWeight="Bold" FontSize="10" Grid.Row="5" Grid.Column="0" Margin="10,0,0,0" />

View File

@ -5,6 +5,7 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
@ -12,12 +13,17 @@ using System.Windows;
using System.Windows.Controls;
using bsmd.database;
using System.Windows.Media;
namespace ENI2.Util
{
public class HighlightService
{
private static ControlTemplate groupBoxDefaultTemplate;
private static Brush dtPickerDefaultColor;
private static Brush textBoxDefaultColor;
private static Brush intUpDownDefaultColor;
private static Brush doubleUpDownDefaultColor;
#region Construction
@ -46,7 +52,7 @@ namespace ENI2.Util
public delegate void HighlightChangeNotificationHandler(Message relevantMessage, DatabaseEntity subElement, string identifier);
public event HighlightChangeNotificationHandler PropertyHighlightingChanged;
//public event HighlightChangeNotificationHandler PropertyHighlightingChanged;
#endregion
@ -70,6 +76,24 @@ namespace ENI2.Util
return !theMessage.ErrorList.IsNullOrEmpty();
}
public void HighlightError(MessageError messageError, DependencyObject rootDependency)
{
IList<DependencyObject> dList = ValidationContext.GetDependencyObjectsWithBindingToProperty(rootDependency, messageError.PropertyName);
if (dList.Count > 0)
{
HighlightControl(dList[0], HighlightStyle.ERROR, messageError.MessageHeader);
}
}
public void HighlightViolation(MessageViolation messageViolation, DependencyObject rootDependency)
{
IList<DependencyObject> dList = ValidationContext.GetDependencyObjectsWithBindingToProperty(rootDependency, messageViolation.PropertyName);
if (dList.Count > 0)
{
HighlightControl(dList[0], HighlightStyle.ERROR, messageViolation.MessageHeader);
}
}
#endregion
#region public static methods
@ -110,6 +134,63 @@ namespace ENI2.Util
}
if(control is Xceed.Wpf.Toolkit.DateTimePicker)
{
Xceed.Wpf.Toolkit.DateTimePicker dtPicker = (Xceed.Wpf.Toolkit.DateTimePicker)control;
if (dtPickerDefaultColor == null)
dtPickerDefaultColor = dtPicker.Background;
switch (highlightStyle)
{
case HighlightStyle.ERROR:
dtPicker.Background = new SolidColorBrush(Color.FromArgb(100, 255, 0, 0));
break;
}
}
if(control is TextBox)
{
TextBox textBox = (TextBox)control;
if (textBoxDefaultColor == null)
textBoxDefaultColor = textBox.Background;
switch(highlightStyle)
{
case HighlightStyle.ERROR:
textBox.Background = new SolidColorBrush(Color.FromArgb(150, 255, 0, 0));
break;
}
}
if(control is Xceed.Wpf.Toolkit.IntegerUpDown)
{
Xceed.Wpf.Toolkit.IntegerUpDown integerUpDown = (Xceed.Wpf.Toolkit.IntegerUpDown)control;
if (intUpDownDefaultColor == null)
intUpDownDefaultColor = integerUpDown.Background;
switch (highlightStyle)
{
case HighlightStyle.ERROR:
integerUpDown.Background = new SolidColorBrush(Color.FromArgb(150, 255, 0, 0));
break;
}
}
if(control is Xceed.Wpf.Toolkit.DoubleUpDown)
{
Xceed.Wpf.Toolkit.DoubleUpDown doubleUpDown = (Xceed.Wpf.Toolkit.DoubleUpDown)control;
if (doubleUpDownDefaultColor == null)
doubleUpDownDefaultColor = doubleUpDown.Background;
switch (highlightStyle)
{
case HighlightStyle.ERROR:
doubleUpDown.Background = new SolidColorBrush(Color.FromArgb(150, 255, 0, 0));
break;
}
}

View File

@ -0,0 +1,146 @@
// Copyright (c) 2017 schick Informatik
// Description: Validation / Highlighting helper class
//
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Data;
using System.Windows.Markup.Primitives;
namespace ENI2.Util
{
class ValidationContext
{
private BindingExpression _bindingExpression;
private UIElement _uiElement;
public ValidationContext(BindingExpression bindingExpression, UIElement anUIElement)
{
_bindingExpression = bindingExpression;
_uiElement = anUIElement;
}
#region Properties
public BindingExpression BindingExpression { get { return this._bindingExpression; } }
public UIElement UIElement { get { return this._uiElement; } }
#endregion
#region static creation
/// <summary>
/// Rekursive Funktion mit Reflection
/// </summary>
/// <param name="boundType"></param>
/// <param name="boundPropertyName"></param>
/// <param name="root"></param>
/// <returns></returns>
private static ValidationContext GetBindingForProperty(Type boundType, string boundPropertyName, FrameworkElement root)
{
foreach (FrameworkElement element in LogicalTreeHelper.GetChildren(root).OfType<FrameworkElement>())
{
FieldInfo[] properties = element.GetType().GetFields(BindingFlags.Public | BindingFlags.GetProperty | BindingFlags.FlattenHierarchy); // | BindingFlags.Static
foreach (FieldInfo field in properties)
{
if (field.FieldType == typeof(DependencyProperty))
{
DependencyProperty dp = (DependencyProperty)field.GetValue(null);
if (BindingOperations.IsDataBound(element, dp))
{
BindingExpression bindingExpression = BindingOperations.GetBindingExpression(element, dp);
if (boundType == bindingExpression.DataItem.GetType())
{
if (boundPropertyName == bindingExpression.ParentBinding.Path.Path)
{
return new ValidationContext(bindingExpression, element as UIElement);
}
}
}
}
}
// Not found so check all child elements
ValidationContext bindingContext = GetBindingForProperty(boundType, boundPropertyName, element);
if (bindingContext != null) return bindingContext;
}
return null;
}
#endregion
/// <summary>
/// Gets all dependency objects which has binding to specific property
/// </summary>
/// <param name="dependencyObject"></param>
/// <param name="propertyName"></param>
/// <returns></returns>
public static IList<DependencyObject> GetDependencyObjectsWithBindingToProperty(DependencyObject dependencyObject, string propertyName)
{
var list = new List<DependencyObject>();
ValidationContext.GetDependencyObjectsWithBindingToPropertyRecursive(propertyName, dependencyObject, list);
return list;
}
/// <summary>
///
/// </summary>
/// <param name="propertyName"></param>
/// <param name="dependencyObject"></param>
/// <param name="sources"></param>
/// <remarks>
/// Based on ASanch answer on http://stackoverflow.com/questions/3959421/wpf-find-control-that-binds-to-specific-property
/// </remarks>>
private static void GetDependencyObjectsWithBindingToPropertyRecursive(string propertyName, DependencyObject dependencyObject,
ICollection<DependencyObject> sources)
{
var dependencyProperties = new List<DependencyProperty>();
dependencyProperties.AddRange(MarkupWriter.GetMarkupObjectFor(dependencyObject).Properties.Where(x => x.DependencyProperty != null).Select(x => x.DependencyProperty).ToList());
dependencyProperties.AddRange(MarkupWriter.GetMarkupObjectFor(dependencyObject).Properties.Where(x => x.IsAttached && x.DependencyProperty != null).Select(x => x.DependencyProperty).ToList());
var bindings = dependencyProperties.Select(x => BindingOperations.GetBindingBase(dependencyObject, x)).Where(x => x != null).ToList();
Predicate<Binding> condition = binding => binding != null && binding.Path.Path == propertyName && !sources.Contains(dependencyObject);
foreach (var bindingBase in bindings)
{
if (bindingBase is Binding)
{
if (condition(bindingBase as Binding))
sources.Add(dependencyObject);
}
else if (bindingBase is MultiBinding)
{
if (((MultiBinding)bindingBase).Bindings.Any(bindingBase2 => condition(bindingBase2 as Binding)))
{
sources.Add(dependencyObject);
}
}
else if (bindingBase is PriorityBinding)
{
if (((PriorityBinding)bindingBase).Bindings.Any(bindingBase2 => condition(bindingBase2 as Binding)))
{
sources.Add(dependencyObject);
}
}
}
var children = LogicalTreeHelper.GetChildren(dependencyObject).OfType<DependencyObject>().ToList();
if (children.Count == 0)
return;
foreach (var child in children)
{
GetDependencyObjectsWithBindingToPropertyRecursive(propertyName, child, sources);
}
}
}
}

Binary file not shown.

View File

@ -0,0 +1,20 @@
insert into ViolationText (ViolationCode, ViolationText) VALUES (804, 'As the flashpoint is below 60 degree, the temperature has to be provided')
insert into ViolationText (ViolationCode, ViolationText) VALUES (802, 'At least one of net weight, gross weight or volume of the dangerous good has to be provided.')
insert into ViolationText (ViolationCode, ViolationText) VALUES (808, 'At least one information about general cargo, container identification or vehicle identification has to be provided')
insert into ViolationText (ViolationCode, ViolationText) VALUES (721, 'For Cargo Code 11, 12, 16 and 19 the quantity must be provided')
insert into ViolationText (ViolationCode, ViolationText) VALUES (703, 'At least one of portlocode or portname in combination with portcountry has to be provided')
insert into ViolationText (ViolationCode, ViolationText) VALUES (767, 'The names of the crew members that have joined the ship have to be provided')
insert into ViolationText (ViolationCode, ViolationText) VALUES (741, 'The additional information for tankers is not provided')
insert into ViolationText (ViolationCode, ViolationText) VALUES (704, 'The provided port of call is not in the list of German seaports')
insert into ViolationText (ViolationCode, ViolationText) VALUES (702, 'The reason for a missing certificates is not provided')
insert into ViolationText (ViolationCode, ViolationText) VALUES (701, 'The location for the ship-to-ship acitivities during last ten called port facilities is not provided')
insert into ViolationText (ViolationCode, ViolationText) VALUES (821, 'ISM Company information has to be provided')
insert into ViolationText (ViolationCode, ViolationText) VALUES (781, 'A description text is required for waste of types 3,8 and 9')
insert into ErrorText (ErrorCode, ErrorText) Values (121, 'Departure time {0} before arrival time')
insert into ErrorText (ErrorCode, ErrorText) Values (11, 'List {0} may not be empty')
--update ErrorText set ErrorText = 'Departure time {0} before arrival time' where id='F7164CE5-E396-46F8-BF97-6CA575FAB15C'
select * from ErrorText order by ErrorCode

View File

@ -231,7 +231,7 @@ namespace bsmd.database
{
if (this.FlashpointInformation.HasValue && (this.FlashpointInformation.Value == 2) &&
this.Flashpoint_CEL.IsNullOrEmpty())
violations.Add(RuleEngine.CreateViolation(ValidationCode.V804, "flashpoint information missing", null));
violations.Add(RuleEngine.CreateViolation(ValidationCode.V804, "Flashpoint_CEL", null, this.Title, this.Identifier));
}
#endregion

View File

@ -395,12 +395,10 @@ namespace bsmd.database
{
if (!this.NetQuantity_KGM.HasValue && !this.GrossQuantity_KGM.HasValue && !this.Volume_MTQ.HasValue)
violations.Add(RuleEngine.CreateViolation(ValidationCode.V802,
"at least on of NetQuantity, Grossquantity or Volume_MTQ has to be provided", null));
violations.Add(RuleEngine.CreateViolation(ValidationCode.V802, null, null, this.Title, this.Identifier));
if ((this.GeneralCargoIBC ?? false) && this.ContainerNumber.IsNullOrEmpty() && this.VehicleLicenseNumber.IsNullOrEmpty())
violations.Add(RuleEngine.CreateViolation(ValidationCode.V808,
"at least Container number or Vehicle license number has to be provided for GeneralCargoIBC", null));
violations.Add(RuleEngine.CreateViolation(ValidationCode.V808, null, null, this.Title, this.Identifier));
foreach (SubsidiaryRisks sr in this.SubsidiaryRiskList)
RuleEngine.ValidateProperties(sr, errors);

View File

@ -159,45 +159,7 @@ namespace bsmd.database
return result;
}
#endregion
#region Validation
public override void Validate(List<MessageError> errors, List<MessageViolation> violations)
{
_log.InfoFormat("rule checking port area {0}", this.PortArea ?? "");
if (!this.PortArea.IsNullOrEmpty())
{
string key = this.MessageCore.PoC + this.PortArea;
bool hasValue = DBManager.Instance.GetPortAreaDict().ContainsKey(key);
if (!hasValue)
{
_log.WarnFormat("No port area entry found: PoC {0}, area {1}", this.MessageCore.PoC ?? "", this.PortArea ?? "");
if(this.MessageCore.PoC == null)
{
foreach (PortArea pa in DBManager.Instance.GetPortAreaDict().Values)
{
if (this.PortArea.Equals(pa.Code))
{
hasValue = true;
_log.InfoFormat("PoC null but port area found: {0} {1} {2}", pa.Name, pa.Country, pa.Port);
break;
}
}
}
if (!hasValue) {
_log.WarnFormat("creating violation for invalid port area {0}", this.PortArea ?? "");
violations.Add(RuleEngine.CreateViolation(ValidationCode.PORTAREA,
string.Format("{0} is not in the list of valid port areas", this.PortArea),
null));
}
}
}
}
#endregion
#endregion
}
}

View File

@ -213,7 +213,7 @@ namespace bsmd.database
(this.CargoCodeNST.Equals("11") || this.CargoCodeNST.Equals("12") || this.CargoCodeNST.Equals("16") ||
this.CargoCodeNST.Equals("19")) &&
!this.CargoNumberOfItems.HasValue)
violations.Add(RuleEngine.CreateViolation(ValidationCode.V721, "If cargo code is 11/12/16/19 number of items must be given!", null));
violations.Add(RuleEngine.CreateViolation(ValidationCode.V721, "CargoNumberOfItems" , null, this.Title, this.Identifier));
}
#endregion

View File

@ -158,7 +158,7 @@ namespace bsmd.database
{
string val = string.Format("LoCode:{0} Port:{1} Country:{2}", this.PortFacilityPortLoCode ?? "", this.PortFacilityPortName ?? "",
this.PortFacilityPortCountry ?? "");
RuleEngine.CreateViolation(ValidationCode.V703, "Last 10 Port facilities: Either LoCode or Country + Name must be given", val);
RuleEngine.CreateViolation(ValidationCode.V703, null, val, this.Title, this.Identifier);
}
}

View File

@ -162,7 +162,7 @@ namespace bsmd.database
{
if (this.FlashpointInformation.HasValue && (this.FlashpointInformation.Value == 2) &&
this.Flashpoint_CEL.IsNullOrEmpty())
violations.Add(RuleEngine.CreateViolation(ValidationCode.V804, "flashpoint information missing", null));
violations.Add(RuleEngine.CreateViolation(ValidationCode.V804, "Flashpoint_CEL", null, this.Title, this.Identifier));
}
#endregion

View File

@ -11,6 +11,7 @@ using System;
using System.Data;
using System.Data.SqlClient;
using System.Collections.Generic;
using System.Text;
namespace bsmd.database
{
@ -153,6 +154,74 @@ namespace bsmd.database
[LookupName("MDH.InfectedAreaDate_1")]
public DateTime? InfectedAreaDate { get; set; }
/// <summary>
/// Hilfsproperty, um eine kommaseparierte Liste von JoiningLocation (analog ANSW) im ENI-2 anzuzeigen,
/// </summary>
public string StowawaysJoiningLocationText
{
get
{
StringBuilder sb = new StringBuilder();
for (int i = 0; i < this.StowawaysJoiningLocations.Count; i++)
{
if (i > 0)
sb.Append(", ");
sb.Append(this.StowawaysJoiningLocations[i].StowawayJoiningLocation);
}
return sb.ToString();
}
set
{
if (value.IsNullOrEmpty())
{
foreach (StowawaysJoiningLocation wdsp in this.StowawaysJoiningLocations)
DBManager.Instance.Delete(wdsp);
this.StowawaysJoiningLocations.Clear();
}
else
{
string[] joiningLocations = value.Split(',');
List<StowawaysJoiningLocation> foundList = new List<database.StowawaysJoiningLocation>();
for (int i = 0; i < joiningLocations.Length; i++)
{
string jLocation = joiningLocations[i].Trim();
if (jLocation.Length > 0)
{
StowawaysJoiningLocation matchingLocation = null;
foreach (StowawaysJoiningLocation wdsp in this.StowawaysJoiningLocations)
{
if (wdsp.StowawayJoiningLocation.Equals(jLocation, StringComparison.OrdinalIgnoreCase))
{
matchingLocation = wdsp;
break;
}
}
if (matchingLocation != null)
{
foundList.Add(matchingLocation);
this.StowawaysJoiningLocations.Remove(matchingLocation);
}
else
{
StowawaysJoiningLocation newLocation = new StowawaysJoiningLocation();
newLocation.MDH = this;
newLocation.StowawayJoiningLocation = jLocation;
foundList.Add(newLocation);
}
}
}
// remove remaining location (no longer valid)
foreach (StowawaysJoiningLocation remainingLocation in this.StowawaysJoiningLocations)
DBManager.Instance.Delete(remainingLocation);
this.StowawaysJoiningLocations.Clear();
// add existing and new crew
this.StowawaysJoiningLocations.AddRange(foundList);
}
}
}
#endregion
#region abstract method implementation
@ -407,36 +476,36 @@ namespace bsmd.database
if (this.GetValidationBlock() == ValidationBlock.BLOCK1)
{
if (this.PortOfCallWhereCompleteMDHNotified.IsNullOrEmpty())
violations.Add(RuleEngine.CreateViolation(ValidationCode.V768, "PortOfCallWhereCompleteMDHNotified missing", null));
violations.Add(RuleEngine.CreateViolation(ValidationCode.V768, "PortOfCallWhereCompleteMDHNotified missing", null, this.Title, null));
}
else
{
if ((this.NonAccidentalDeathsDuringVoyage ?? false) && ((this.NonAccidentalDeathsDuringVoyageCount ?? 0) == 0))
violations.Add(RuleEngine.CreateViolation(ValidationCode.V761, "NonAccidentalDeathsDuringVoyageCount missing", null));
violations.Add(RuleEngine.CreateViolation(ValidationCode.V761, "NonAccidentalDeathsDuringVoyageCount missing", null, this.Title, null));
if ((this.NumberOfIllPersonsHigherThanExpected ?? false) && ((this.NumberOfIllPersons ?? 0) == 0))
violations.Add(RuleEngine.CreateViolation(ValidationCode.V762, "Number of ill persons missing", null));
violations.Add(RuleEngine.CreateViolation(ValidationCode.V762, "Number of ill persons missing", null, this.Title, null));
if ((this.SanitaryMeasuresApplied ?? false) && (
this.SanitaryMeasuresType.IsNullOrEmpty() ||
!this.SanitaryMeasuresDate.HasValue ||
this.SanitaryMeasuresLocation.IsNullOrEmpty()))
violations.Add(RuleEngine.CreateViolation(ValidationCode.V763, "Sanitary measure details missing", null));
violations.Add(RuleEngine.CreateViolation(ValidationCode.V763, "Sanitary measure details missing", null, this.Title, null));
if ((this.StowawaysDetected ?? false) && this.StowawaysJoiningLocation.IsNullOrEmpty())
violations.Add(RuleEngine.CreateViolation(ValidationCode.V764, "Stowaways joining location missing", null));
violations.Add(RuleEngine.CreateViolation(ValidationCode.V764, "Stowaways joining location missing", null, this.Title, null));
if ((this.ValidSanitaryControlExemptionOrCertificateOnBoard ?? false) &&
(this.PlaceOfIssue.IsNullOrEmpty() || !this.DateOfIssue.HasValue))
violations.Add(RuleEngine.CreateViolation(ValidationCode.V765, "Cert. Place or Date of issue missing", null));
violations.Add(RuleEngine.CreateViolation(ValidationCode.V765, "Cert. Place or Date of issue missing", null, this.Title, null));
if ((this.InfectedAreaVisited ?? false) &&
(!this.InfectedAreaDate.HasValue || this.InfectedAreaPort.IsNullOrEmpty()))
violations.Add(RuleEngine.CreateViolation(ValidationCode.V766, "Infected area date or port missing", null));
violations.Add(RuleEngine.CreateViolation(ValidationCode.V766, "Infected area date or port missing", null, this.Title, null));
if (this.portOfCallLast30Days.Count == 0)
{
errors.Add(RuleEngine.CreateError(ValidationCode.NOT_NULL, "Port of Call last 30 day list is EMPTY", null));
errors.Add(RuleEngine.CreateError(ValidationCode.NOT_NULL, "Port of Call last 30 day list is EMPTY", null, this.Title, null));
}
foreach (PortOfCallLast30Days poc30d in this.portOfCallLast30Days)

View File

@ -32,6 +32,12 @@ namespace bsmd.database
public bool Deleted { get; set; }
public string FullName { get; set; }
public string PropertyName { get; set; }
public string MessageGroupName { get; set; }
#endregion
#region IDatabaseEntity implementation

View File

@ -30,6 +30,12 @@ namespace bsmd.database
public Guid MessageHeaderId { get; set; }
public string FullName { get; set; }
public string PropertyName { get; set; }
public string MessageGroupName { get; set; }
#endregion
#region DatabaseEntity implementation

View File

@ -210,11 +210,11 @@ namespace bsmd.database
{
if(this.ETDFromPortOfCall.HasValue && this.ETAToPortOfCall.HasValue &&
(this.ETDFromPortOfCall < this.ETAToPortOfCall))
errors.Add(RuleEngine.CreateError(ValidationCode.E121, "Departure time before arrival time!", null));
errors.Add(RuleEngine.CreateError(ValidationCode.E121, "ETDFromPortOfCall", this.ETDFromPortOfCall.ToString(), this.Title, null));
if(this.CallPurposes.Count == 0)
{
errors.Add(RuleEngine.CreateError(ValidationCode.NOT_NULL, "Purpose of call missing!", null));
errors.Add(RuleEngine.CreateError(ValidationCode.LIST_EMPTY, null, "CallPurpose", this.Title, null));
}
}
@ -222,18 +222,18 @@ namespace bsmd.database
{
if (this.ETDFromKielCanal.HasValue && this.ETAToKielCanal.HasValue &&
(this.ETDFromKielCanal < this.ETAToKielCanal))
errors.Add(RuleEngine.CreateError(ValidationCode.E123, "Departure time before arrival time!", null));
errors.Add(RuleEngine.CreateError(ValidationCode.E121, "ETDFromKielCanal", this.ETDFromKielCanal.ToString(), this.Title, null));
}
if((this.LastPort != null) && !this.LastPort.Equals("ZZUKN") && !this.ETDFromLastPort.HasValue)
errors.Add(RuleEngine.CreateError(ValidationCode.E125, "ETD last port must be set!", null));
errors.Add(RuleEngine.CreateError(ValidationCode.NOT_NULL, "ETDFromLastPort", null, this.Title, null));
if (this.ETDFromPortOfCall.HasValue && this.ETAToNextPort.HasValue &&
this.ETAToNextPort < ETDFromPortOfCall)
errors.Add(RuleEngine.CreateError(ValidationCode.E122, "ETD PoC must be before ETA next port!", null));
errors.Add(RuleEngine.CreateError(ValidationCode.E121, "ETAToNextPort", null, this.Title, null));
if ((this.NextPort != null) && !this.NextPort.Equals("ZZUKN") && !this.ETAToNextPort.HasValue)
errors.Add(RuleEngine.CreateError(ValidationCode.E124, "ETA next port must be set!", null));
errors.Add(RuleEngine.CreateError(ValidationCode.NOT_NULL, "ETAToNextPort", null, this.Title, null));
}

View File

@ -220,11 +220,17 @@ namespace bsmd.database
public override void Validate(List<MessageError> errors, List<MessageViolation> violations)
{
if (this.PassengerPortOfDisembarkation.Equals("ZZUKN"))
violations.Add(RuleEngine.CreateViolation(ValidationCode.LOCODE, "Port of disembarkation unspecified!", null));
if (this.PassengerPortOfDisembarkation != null)
{
if (this.PassengerPortOfDisembarkation.Equals("ZZUKN"))
violations.Add(RuleEngine.CreateViolation(ValidationCode.NOT_NULL, "PassengerPortOfDisembarkation", null, this.Title, this.Identifier));
}
if (this.PassengerPortOfEmbarkation.Equals("ZZUKN"))
violations.Add(RuleEngine.CreateViolation(ValidationCode.LOCODE, "Port of embarkation unspecified!", null));
if (this.PassengerPortOfEmbarkation != null)
{
if (this.PassengerPortOfEmbarkation.Equals("ZZUKN"))
violations.Add(RuleEngine.CreateViolation(ValidationCode.NOT_NULL, "PassengerPortOfEmbarkation", null, this.Title, this.Identifier));
}
}
#endregion

View File

@ -174,9 +174,9 @@ namespace bsmd.database
if (this.Tanker ?? false)
{
if (!this.TankerHullConfiguration.HasValue)
violations.Add(RuleEngine.CreateViolation(ValidationCode.V741, "Tanker hull configuration must be set for tanker", null));
violations.Add(RuleEngine.CreateViolation(ValidationCode.V741, "TankerHullConfiguration", null, this.Title, null));
if (!this.ConditionCargoBallastTanks.HasValue)
violations.Add(RuleEngine.CreateViolation(ValidationCode.V741, "ConditionCargoBallastTanks must be set for tanker", null));
violations.Add(RuleEngine.CreateViolation(ValidationCode.V741, "ConditionCargoBallastTanks", null, this.Title, null));
}
}

View File

@ -238,7 +238,7 @@ namespace bsmd.database
public override void Validate(List<MessageError> errors, List<MessageViolation> violations)
{
if((this.PortOfCallLast30DaysCrewMembersJoined ?? false) && (this.CrewJoinedShip.Count == 0))
RuleEngine.CreateViolation(ValidationCode.V767, "Joined crew members", null);
RuleEngine.CreateViolation(ValidationCode.V767, "PortOfCallLast30DaysCrewMembersJoined", null, this.Title, this.Identifier);
if (this.PortOfCallLast30DaysCrewMembersJoined ?? false)
{

View File

@ -2,6 +2,6 @@
[assembly: AssemblyCompany("Informatikbüro Daniel Schick")]
[assembly: AssemblyProduct("BSMD NSW interface")]
[assembly: AssemblyInformationalVersion("3.6.15")]
[assembly: AssemblyInformationalVersion("3.6.16")]
[assembly: AssemblyCopyright("Copyright © 2014-2017 Informatikbüro Daniel Schick. All rights reserved.")]
[assembly: AssemblyTrademark("")]

View File

@ -1,4 +1,4 @@
using System.Reflection;
[assembly: AssemblyVersion("3.6.15.*")]
[assembly: AssemblyVersion("3.6.16.*")]

View File

@ -124,6 +124,9 @@ namespace bsmd.database
/// <param name="errors"></param>
public static void ValidateProperties(DatabaseEntity entity, List<MessageError> errors)
{
string identifier = null;
if (entity is ISublistElement)
identifier = ((ISublistElement)entity).Identifier;
Type objType = entity.GetType();
@ -176,94 +179,94 @@ namespace bsmd.database
switch (validationCode)
{
case ValidationCode.NOT_NULL:
if (value.Length == 0) errors.Add(RuleEngine.CreateError(validationCode, property.Name, value));
if (value.Length == 0) errors.Add(RuleEngine.CreateError(validationCode, property.Name, value, entity.Title, identifier));
break;
case ValidationCode.LOCODE:
{
Regex rgx = new Regex("[A-Z]{2}[A-Z0-9]{3}");
if (!rgx.IsMatch(value)) errors.Add(RuleEngine.CreateError(validationCode, property.Name, value));
if (!rgx.IsMatch(value)) errors.Add(RuleEngine.CreateError(validationCode, property.Name, value, entity.Title, identifier));
}
break;
case ValidationCode.LOCODE_GER:
{
if(!RuleEngine.gerLocodeList.Contains(value))
errors.Add(RuleEngine.CreateError(validationCode, property.Name, value));
errors.Add(RuleEngine.CreateError(validationCode, property.Name, value, entity.Title, identifier));
}
break;
case ValidationCode.INT_GT_ZERO:
{
int intVal = 0;
if (!Int32.TryParse(value, out intVal) || intVal <= 0)
errors.Add(RuleEngine.CreateError(validationCode, property.Name, value));
errors.Add(RuleEngine.CreateError(validationCode, property.Name, value, entity.Title, identifier));
}
break;
case ValidationCode.DOUBLE_GT_ZERO:
{
double dVal = 0;
if (!Double.TryParse(value, out dVal) || dVal <= 0)
errors.Add(RuleEngine.CreateError(validationCode, property.Name, value));
errors.Add(RuleEngine.CreateError(validationCode, property.Name, value, entity.Title, identifier));
}
break;
case ValidationCode.GISIS:
{
Regex rgx = new Regex("[0-9]{4}");
if (!rgx.IsMatch(value)) errors.Add(RuleEngine.CreateError(validationCode, property.Name, value));
if (!rgx.IsMatch(value)) errors.Add(RuleEngine.CreateError(validationCode, property.Name, value, entity.Title, identifier));
}
break;
case ValidationCode.FLAG_CODE:
{
Regex rgx = new Regex("[A-Z]{2}");
if(!rgx.IsMatch(value)) errors.Add(RuleEngine.CreateError(validationCode, property.Name, value));
if(!rgx.IsMatch(value)) errors.Add(RuleEngine.CreateError(validationCode, property.Name, value, entity.Title, identifier));
}
break;
case ValidationCode.TWO_DIGIT:
{
Regex rgx = new Regex("[0-9]{2}");
if (!rgx.IsMatch(value)) errors.Add(RuleEngine.CreateError(validationCode, property.Name, value));
if (!rgx.IsMatch(value)) errors.Add(RuleEngine.CreateError(validationCode, property.Name, value, entity.Title, identifier));
}
break;
case ValidationCode.STRING_EXACT_LEN:
{
if (value.Length != maxlen)
errors.Add(RuleEngine.CreateError(validationCode, property.Name, value));
errors.Add(RuleEngine.CreateError(validationCode, property.Name, value, entity.Title, identifier));
}
break;
case ValidationCode.STRING_MAXLEN:
{
if (value.Length > maxlen)
errors.Add(RuleEngine.CreateError(validationCode, property.Name, value));
errors.Add(RuleEngine.CreateError(validationCode, property.Name, value, entity.Title, identifier));
}
break;
case ValidationCode.STRING_IMOCLASS:
{
Regex rgx = new Regex(@"[1-9]{1}(\.[1-9]{1})?");
if (!rgx.IsMatch(value)) errors.Add(RuleEngine.CreateError(validationCode, property.Name, value));
if (!rgx.IsMatch(value)) errors.Add(RuleEngine.CreateError(validationCode, property.Name, value, entity.Title, identifier));
}
break;
case ValidationCode.STRING_UNNUMBER:
{
Regex rgx = new Regex("[0-9]{4}");
if (!rgx.IsMatch(value)) errors.Add(RuleEngine.CreateError(validationCode, property.Name, value));
if (!rgx.IsMatch(value)) errors.Add(RuleEngine.CreateError(validationCode, property.Name, value, entity.Title, identifier));
}
break;
case ValidationCode.DRAUGHT_IMPLAUSIBLE:
{
double dVal = 0;
if (!Double.TryParse(value, out dVal) || dVal <= 0)
errors.Add(RuleEngine.CreateError(ValidationCode.DOUBLE_GT_ZERO, property.Name, value));
errors.Add(RuleEngine.CreateError(ValidationCode.DOUBLE_GT_ZERO, property.Name, value, entity.Title, identifier));
else
if ((dVal < 20) || (dVal > 150))
errors.Add(RuleEngine.CreateError(validationCode, property.Name, value));
errors.Add(RuleEngine.CreateError(validationCode, property.Name, value, entity.Title, identifier));
}
break;
case ValidationCode.TIME_IMPLAUSIBLE:
{
DateTime aTime;
if (value.Length == 0) errors.Add(RuleEngine.CreateError(ValidationCode.NOT_NULL, property.Name, value));
if (value.Length == 0) errors.Add(RuleEngine.CreateError(ValidationCode.NOT_NULL, property.Name, value, entity.Title, identifier));
if (DateTime.TryParse(value, out aTime))
{
if ((aTime - DateTime.UtcNow).Minutes > 30)
errors.Add(RuleEngine.CreateError(validationCode, property.Name, value));
errors.Add(RuleEngine.CreateError(validationCode, property.Name, value, entity.Title, identifier));
}
}
break;
@ -277,6 +280,25 @@ namespace bsmd.database
#region public methods
public List<string> ValidateMessage(Message aMessage, out List<MessageError> errors, out List<MessageViolation> violations)
{
List<string> result = new List<string>();
errors = new List<MessageError>();
violations = new List<MessageViolation>();
foreach (DatabaseEntity derivedEntity in aMessage.Elements)
{
// individuelle Fehler nach Nachrichtenklasse prüfen
derivedEntity.MessageCore = aMessage.MessageCore; // some instance we need info from core (NOA / Transit)
if ((derivedEntity is LADG) && aMessage.MessageCore.IsTransit) continue; // kein error reporting für LADG bei Transit (CH, 1.2.16)
RuleEngine.ValidateProperties(derivedEntity, errors);
derivedEntity.Validate(errors, violations);
}
return result;
}
/// <summary>
/// Diese Funktion wird für Nachrichtenklassen (MDH, SEC,.. usw.) aufgerufen. Error in eingebetteten
/// Klassen werden dann der Nachrichtenklasse zugeordnet (können dann logischerweise mehrfach auftreten)
@ -337,12 +359,19 @@ namespace bsmd.database
#region private helper
internal static MessageError CreateError(ValidationCode validationCode, string p, string value)
internal static MessageError CreateError(ValidationCode validationCode, string p, string value, string entityName, string identifier)
{
MessageError error = new MessageError();
if (identifier.IsNullOrEmpty())
error.FullName = string.Format("{0}.{1}", entityName, p);
else
error.FullName = string.Format("{0}.{1}_{2}", entityName, p, identifier);
error.ErrorCode = (int)validationCode;
error.PropertyName = p;
if (errorTextList.ContainsKey((int)validationCode))
{
error.ErrorText = string.Format(errorTextList[(int)validationCode], p, value);
@ -356,12 +385,19 @@ namespace bsmd.database
return error;
}
internal static MessageViolation CreateViolation(ValidationCode validationCode, string p, string value)
internal static MessageViolation CreateViolation(ValidationCode validationCode, string p, string value, string entityName, string identifier)
{
MessageViolation violation = new MessageViolation();
if (identifier.IsNullOrEmpty())
violation.FullName = string.Format("{0}.{1}", entityName, p);
else
violation.FullName = string.Format("{0}.{1}_{2}", entityName, p, identifier);
violation.ViolationCode = (int)validationCode;
violation.PropertyName = p;
if (violationTextList.ContainsKey((int)validationCode))
{
violation.ViolationText = string.Format(violationTextList[(int)validationCode], p, value);

View File

@ -326,12 +326,12 @@ namespace bsmd.database
if (this.GetValidationBlock() == ValidationBlock.BLOCK1)
{
if (this.PortOfCallWhereCompleteSECNotified.IsNullOrEmpty())
violations.Add(RuleEngine.CreateViolation(ValidationCode.V704, "PortOfCallWhereCompleteSECNotified", null));
violations.Add(RuleEngine.CreateViolation(ValidationCode.V704, "PortOfCallWhereCompleteSECNotified", null, this.Title, null));
}
else
{
if((!this.ValidISSCOnBoard ?? true) && this.ReasonsForNoValidISSC.IsNullOrEmpty())
violations.Add(RuleEngine.CreateViolation(ValidationCode.V702, "Reasons missing", null));
violations.Add(RuleEngine.CreateViolation(ValidationCode.V702, "ReasonsForNoValidISSC", null, this.Title, null));
}

View File

@ -282,7 +282,7 @@ namespace bsmd.database
public override void Validate(List<MessageError> errors, List<MessageViolation> violations)
{
if (this.ISMCompanyName.IsNullOrEmpty() || this.ISMCompanyId.IsNullOrEmpty())
violations.Add(RuleEngine.CreateViolation(ValidationCode.V821, "For BRZ > 500 ISM company information must be provider", null));
violations.Add(RuleEngine.CreateViolation(ValidationCode.V821, "ISMCompanyName", null, this.Title, null));
}
#endregion

View File

@ -156,7 +156,7 @@ namespace bsmd.database
if (locationInsufficient)
{
violations.Add(RuleEngine.CreateViolation(ValidationCode.V701, "Ship To Ship: Either LoCode or Coordinates must be given", null));
violations.Add(RuleEngine.CreateViolation(ValidationCode.V701, null, null , this.Title, this.Identifier));
}
}

View File

@ -29,10 +29,11 @@ namespace bsmd.database
TWO_DIGIT,
STRING_MAXLEN,
STRING_EXACT_LEN,
LIST_EMPTY,
STRING_UNNUMBER = 23,
STRING_IMOCLASS = 24,
DRAUGHT_IMPLAUSIBLE = 25,
TIME_IMPLAUSIBLE = 26,
TIME_IMPLAUSIBLE = 26,
PORTAREA,
E121 = 121,
E122 = 122,

View File

@ -293,28 +293,7 @@ namespace bsmd.database
{
if(this.GetValidationBlock() == ValidationBlock.BLOCK2)
{
bool allWasteTypesPresent = true;
for(int i=1;i<=9;i++) {
bool foundIndex = false;
foreach(Waste waste in this.Waste) {
if((waste.WasteType ?? 0) == i) {
foundIndex = true;
break;
}
}
if (!foundIndex)
{
allWasteTypesPresent = false;
break;
}
}
if (!allWasteTypesPresent)
{
violations.Add(RuleEngine.CreateViolation(ValidationCode.V783, "not all waste types present!", null));
}
{
foreach (Waste waste in this.Waste)
{
RuleEngine.ValidateProperties(waste, errors);

View File

@ -204,9 +204,9 @@ namespace bsmd.database
if (this.WasteType.HasValue &&
((this.WasteType.Value == (int)3) || (this.WasteType.Value == (int)8) || (this.WasteType.Value == (int)9)) &&
this.WasteDescription.IsNullOrEmpty())
violations.Add(RuleEngine.CreateViolation(ValidationCode.V781, "Waste description missing!", null));
violations.Add(RuleEngine.CreateViolation(ValidationCode.V781, "WasteDescription", null, this.Title, this.Identifier));
// TODO 782: die verstehe ich nicht richtig
// TODO: 782
}
#endregion

View File

@ -380,14 +380,11 @@ namespace bsmd.hisnord
{
POBA poba = message.Elements[0] as POBA;
global::poba hn_poba = new global::poba();
if (poba.TotalCrewMembersOnBoardUponArrival.HasValue)
hn_poba.TotalCrewMembersOnBoardUponArrival = poba.TotalCrewMembersOnBoardUponArrival.Value.ToString();
if (poba.TotalPassengersOnBoardUponArrival.HasValue)
hn_poba.TotalPassengersOnBoardUponArrival = poba.TotalPassengersOnBoardUponArrival.Value.ToString();
if (poba.TotalPersonsOnBoardUponArrival.HasValue)
hn_poba.TotalPersonsOnBoardUponArrival = poba.TotalPersonsOnBoardUponArrival.Value.ToString();
if (poba.TotalStowawaysOnBoardUponArrival.HasValue)
hn_poba.TotalStowawaysOnBoardUponArrival = poba.TotalStowawaysOnBoardUponArrival.Value.ToString();
hn_poba.TotalCrewMembersOnBoardUponArrival = (poba.TotalCrewMembersOnBoardUponArrival ?? 0).ToString();
hn_poba.TotalPassengersOnBoardUponArrival = (poba.TotalPassengersOnBoardUponArrival ?? 0).ToString();
hn_poba.TotalPersonsOnBoardUponArrival = (poba.TotalPersonsOnBoardUponArrival ?? 0).ToString();
hn_poba.TotalStowawaysOnBoardUponArrival = (poba.TotalStowawaysOnBoardUponArrival ?? 0).ToString();
items1ChoiceType.Add(Items1ChoiceType.POBA);
items1.Add(hn_poba);
@ -411,14 +408,11 @@ namespace bsmd.hisnord
{
POBD pobd = message.Elements[0] as POBD;
global::pobd hn_pobd = new global::pobd();
if (pobd.TotalCrewMembersOnBoardUponDeparture.HasValue)
hn_pobd.TotalCrewMembersOnBoardUponDeparture = pobd.TotalCrewMembersOnBoardUponDeparture.Value.ToString();
if (pobd.TotalPassengersOnBoardUponDeparture.HasValue)
hn_pobd.TotalPassengersOnBoardUponDeparture = pobd.TotalPassengersOnBoardUponDeparture.Value.ToString();
if (pobd.TotalPersonsOnBoardUponDeparture.HasValue)
hn_pobd.TotalPersonsOnBoardUponDeparture = pobd.TotalPersonsOnBoardUponDeparture.Value.ToString();
if (pobd.TotalStowawaysOnBoardUponDeparture.HasValue)
hn_pobd.TotalStowawaysOnBoardUponDeparture = pobd.TotalStowawaysOnBoardUponDeparture.Value.ToString();
hn_pobd.TotalCrewMembersOnBoardUponDeparture = (pobd.TotalCrewMembersOnBoardUponDeparture ?? 0).ToString();
hn_pobd.TotalPassengersOnBoardUponDeparture = (pobd.TotalPassengersOnBoardUponDeparture ?? 0).ToString();
hn_pobd.TotalPersonsOnBoardUponDeparture = (pobd.TotalPersonsOnBoardUponDeparture ?? 0).ToString();
hn_pobd.TotalStowawaysOnBoardUponDeparture = (pobd.TotalStowawaysOnBoardUponDeparture ?? 0).ToString();
items1ChoiceType.Add(Items1ChoiceType.POBD);
items1.Add(hn_pobd);