diff --git a/ENI-2/ENI2/ENI2/DetailRootControl.xaml.cs b/ENI-2/ENI2/ENI2/DetailRootControl.xaml.cs index 810e0757..82e49694 100644 --- a/ENI-2/ENI2/ENI2/DetailRootControl.xaml.cs +++ b/ENI-2/ENI2/ENI2/DetailRootControl.xaml.cs @@ -57,6 +57,39 @@ namespace ENI2 get { return this.buttonSave.Visibility == Visibility.Visible; } // schwach aber es wird's tun } + public bool HasUnsentMessages + { + get + { + // Bedingung: + // wenn in einer Meldeklasse zwar Daten vorhanden sind, eingespielt durch Excel import oder + // Handeingabe, diese aber NICHT gesendet wurden. + foreach (Message aMessage in _messages) + { + if ((aMessage.InternalStatus == Message.BSMDStatus.UPDATED) || + (aMessage.InternalStatus == Message.BSMDStatus.SAVED) || + (aMessage.InternalStatus == Message.BSMDStatus.EXCEL)) + return true; + } + + return false; + } + } + + public bool HasUnConfirmedMessages + { + get + { + foreach(Message aMessage in _messages) + { + if ((aMessage.InternalStatus == Message.BSMDStatus.SENT) || + (aMessage.InternalStatus == Message.BSMDStatus.TOSEND)) + return true; + } + return false; + } + } + #endregion #region Construction @@ -231,7 +264,6 @@ namespace ENI2 existingCore = DBManager.GetSingleCon(Properties.Settings.Default.ConnectionString).GetMessageCoreByVisitId(newCore.VisitId); } - bool skipCopyTransit = false; bool skipCopyVisit = false; @@ -302,6 +334,20 @@ namespace ENI2 if (skipCopyTransit && (oldMessage.MessageNotificationClass == Message.NotificationClass.TRANSIT)) continue; if (skipCopyVisit && (oldMessage.MessageNotificationClass == Message.NotificationClass.VISIT)) continue; + // 10.9.19: bestimmte Meldeklassen nicht kopieren. Muss getestet werden, ob hier + // stattdessen "Leer"-Messages erzeugt werden müssen + if (oldMessage.MessageNotificationClass == Message.NotificationClass.ATA) continue; + if (oldMessage.MessageNotificationClass == Message.NotificationClass.ATD) continue; + if (oldMessage.MessageNotificationClass == Message.NotificationClass.NOA_NOD) continue; + + bool isAndienKlasse = ((oldMessage.MessageNotificationClass == Message.NotificationClass.AGNT) || + (oldMessage.MessageNotificationClass == Message.NotificationClass.STAT) || + (oldMessage.MessageNotificationClass == Message.NotificationClass.INFO) || + (oldMessage.MessageNotificationClass == Message.NotificationClass.HAZA) || + (oldMessage.MessageNotificationClass == Message.NotificationClass.HAZD)); + + if (!cdd.CopyAll && !isAndienKlasse) continue; + Message newMessage = oldMessage.Clone() as Message; newMessage.MessageCore = newCore; newMessage.MessageCoreId = newCore.Id; @@ -366,9 +412,12 @@ namespace ENI2 { if (message.IsDirty || message.IsNew) { - if ((message.Status == Message.MessageStatus.ACCEPTED) && + if ((message.Status == Message.MessageStatus.ACCEPTED) && ((message.InternalStatus == Message.BSMDStatus.CONFIRMED) || (message.InternalStatus == Message.BSMDStatus.VIOLATION))) message.InternalStatus = Message.BSMDStatus.UPDATED; + else + message.InternalStatus = Message.BSMDStatus.SAVED; + string userName = "?"; if(App.UserId.HasValue && DBManager.Instance.GetReportingPartyDict().ContainsKey(App.UserId.Value)) { @@ -377,24 +426,8 @@ namespace ENI2 message.ChangedBy = string.Format("{0} at {1}", userName, DateTime.Now); DBManager.GetSingleCon(Properties.Settings.Default.ConnectionString).Save(message); - //if (message.MessageNotificationClass == Message.NotificationClass.CREW) - //{ - // foreach(CREW crew in message.Elements) - // { - // if (crew.IsNew || crew.IsDirty) DBManager.GetSingleCon(Properties.Settings.Default.ConnectionString).Save(crew); - // } - //} - //else if (message.MessageNotificationClass == Message.NotificationClass.PAS) - //{ - // foreach(PAS pas in message.Elements) - // { - // if(pas.IsNew || pas.IsDirty) DBManager.GetSingleCon(Properties.Settings.Default.ConnectionString).Save(pas); - // } - //} - //else - //{ - message.SaveElements(); - //} + message.SaveElements(); + message.IsDirty = false; if(message.MessageNotificationClass == Message.NotificationClass.ATA) diff --git a/ENI-2/ENI2/ENI2/EditControls/CopyDeclarationDialog.xaml b/ENI-2/ENI2/ENI2/EditControls/CopyDeclarationDialog.xaml index 0b029f3b..94e44c07 100644 --- a/ENI-2/ENI2/ENI2/EditControls/CopyDeclarationDialog.xaml +++ b/ENI-2/ENI2/ENI2/EditControls/CopyDeclarationDialog.xaml @@ -8,7 +8,7 @@ xmlns:p="clr-namespace:ENI2.Properties" xmlns:xctk="http://schemas.xceed.com/wpf/xaml/toolkit" mc:Ignorable="d" - Title="{x:Static p:Resources.textCopyDeclaration}" Height="270" Width="440" WindowStyle="SingleBorderWindow" Background="AliceBlue" ResizeMode="NoResize" Icon="/ENI2;component/Resources/id_cards.ico"> + Title="{x:Static p:Resources.textCopyDeclaration}" Height="326" Width="440" WindowStyle="SingleBorderWindow" Background="AliceBlue" ResizeMode="NoResize" Icon="/ENI2;component/Resources/id_cards.ico"> @@ -17,6 +17,8 @@ + + @@ -29,6 +31,7 @@ \ No newline at end of file diff --git a/ENI-2/ENI2/ENI2/EditControls/CopyDeclarationDialog.xaml.cs b/ENI-2/ENI2/ENI2/EditControls/CopyDeclarationDialog.xaml.cs index 8fa564ff..345875ac 100644 --- a/ENI-2/ENI2/ENI2/EditControls/CopyDeclarationDialog.xaml.cs +++ b/ENI-2/ENI2/ENI2/EditControls/CopyDeclarationDialog.xaml.cs @@ -23,31 +23,7 @@ namespace ENI2.EditControls { InitializeComponent(); Loaded += CopyDeclarationDialog_Loaded; - } - - private void CopyDeclarationDialog_Loaded(object sender, System.Windows.RoutedEventArgs e) - { - this.OKClicked += VisitIdDialog_OKClicked; - List> comboDataSource = new List>() - { - new KeyValuePair( Message.NSWProvider.DBH, "DBH live" ), - new KeyValuePair( Message.NSWProvider.DBH_TEST, "DBH Testsystem" ), - new KeyValuePair( Message.NSWProvider.DUDR, "HIS-Nord live" ), - new KeyValuePair( Message.NSWProvider.DUDR_TEST, "HIS-Nord Testsystem" ) - }; - - this.comboBoxInitialHIS.ItemsSource = comboDataSource; - this.comboBoxInitialHIS.SelectedIndex = 2; - - this.EnableOK(false); - this.locodePoC.PropertyChanged += LocodePoC_PropertyChanged; - - if (!this.OldCore.IMO.IsNullOrEmpty()) this.doubleUpDownIMO.Value = Double.Parse(this.OldCore.IMO); - if (!this.OldCore.ENI.IsNullOrEmpty()) this.doubleUpDownENI.Value = Double.Parse(this.OldCore.ENI); - if (!this.OldCore.PoC.IsNullOrEmpty()) this.locodePoC.LocodeValue = this.OldCore.PoC; - if (this.OldCore.ETA.HasValue) this.datePickerETA.SelectedDate = this.OldCore.ETA; - - } + } #region Properties @@ -57,6 +33,8 @@ namespace ENI2.EditControls public bool IsOK { get { return this._isOK; } } + public bool CopyAll { get { return this.radioButtonCopyAll.IsChecked ?? false; } } + #endregion #region completion logic @@ -93,6 +71,30 @@ namespace ENI2.EditControls #region event handler + private void CopyDeclarationDialog_Loaded(object sender, System.Windows.RoutedEventArgs e) + { + this.OKClicked += VisitIdDialog_OKClicked; + List> comboDataSource = new List>() + { + new KeyValuePair( Message.NSWProvider.DBH, "DBH live" ), + new KeyValuePair( Message.NSWProvider.DBH_TEST, "DBH Testsystem" ), + new KeyValuePair( Message.NSWProvider.DUDR, "HIS-Nord live" ), + new KeyValuePair( Message.NSWProvider.DUDR_TEST, "HIS-Nord Testsystem" ) + }; + + this.comboBoxInitialHIS.ItemsSource = comboDataSource; + this.comboBoxInitialHIS.SelectedIndex = 2; + + this.EnableOK(false); + this.locodePoC.PropertyChanged += LocodePoC_PropertyChanged; + + if (!this.OldCore.IMO.IsNullOrEmpty()) this.doubleUpDownIMO.Value = Double.Parse(this.OldCore.IMO); + if (!this.OldCore.ENI.IsNullOrEmpty()) this.doubleUpDownENI.Value = Double.Parse(this.OldCore.ENI); + if (!this.OldCore.PoC.IsNullOrEmpty()) this.locodePoC.LocodeValue = this.OldCore.PoC; + if (this.OldCore.ETA.HasValue) this.datePickerETA.SelectedDate = this.OldCore.ETA; + + } + private void LocodePoC_PropertyChanged(object sender, PropertyChangedEventArgs e) { this.CheckComplete(); diff --git a/ENI-2/ENI2/ENI2/MainWindow.xaml.cs b/ENI-2/ENI2/ENI2/MainWindow.xaml.cs index 65845a3c..949a2691 100644 --- a/ENI-2/ENI2/ENI2/MainWindow.xaml.cs +++ b/ENI-2/ENI2/ENI2/MainWindow.xaml.cs @@ -159,6 +159,21 @@ namespace ENI2 e.Cancel = true; } + // Test for unsent messages + if (!e.Cancel && drc.HasUnsentMessages) + { + if (MessageBox.Show(Properties.Resources.textConfirmUnsentMessages, Properties.Resources.textConfirmation, MessageBoxButton.YesNo, MessageBoxImage.Question, MessageBoxResult.No) == MessageBoxResult.No) + e.Cancel = true; + } + + // Test for unconfirmed messages + if(!e.Cancel && drc.HasUnConfirmedMessages) + { + if (MessageBox.Show(Properties.Resources.textConfirmUnconfirmedMessages, Properties.Resources.textConfirmation, MessageBoxButton.YesNo, MessageBoxImage.Question, MessageBoxResult.No) == MessageBoxResult.No) + e.Cancel = true; + } + + if (!e.Cancel) { if (lockedCores.ContainsKey(tabItem)) diff --git a/ENI-2/ENI2/ENI2/Properties/Resources.Designer.cs b/ENI-2/ENI2/ENI2/Properties/Resources.Designer.cs index d9046a93..073e9b78 100644 --- a/ENI-2/ENI2/ENI2/Properties/Resources.Designer.cs +++ b/ENI-2/ENI2/ENI2/Properties/Resources.Designer.cs @@ -1370,6 +1370,24 @@ namespace ENI2.Properties { } } + /// + /// Looks up a localized string similar to Unconfirmed messages! Do you want to close anyway?. + /// + public static string textConfirmUnconfirmedMessages { + get { + return ResourceManager.GetString("textConfirmUnconfirmedMessages", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unsent messages! Do you want to close anyway?. + /// + public static string textConfirmUnsentMessages { + get { + return ResourceManager.GetString("textConfirmUnsentMessages", resourceCulture); + } + } + /// /// Looks up a localized string similar to Unsaved changes! Do you want to close anyway?. /// diff --git a/ENI-2/ENI2/ENI2/Properties/Resources.resx b/ENI-2/ENI2/ENI2/Properties/Resources.resx index 6eff215c..01e788e8 100644 --- a/ENI-2/ENI2/ENI2/Properties/Resources.resx +++ b/ENI-2/ENI2/ENI2/Properties/Resources.resx @@ -1525,6 +1525,12 @@ Unsaved changes! Do you want to close anyway? + + Unsent messages! Do you want to close anyway? + + + Unconfirmed messages! Do you want to close anyway? + Some messages have unsaved changes. Send anyway? diff --git a/Stundensheet.xlsx b/Stundensheet.xlsx index 70b37197..fa1f6d05 100644 Binary files a/Stundensheet.xlsx and b/Stundensheet.xlsx differ diff --git a/nsw/Source/bsmd.ExcelReadService/ExcelReadService.cs b/nsw/Source/bsmd.ExcelReadService/ExcelReadService.cs index 82c17e0e..d1afd932 100644 --- a/nsw/Source/bsmd.ExcelReadService/ExcelReadService.cs +++ b/nsw/Source/bsmd.ExcelReadService/ExcelReadService.cs @@ -30,7 +30,7 @@ namespace bsmd.ExcelReadService { this.EventLog.Source = this.ServiceName; this.EventLog.Log = "Application"; - this.Init(args); + this.Init(); this.EventLog.WriteEntry("NSW Excel Read Service started.", EventLogEntryType.Information); System.Reflection.Assembly assembly = System.Reflection.Assembly.GetExecutingAssembly(); FileVersionInfo fvi = FileVersionInfo.GetVersionInfo(assembly.Location); @@ -40,7 +40,7 @@ namespace bsmd.ExcelReadService this.DoOnce(); } - private void Init(string[] args) + private void Init() { this._timer = new Timer { diff --git a/nsw/Source/bsmd.ExcelReadService/Util.cs b/nsw/Source/bsmd.ExcelReadService/Util.cs index abc9b0c9..0868d7df 100644 --- a/nsw/Source/bsmd.ExcelReadService/Util.cs +++ b/nsw/Source/bsmd.ExcelReadService/Util.cs @@ -22,8 +22,6 @@ namespace bsmd.ExcelReadService internal static bool ProcessSheet(ExcelReader reader, out string readMessage, out MessageCore messageCore) { - readMessage = "ok"; - messageCore = Util.LookupMessageCore(reader, out readMessage); if (messageCore == null) return false; // cannot work with this sheet or create one @@ -138,6 +136,7 @@ namespace bsmd.ExcelReadService foreach (Message message in messages) { message.CreatedBy = "EXCEL"; + message.InternalStatus = Message.BSMDStatus.EXCEL; DBManager.Instance.Save(message); message.SaveElements(); } @@ -2590,7 +2589,7 @@ namespace bsmd.ExcelReadService // lookup using field values MessageCore result = null; DateTime? eta = null; - string poc = null; + string poc; string imo = null; message = string.Empty; bool isTransit = false; @@ -2708,9 +2707,11 @@ namespace bsmd.ExcelReadService imo = reader.ReadText("Visit.IMONumber"); reader.Conf.ConfirmText("Visit.IMONumber", imo, imo.IsNullOrEmpty() ? ExcelReader.ReadState.FAIL : ExcelReader.ReadState.OK); + if ((imo.Length > 0) && !bsmd.database.Util.IsIMOValid(imo)) + reader.Conf.ConfirmText("Visit.IMONumber", imo, ExcelReader.ReadState.WARN); // ETA - if(poc != null) + if (poc != null) eta = reader.ReadDateTime("NOA_NOD.ETADateToPortOfCall", "NOA_NOD.ETATimeToPortOfCall"); if ((imo != null) && (eta.HasValue) && (poc != null)) @@ -2795,6 +2796,11 @@ namespace bsmd.ExcelReadService result.IMO = result.IMO.Substring(0, 7); } + if((result.IMO.Length == 7) && !bsmd.database.Util.IsIMOValid(result.IMO)) + { + _log.WarnFormat("IMO {0} possibly invalid (checksum number violation)", result.IMO); + } + if(visitTransitId != null) { if (bsmd.database.Util.IsTransitId(visitTransitId)) diff --git a/nsw/Source/bsmd.database/Message.cs b/nsw/Source/bsmd.database/Message.cs index f4933479..9a646e22 100644 --- a/nsw/Source/bsmd.database/Message.cs +++ b/nsw/Source/bsmd.database/Message.cs @@ -157,7 +157,9 @@ namespace bsmd.database SUSPENDED = 8, IN_USE, UPDATED, - REPORT // nur für diese Meldeklasse einen PDF Report erzeugen (geht danach wieder auf PREPARE) + REPORT, // nur für diese Meldeklasse einen PDF Report erzeugen (geht danach wieder auf PREPARE) + SAVED, // veränderte Meldeklasse wird im ENI gespeichert + EXCEL // Meldeklasse wurde in Excel befüllt } /// diff --git a/nsw/Source/bsmd.database/Util.cs b/nsw/Source/bsmd.database/Util.cs index b0aa2f6c..434c4fbf 100644 --- a/nsw/Source/bsmd.database/Util.cs +++ b/nsw/Source/bsmd.database/Util.cs @@ -227,6 +227,41 @@ namespace bsmd.database return null; } + public static bool IsIMOValid(string imoAsString) + { + if (imoAsString.IsNullOrEmpty()) return false; + string actualIMO = null; + if(imoAsString.Length == 10) + { + if (imoAsString.Substring(0, 3).Equals("imo", StringComparison.OrdinalIgnoreCase)) + actualIMO = imoAsString.Substring(3); + } + if (imoAsString.Length == 7) + actualIMO = imoAsString; + + if ((actualIMO != null) && Int32.TryParse(actualIMO, out int _)) + { + /* The integrity of an IMO number can be verified using its check digit. This is done by multiplying + * each of the first six digits by a factor of 2 to 7 corresponding to their position from right + * to left. The rightmost digit of this sum is the check digit. + * For example, for IMO 9074729: (9×7) + (0×6) + (7×5) + (4×4) + (7×3) + (2×2) = 139 + */ + + int sum = 0; + for (int i = 0, multiplier = 7; i < 6; i++, multiplier--) + { + sum += (Convert.ToInt32(actualIMO[i]) * multiplier); + } + + int lastdigit = sum % 10; // letzte Stelle + + if (Convert.ToInt32(actualIMO[6]) == lastdigit) + return true; + } + + return false; + } + #region CoordinateTransformation public static double NSWToDecimalDegrees(int nswCoordinate) diff --git a/nsw/Source/misc/db.sqlite b/nsw/Source/misc/db.sqlite index efdea21e..0693e66c 100644 Binary files a/nsw/Source/misc/db.sqlite and b/nsw/Source/misc/db.sqlite differ