diff --git a/ENI2/Controls/MaerskListControl.xaml.cs b/ENI2/Controls/MaerskListControl.xaml.cs index 572a5788..2bf7cd91 100644 --- a/ENI2/Controls/MaerskListControl.xaml.cs +++ b/ENI2/Controls/MaerskListControl.xaml.cs @@ -17,6 +17,8 @@ using bsmd.database; using ExcelDataReader; using System.Collections.ObjectModel; using ENI2.Excel; +using ENI2.Locode; +using ENI2.Util; namespace ENI2.Controls { @@ -24,12 +26,13 @@ namespace ENI2.Controls /// Interaction logic for MaerskListControl.xaml /// public partial class MaerskListControl : UserControl - { + { #region Fields - + private readonly ObservableCollection maerskDataList = new ObservableCollection(); private const uint MAX_EMPTY_ROWS_ON_IMPORT = 3; // import breaks if more than this count of empty rows have been read + private readonly DatabaseEntityWatchdog _dbWatchDog; #endregion @@ -41,8 +44,47 @@ namespace ENI2.Controls Loaded += POList_Loaded; this.dateTimePickerFrom.Value = DateTime.Today.AddDays(-14); this.dateTimePickerTo.Value = DateTime.Today.AddDays(14); + this._dbWatchDog = new DatabaseEntityWatchdog(); + this._dbWatchDog.DatabaseEntityChanged += _dbWatchDog_DatabaseEntityChanged; + this._dbWatchDog.VisitTransitIdUpdated += _dbWatchDog_VisitTransitIdUpdated; } + private async void _dbWatchDog_VisitTransitIdUpdated(DatabaseEntity entity) + { + if (entity is MessageCore core) + { + foreach (MaerskData md in this.maerskDataList) + { + if ((md.MessageCore != null) && (md.MessageCore.Id == core.Id)) + { + md.MessageCore = core; + md.Status = MaerskData.MDStatus.ID; + md.ColM = core.VisitId; + await DBManagerAsync.Save(md); + this.Dispatcher.Invoke(() => + { + this.dataGridPOCores.Items.Refresh(); + }); + } + } + } + } + + private void _dbWatchDog_DatabaseEntityChanged(DatabaseEntity entity) + { + if (entity is MessageCore core) + System.Diagnostics.Trace.WriteLine($"Core state changed to {core.BSMDStatusInternal}"); + } + + #endregion + + #region Properties + + /// + /// Locode of the port that is concerned by this import list. Is to be set in the surrounding container: + /// + public string PortLocode { get; set; } + #endregion #region control event handler @@ -302,18 +344,21 @@ namespace ENI2.Controls private async void buttonSave_Click(object sender, RoutedEventArgs e) { + busyControl.BusyState = Util.UIHelper.BusyStateEnum.BUSY; + // save the current list to DB (only if the entries have matching cores!) foreach(MaerskData md in this.maerskDataList) { if(md.MessageCore != null) { - await DBManagerAsync.Save(md.MessageCore); + await DBManagerAsync.Save(md); } } + busyControl.BusyState = Util.UIHelper.BusyStateEnum.NEUTRAL; } - private void buttonRequestIds_Click(object sender, RoutedEventArgs e) + private async void buttonRequestIds_Click(object sender, RoutedEventArgs e) { // find all entries from now until 3 days into the future and track parallel requests List requestList = new List(); @@ -330,13 +375,34 @@ namespace ENI2.Controls else { // Todo: + foreach (MaerskData md in requestList) + { + // 1) create MessageCore and message classes + md.MessageCore = new MessageCore(); + md.MessageCore.InitialHIS = Message.NSWProvider.DBH; + md.MessageCore.IMO = md.ColF; + md.MessageCore.ETA = md.ETA; + md.MessageCore.IsTransit = false; + md.MessageCore.PoC = this.PortLocode; + md.MessageCore.Portname = LocodeDB.PortNameFromLocode(md.MessageCore.PoC); + md.MessageCore.BSMDStatusInternal = MessageCore.BSMDStatus.TOSEND; + md.MessageCore.Incoming = true; + md.MessageCore.DefaultReportingPartyId = App.UserId.Value; + await DBManagerAsync.Save(md.MessageCore); + md.MessageCoreId = md.MessageCore.Id.Value; + await DBManagerAsync.Save(md); - // 1) create MessageCore and message classes + // Meldeklassen für neuen Anlauf erzeugen + // TODO: pre-set certain fields taken from Maersk data + await bsmd.database.Util.CreateMessagesForCoreAsync(md.MessageCore, null); - // 2) request dbh Id + // watchdog registrieren + this._dbWatchDog.Register(md.MessageCore); + // 2) request dbh Id - // 3) register watchdog for request completion + // 3) register watchdog for request completion + } } this.dataGridPOCores.Items.Refresh(); } diff --git a/ENI2/Controls/MaerskOverviewControl.xaml.cs b/ENI2/Controls/MaerskOverviewControl.xaml.cs index 79cf4f50..1f443b3c 100644 --- a/ENI2/Controls/MaerskOverviewControl.xaml.cs +++ b/ENI2/Controls/MaerskOverviewControl.xaml.cs @@ -1,17 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Windows; -using System.Windows.Controls; -using System.Windows.Data; -using System.Windows.Documents; -using System.Windows.Input; -using System.Windows.Media; -using System.Windows.Media.Imaging; -using System.Windows.Navigation; -using System.Windows.Shapes; +using System.Windows.Controls; namespace ENI2.Controls { @@ -23,6 +10,8 @@ namespace ENI2.Controls public MaerskOverviewControl() { InitializeComponent(); + this.brvListControl.PortLocode = "DEBRV"; + this.wvnListControl.PortLocode = "DEWVN"; } } } diff --git a/ENI2/DetailViewControls/OverViewDetailControl.xaml.cs b/ENI2/DetailViewControls/OverViewDetailControl.xaml.cs index 5ffcbeb8..4f241b59 100644 --- a/ENI2/DetailViewControls/OverViewDetailControl.xaml.cs +++ b/ENI2/DetailViewControls/OverViewDetailControl.xaml.cs @@ -787,7 +787,6 @@ namespace ENI2.DetailViewControls if (sfd.ShowDialog() ?? false) { Util.UIHelper.SetBusyState(); - ExcelManager em = new ExcelManager(); try @@ -800,7 +799,7 @@ namespace ENI2.DetailViewControls { MessageBox.Show(ex.Message, "Export failed", MessageBoxButton.OK, MessageBoxImage.Error); } - } + } } #endregion diff --git a/ENI2/EditControls/VisitIdDialog.xaml.cs b/ENI2/EditControls/VisitIdDialog.xaml.cs index 6453e2f7..cdddb4c4 100644 --- a/ENI2/EditControls/VisitIdDialog.xaml.cs +++ b/ENI2/EditControls/VisitIdDialog.xaml.cs @@ -47,7 +47,7 @@ namespace ENI2.EditControls if(this.locodePoC.LocodeValue == "ZZNOK") { - this.Core.IsTransit = true; + this.Core.IsTransit = true; this.Core.ETAKielCanal = this.datePickerETA.SelectedDate; } @@ -78,7 +78,7 @@ namespace ENI2.EditControls private void doubleUpDownIMO_ValueChanged(object sender, RoutedPropertyChangedEventArgs e) { - bool hasValue = (doubleUpDownIMO.Value.HasValue && doubleUpDownIMO.Value > 0); + bool hasValue = doubleUpDownIMO.Value.HasValue && doubleUpDownIMO.Value > 0; doubleUpDownENI.IsReadOnly = hasValue; this.CheckComplete(); @@ -88,7 +88,7 @@ namespace ENI2.EditControls private void doubleUpDownENI_ValueChanged(object sender, RoutedPropertyChangedEventArgs e) { - bool hasValue = (doubleUpDownENI.Value.HasValue && doubleUpDownENI.Value > 0); + bool hasValue = doubleUpDownENI.Value.HasValue && doubleUpDownENI.Value > 0; doubleUpDownIMO.IsReadOnly = hasValue; this.CheckComplete(); } diff --git a/ENI2/MainWindow.xaml.cs b/ENI2/MainWindow.xaml.cs index d2dac9d7..4556ae47 100644 --- a/ENI2/MainWindow.xaml.cs +++ b/ENI2/MainWindow.xaml.cs @@ -405,7 +405,7 @@ namespace ENI2 if (!closedDialog.Core.IsDK) { // deutsche Häfen fordern eine Visit-Id an, für DK erfolgt hier nur die Anlage eines Datensatzes - closedDialog.Core.BSMDStatusInternal = MessageCore.BSMDStatus.TOSEND; + closedDialog.Core.BSMDStatusInternal = MessageCore.BSMDStatus.TOSEND; } if (closedDialog.Core.PoC.Equals("ZZNOK")) diff --git a/ENI2/Util/DatabaseEntityWatchdog.cs b/ENI2/Util/DatabaseEntityWatchdog.cs index 5cf88a6c..88de8eec 100644 --- a/ENI2/Util/DatabaseEntityWatchdog.cs +++ b/ENI2/Util/DatabaseEntityWatchdog.cs @@ -98,7 +98,7 @@ namespace ENI2.Util if (this._watchedEntities.ContainsKey(entity)) // hier wird mit Id verglichen (IEquatable impl.) this._watchedEntities.Remove(entity); if (this._watchedEntities.Count == 0) - this.bgTimer.Stop(); + this.bgTimer.Stop(); } } diff --git a/bsmd.database/MaerskData.cs b/bsmd.database/MaerskData.cs index d5791efe..2e88fc5d 100644 --- a/bsmd.database/MaerskData.cs +++ b/bsmd.database/MaerskData.cs @@ -25,7 +25,7 @@ namespace bsmd.database #region Construction public MaerskData() { - this.tablename = "[dbo].[MaerskData]"; + this.tablename = "[dbo].[XtraData]"; } #endregion @@ -135,12 +135,14 @@ namespace bsmd.database public async Task> LoadListAsync(SqlDataReader reader) { List result = new List(); - - while (await reader.ReadAsync()) + if (reader != null) { - result.Add(ReadRowFromReader(reader)); + while (await reader.ReadAsync()) + { + result.Add(ReadRowFromReader(reader)); + } + reader.Close(); } - reader.Close(); return result; } diff --git a/bsmd.database/Util.cs b/bsmd.database/Util.cs index 00793a32..865d8563 100644 --- a/bsmd.database/Util.cs +++ b/bsmd.database/Util.cs @@ -13,6 +13,7 @@ using System.Collections.Generic; using System.Text.RegularExpressions; using log4net; using System.Globalization; +using System.Threading.Tasks; namespace bsmd.database { @@ -110,16 +111,16 @@ namespace bsmd.database } public static bool IsVisitId(string val) - { + { if (val.IsNullOrEmpty()) return false; return regexVisit.IsMatch(val); } public static bool IsTransitId(string val) - { + { if (val.IsNullOrEmpty()) return false; return regexTransit.IsMatch(val); - } + } /// /// Hilfsfunktion für "manuelle" Anlage eines Schiffsanlaufs. Die Objekte sind bereits gespeichert. @@ -137,8 +138,8 @@ namespace bsmd.database { _log.WarnFormat("Core {0} [{1}] has more than one message class for {2}", core.Id, core.DisplayId, aMessage.MessageNotificationClassDisplay); } - messageDict[aMessage.MessageNotificationClass] = aMessage; - } + messageDict[aMessage.MessageNotificationClass] = aMessage; + } } bool isDE, isDK; @@ -148,7 +149,7 @@ namespace bsmd.database isDK = core.PoC.StartsWith("DK"); foreach (Message.NotificationClass notificationClass in Enum.GetValues(typeof(Message.NotificationClass))) - { + { if(isDE) { if (notificationClass == Message.NotificationClass.STO) continue; @@ -207,12 +208,105 @@ namespace bsmd.database DBManager.Instance.Save(classElement); message.Elements.Add(classElement); } - } + } } } return result; } + /// + /// Hilfsfunktion für "manuelle" Anlage eines Schiffsanlaufs. Die Objekte sind bereits gespeichert. + /// Es werden nur noch nicht vorhandene Meldeklassen erzeugt (Async version) + /// + public static async Task> CreateMessagesForCoreAsync(MessageCore core, List existingMessages, ReportingParty user = null) + { + List result = new List(); + Dictionary messageDict = new Dictionary(); + if (!existingMessages.IsNullOrEmpty()) + { + foreach (Message aMessage in existingMessages) + { + if (messageDict.ContainsKey(aMessage.MessageNotificationClass)) + { + _log.WarnFormat("Core {0} [{1}] has more than one message class for {2}", core.Id, core.DisplayId, aMessage.MessageNotificationClassDisplay); + } + messageDict[aMessage.MessageNotificationClass] = aMessage; + } + } + + bool isDE, isDK; + if (core?.PoC != null) + { + isDE = core.PoC.Equals("ZZNOK") || core.PoC.StartsWith("DE"); + isDK = core.PoC.StartsWith("DK"); + + foreach (Message.NotificationClass notificationClass in Enum.GetValues(typeof(Message.NotificationClass))) + { + if (isDE) + { + if (notificationClass == Message.NotificationClass.STO) continue; + } + if (isDK) + { + // gibt es hier etwas, das nicht gebraucht wird? (siehe Mail von Christin, 29.5.17 + if ((notificationClass == Message.NotificationClass.MDH) || + (notificationClass == Message.NotificationClass.BKRA) || + (notificationClass == Message.NotificationClass.BKRD) || + (notificationClass == Message.NotificationClass.TOWA) || + (notificationClass == Message.NotificationClass.TOWD)) continue; + } + + if (core.IsTransit && (notificationClass == Message.NotificationClass.VISIT)) continue; + if (!core.IsTransit && (notificationClass == Message.NotificationClass.TRANSIT)) continue; + + Message message; + + if (!messageDict.ContainsKey(notificationClass)) + { + message = new Message(); + if (user != null) + message.CreatedBy = string.Format("ENI-2: {0}", user.Logon); + message.MessageCore = core; + message.MessageCoreId = core.Id; + message.MessageNotificationClass = notificationClass; + await DBManagerAsync.Save(message); + result.Add(message); + } + else + { + message = messageDict[notificationClass]; + } + + // abgesehen von "Listen" für die Nachrichtenklassen auch untergeordnete Elemente erzeugen, falls nicht vorhanden! + DatabaseEntity classElement; + if (!Message.IsListClass(notificationClass) && (message.Elements.Count == 0)) + { + classElement = DBManager.CreateMessage(notificationClass); + + // CH: 6.10.17: Für die manuelle Eingabe (wird leider nicht ganz auszuschließen sein) wäre es hilfreich, wenn alle Checkboxen nicht leer sind, sondern False beinhalten. + if (notificationClass == Message.NotificationClass.MDH) + { + ((MDH)classElement).SetBoolsToFalse(); + } + if (notificationClass == Message.NotificationClass.BPOL) + { + // Vorbelegung, Spezialwunsch aus BRV 5.2.18 + ((BPOL)classElement).CruiseShip = false; + ((BPOL)classElement).StowawaysOnBoard = false; + } + if (classElement != null) // null für Visit/Transit + { + classElement.MessageHeader = message; + await DBManagerAsync.Save(classElement); + message.Elements.Add(classElement); + } + } + } + } + return result; + } + + public static int? GetNumericIdentifier(ISublistElement element) { if (element != null)