From 782ae3138ef1dbdaee96e110a7ac56a3a2e4d13f Mon Sep 17 00:00:00 2001 From: Daniel Schick Date: Mon, 26 Jan 2026 13:46:51 +0100 Subject: [PATCH 01/12] Increased version to 7.2.14 --- ENI2/ENI2.csproj | 4 ++-- bsmd.database/Properties/AssemblyProductInfo.cs | 2 +- bsmd.database/Properties/AssemblyProjectInfo.cs | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/ENI2/ENI2.csproj b/ENI2/ENI2.csproj index 2beedc3b..8fc4257d 100644 --- a/ENI2/ENI2.csproj +++ b/ENI2/ENI2.csproj @@ -36,8 +36,8 @@ 5.4.0.0 true publish.html - 2 - 7.2.13.2 + 0 + 7.2.14.0 false true true diff --git a/bsmd.database/Properties/AssemblyProductInfo.cs b/bsmd.database/Properties/AssemblyProductInfo.cs index 19b3f3d5..c1cb50b2 100644 --- a/bsmd.database/Properties/AssemblyProductInfo.cs +++ b/bsmd.database/Properties/AssemblyProductInfo.cs @@ -2,6 +2,6 @@ [assembly: AssemblyCompany("schick Informatik")] [assembly: AssemblyProduct("BSMD NSW interface")] -[assembly: AssemblyInformationalVersion("7.2.13")] +[assembly: AssemblyInformationalVersion("7.2.14")] [assembly: AssemblyCopyright("Copyright © 2014-2025 schick Informatik")] [assembly: AssemblyTrademark("")] \ No newline at end of file diff --git a/bsmd.database/Properties/AssemblyProjectInfo.cs b/bsmd.database/Properties/AssemblyProjectInfo.cs index 9a544667..16239876 100644 --- a/bsmd.database/Properties/AssemblyProjectInfo.cs +++ b/bsmd.database/Properties/AssemblyProjectInfo.cs @@ -1,4 +1,4 @@ using System.Reflection; -[assembly: AssemblyVersion("7.2.13.*")] +[assembly: AssemblyVersion("7.2.14.*")] From d02cb0d56ba21751ba95f6696d27c1f721f95154 Mon Sep 17 00:00:00 2001 From: Daniel Schick Date: Mon, 26 Jan 2026 13:48:17 +0100 Subject: [PATCH 02/12] Changed all Excel access to read-only access if sheet is actually opened for reading. This should avoid errors when the sheet is still open in Excel. --- ENI2/Controls/MaerskListControl.xaml.cs | 3 ++- .../BorderPoliceDetailControl.xaml.cs | 12 ++++++++---- .../WasteDetailControl.xaml.cs | 3 ++- ENI2/Excel/ExcelBase.cs | 15 ++++++++++++++- ENI2/Excel/ExcelComparer.cs | 8 +++++--- ENI2/Excel/ExcelLocalImportHelper.cs | 6 ++++-- ENI2/Excel/ExcelReader.cs | 4 ++-- ENI2/Excel/ExcelWriter.cs | 4 ++-- .../CrewDepartureControl.xaml.cs | 3 ++- .../CrewPreArrivalControl.xaml.cs | 3 ++- .../PassengerDepartureControl.xaml.cs | 3 ++- .../PassengerPreArrivalControl.xaml.cs | 3 ++- ENI2/SheetDisplayControls/PortControl.xaml.cs | 3 ++- bsmd.ExcelReadService/ExcelReader.cs | 18 +++++++++++++++++- 14 files changed, 66 insertions(+), 22 deletions(-) diff --git a/ENI2/Controls/MaerskListControl.xaml.cs b/ENI2/Controls/MaerskListControl.xaml.cs index a4d275b6..f3630fab 100644 --- a/ENI2/Controls/MaerskListControl.xaml.cs +++ b/ENI2/Controls/MaerskListControl.xaml.cs @@ -338,7 +338,8 @@ namespace ENI2.Controls { try { - using (var workbook = new XLWorkbook(ofd.FileName)) + using (var stream = new FileStream(ofd.FileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) + using (var workbook = new XLWorkbook(stream)) { var worksheet = workbook.Worksheet(1); // Get first worksheet var rows = worksheet.RangeUsed().RowsUsed().Skip(1); // Skip header row diff --git a/ENI2/DetailViewControls/BorderPoliceDetailControl.xaml.cs b/ENI2/DetailViewControls/BorderPoliceDetailControl.xaml.cs index 91608b6f..0cb64f10 100644 --- a/ENI2/DetailViewControls/BorderPoliceDetailControl.xaml.cs +++ b/ENI2/DetailViewControls/BorderPoliceDetailControl.xaml.cs @@ -1051,7 +1051,8 @@ namespace ENI2.DetailViewControls { try { - using (var workbook = new XLWorkbook(ofd.FileName)) + using (var stream = new FileStream(ofd.FileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) + using (var workbook = new XLWorkbook(stream)) { var worksheet = workbook.Worksheet(1); // Get first worksheet var rows = worksheet.RangeUsed().RowsUsed().Skip(1); // Skip header row if present @@ -1121,7 +1122,8 @@ namespace ENI2.DetailViewControls { try { - using (var workbook = new XLWorkbook(ofd.FileName)) + using (var stream = new FileStream(ofd.FileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) + using (var workbook = new XLWorkbook(stream)) { var worksheet = workbook.Worksheet(1); // Get first worksheet var rows = worksheet.RangeUsed().RowsUsed().Skip(1); // Skip header row if present @@ -1192,7 +1194,8 @@ namespace ENI2.DetailViewControls { try { - using (var workbook = new XLWorkbook(ofd.FileName)) + using (var stream = new FileStream(ofd.FileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) + using (var workbook = new XLWorkbook(stream)) { var worksheet = workbook.Worksheet(1); var rows = worksheet.RangeUsed().RowsUsed().Skip(1); // Skip header row if present @@ -1268,7 +1271,8 @@ namespace ENI2.DetailViewControls { try { - using (var workbook = new XLWorkbook(ofd.FileName)) + using (var stream = new FileStream(ofd.FileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) + using (var workbook = new XLWorkbook(stream)) { var worksheet = workbook.Worksheet(1); var rows = worksheet.RangeUsed().RowsUsed().Skip(1); // Skip header row if present diff --git a/ENI2/DetailViewControls/WasteDetailControl.xaml.cs b/ENI2/DetailViewControls/WasteDetailControl.xaml.cs index d3fe3ea7..140681b5 100644 --- a/ENI2/DetailViewControls/WasteDetailControl.xaml.cs +++ b/ENI2/DetailViewControls/WasteDetailControl.xaml.cs @@ -485,7 +485,8 @@ namespace ENI2.DetailViewControls { try { - using (var workbook = new XLWorkbook(ofd.FileName)) + using (var stream = new FileStream(ofd.FileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) + using (var workbook = new XLWorkbook(stream)) { var worksheet = workbook.Worksheet(1); // Get first worksheet var rows = worksheet.RangeUsed().RowsUsed().Skip(3); // Skip first three rows diff --git a/ENI2/Excel/ExcelBase.cs b/ENI2/Excel/ExcelBase.cs index 7c54a00d..b19dea3a 100644 --- a/ENI2/Excel/ExcelBase.cs +++ b/ENI2/Excel/ExcelBase.cs @@ -9,6 +9,7 @@ using System.Globalization; using System.Text.RegularExpressions; using System.Drawing; using System.Linq; +using System.IO; namespace ENI2.Excel { @@ -22,6 +23,7 @@ namespace ENI2.Excel protected CountryMode _countryMode = CountryMode.DE; protected XLWorkbook _workBook; + protected FileStream _workBookStream; protected Dictionary _nameDict; protected ILog _log; @@ -101,6 +103,12 @@ namespace ENI2.Excel } } + protected void OpenWorkbookReadOnly(string path) + { + _workBookStream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite); + _workBook = new XLWorkbook(_workBookStream); + } + private static double? ParseAnyDouble(string val) { double? result = null; @@ -212,6 +220,11 @@ namespace ENI2.Excel _workBook.Dispose(); _workBook = null; } + if (_workBookStream != null) + { + _workBookStream.Dispose(); + _workBookStream = null; + } } catch (Exception ex) { @@ -222,4 +235,4 @@ namespace ENI2.Excel #endregion } -} \ No newline at end of file +} diff --git a/ENI2/Excel/ExcelComparer.cs b/ENI2/Excel/ExcelComparer.cs index 6db1ae7e..28f32595 100644 --- a/ENI2/Excel/ExcelComparer.cs +++ b/ENI2/Excel/ExcelComparer.cs @@ -53,8 +53,10 @@ namespace ENI2.Excel { File.Copy(targetPath, comparisonFileName, true); - using (var sourceWorkbook = new XLWorkbook(sourcePath)) - using (var comparisonWorkbook = new XLWorkbook(comparisonFileName)) + using (var sourceStream = new FileStream(sourcePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) + using (var sourceWorkbook = new XLWorkbook(sourceStream)) + using (var comparisonStream = new FileStream(comparisonFileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) + using (var comparisonWorkbook = new XLWorkbook(comparisonStream)) { // Es werden Zellen der "used range" miteinander verglichen foreach (var sourceSheet in sourceWorkbook.Worksheets) @@ -152,4 +154,4 @@ namespace ENI2.Excel return comparisonFileName; } } -} \ No newline at end of file +} diff --git a/ENI2/Excel/ExcelLocalImportHelper.cs b/ENI2/Excel/ExcelLocalImportHelper.cs index 84545948..e013ae6e 100644 --- a/ENI2/Excel/ExcelLocalImportHelper.cs +++ b/ENI2/Excel/ExcelLocalImportHelper.cs @@ -26,7 +26,8 @@ namespace ENI2.Excel { try { - using (var workbook = new XLWorkbook(ofd.FileName)) + using (var stream = new FileStream(ofd.FileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) + using (var workbook = new XLWorkbook(stream)) { var worksheet = workbook.Worksheet(1); var rows = worksheet.RangeUsed().RowsUsed(); @@ -144,7 +145,8 @@ namespace ENI2.Excel { try { - using (var workbook = new XLWorkbook(ofd.FileName)) + using (var stream = new FileStream(ofd.FileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) + using (var workbook = new XLWorkbook(stream)) { var worksheet = workbook.Worksheet(1); var rows = worksheet.RangeUsed().RowsUsed(); diff --git a/ENI2/Excel/ExcelReader.cs b/ENI2/Excel/ExcelReader.cs index 8a5c8edf..941ac9c4 100644 --- a/ENI2/Excel/ExcelReader.cs +++ b/ENI2/Excel/ExcelReader.cs @@ -32,7 +32,7 @@ namespace ENI2.Excel public ExcelReader(string filePath, bool createNameFields = true) { - this._workBook = new XLWorkbook(filePath); + this.OpenWorkbookReadOnly(filePath); if (createNameFields) this.InitNameFields(); @@ -793,4 +793,4 @@ namespace ENI2.Excel #endregion Dakosy-specific functions } -} \ No newline at end of file +} diff --git a/ENI2/Excel/ExcelWriter.cs b/ENI2/Excel/ExcelWriter.cs index de1c3ab7..34db3b88 100644 --- a/ENI2/Excel/ExcelWriter.cs +++ b/ENI2/Excel/ExcelWriter.cs @@ -26,7 +26,7 @@ namespace ENI2.Excel if (isRefSheet) filename = @"Excel\Reference_Sheet_DE.xlsx"; string refFilePath = System.IO.Path.Combine(Environment.CurrentDirectory, filename); - this._workBook = new XLWorkbook(refFilePath); + this.OpenWorkbookReadOnly(refFilePath); this.InitNameFields(); } @@ -1426,4 +1426,4 @@ namespace ENI2.Excel #endregion } -} \ No newline at end of file +} diff --git a/ENI2/SheetDisplayControls/CrewDepartureControl.xaml.cs b/ENI2/SheetDisplayControls/CrewDepartureControl.xaml.cs index 0f186fbd..c3d9e323 100644 --- a/ENI2/SheetDisplayControls/CrewDepartureControl.xaml.cs +++ b/ENI2/SheetDisplayControls/CrewDepartureControl.xaml.cs @@ -128,7 +128,8 @@ namespace ENI2.SheetDisplayControls { try { - using (var workbook = new XLWorkbook(ofd.FileName)) + using (var stream = new FileStream(ofd.FileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) + using (var workbook = new XLWorkbook(stream)) { var worksheet = workbook.Worksheet(1); // Get first worksheet var rows = worksheet.RangeUsed().RowsUsed().Skip(1); // Skip header row if present diff --git a/ENI2/SheetDisplayControls/CrewPreArrivalControl.xaml.cs b/ENI2/SheetDisplayControls/CrewPreArrivalControl.xaml.cs index 0bf4e98f..57d89f44 100644 --- a/ENI2/SheetDisplayControls/CrewPreArrivalControl.xaml.cs +++ b/ENI2/SheetDisplayControls/CrewPreArrivalControl.xaml.cs @@ -168,7 +168,8 @@ namespace ENI2.SheetDisplayControls { try { - using (var workbook = new XLWorkbook(ofd.FileName)) + using (var stream = new FileStream(ofd.FileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) + using (var workbook = new XLWorkbook(stream)) { var worksheet = workbook.Worksheet(1); // Get first worksheet var rows = worksheet.RangeUsed().RowsUsed().Skip(1); // Skip header row if present diff --git a/ENI2/SheetDisplayControls/PassengerDepartureControl.xaml.cs b/ENI2/SheetDisplayControls/PassengerDepartureControl.xaml.cs index 8e93f552..5abb1965 100644 --- a/ENI2/SheetDisplayControls/PassengerDepartureControl.xaml.cs +++ b/ENI2/SheetDisplayControls/PassengerDepartureControl.xaml.cs @@ -146,7 +146,8 @@ namespace ENI2.SheetDisplayControls { try { - using (var workbook = new XLWorkbook(ofd.FileName)) + using (var stream = new FileStream(ofd.FileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) + using (var workbook = new XLWorkbook(stream)) { var worksheet = workbook.Worksheet(1); // Get first worksheet var rows = worksheet.RangeUsed().RowsUsed().Skip(1); // Skip header row if present diff --git a/ENI2/SheetDisplayControls/PassengerPreArrivalControl.xaml.cs b/ENI2/SheetDisplayControls/PassengerPreArrivalControl.xaml.cs index 8beaa753..8bbb5361 100644 --- a/ENI2/SheetDisplayControls/PassengerPreArrivalControl.xaml.cs +++ b/ENI2/SheetDisplayControls/PassengerPreArrivalControl.xaml.cs @@ -128,7 +128,8 @@ namespace ENI2.SheetDisplayControls { try { - using (var workbook = new XLWorkbook(ofd.FileName)) + using (var stream = new FileStream(ofd.FileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) + using (var workbook = new XLWorkbook(stream)) { var worksheet = workbook.Worksheet(1); // Get first worksheet var rows = worksheet.RangeUsed().RowsUsed().Skip(1); // Skip header row if present diff --git a/ENI2/SheetDisplayControls/PortControl.xaml.cs b/ENI2/SheetDisplayControls/PortControl.xaml.cs index 988fca9e..2a9e957d 100644 --- a/ENI2/SheetDisplayControls/PortControl.xaml.cs +++ b/ENI2/SheetDisplayControls/PortControl.xaml.cs @@ -520,7 +520,8 @@ namespace ENI2.SheetDisplayControls { try { - using (var workbook = new XLWorkbook(ofd.FileName)) + using (var stream = new FileStream(ofd.FileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) + using (var workbook = new XLWorkbook(stream)) { var worksheet = workbook.Worksheet(1); // Get first worksheet var rows = worksheet.RangeUsed().RowsUsed().Skip(3); // Skip first three rows diff --git a/bsmd.ExcelReadService/ExcelReader.cs b/bsmd.ExcelReadService/ExcelReader.cs index f344d063..b7f68eb2 100644 --- a/bsmd.ExcelReadService/ExcelReader.cs +++ b/bsmd.ExcelReadService/ExcelReader.cs @@ -36,7 +36,23 @@ namespace bsmd.ExcelReadService this._excelApp.DisplayAlerts = false; this._excelWorkbooks = _excelApp.Workbooks; - this._portcall = _excelWorkbooks.Open(filePath, 0, true, 5, "", "", false, XlPlatform.xlWindows, "", false, false, 0, false, false, false); + this._portcall = _excelWorkbooks.Open( + filePath, + UpdateLinks: 0, + ReadOnly: true, + Format: 5, + Password: "", + WriteResPassword: "", + IgnoreReadOnlyRecommended: true, + Origin: XlPlatform.xlWindows, + Delimiter: "", + Editable: false, + Notify: false, + Converter: 0, + AddToMru: false, + Local: false, + CorruptLoad: false); + this._portcall.ChangeFileAccess(XlFileAccess.xlReadOnly); _nameDict = new Dictionary(); int bookCnt = 0; foreach(Name name in _portcall.Names) From 77c0491aa11e8ffb2f2d3589e2eec64800a57482 Mon Sep 17 00:00:00 2001 From: Daniel Schick Date: Mon, 26 Jan 2026 14:45:59 +0100 Subject: [PATCH 03/12] Color tab if the sheet contains a changed cell in ExcelComparer --- ENI2/Excel/ExcelComparer.cs | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/ENI2/Excel/ExcelComparer.cs b/ENI2/Excel/ExcelComparer.cs index 28f32595..f13d5d04 100644 --- a/ENI2/Excel/ExcelComparer.cs +++ b/ENI2/Excel/ExcelComparer.cs @@ -55,8 +55,7 @@ namespace ENI2.Excel using (var sourceStream = new FileStream(sourcePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) using (var sourceWorkbook = new XLWorkbook(sourceStream)) - using (var comparisonStream = new FileStream(comparisonFileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) - using (var comparisonWorkbook = new XLWorkbook(comparisonStream)) + using (var comparisonWorkbook = new XLWorkbook(comparisonFileName)) { // Es werden Zellen der "used range" miteinander verglichen foreach (var sourceSheet in sourceWorkbook.Worksheets) @@ -78,6 +77,7 @@ namespace ENI2.Excel { int maxRows = Math.Max(sourceRows, targetRows); int maxCols = Math.Max(sourceCols, targetCols); + bool sheetHasDiffs = false; for (int rowidx = 1; rowidx <= maxRows; rowidx++) { @@ -113,6 +113,7 @@ namespace ENI2.Excel var cellToHighlight = targetSheet.Cell(rowidx, colidx); cellToHighlight.Style.Fill.BackgroundColor = diffColor; counter++; + sheetHasDiffs = true; } } else if (targetText == null) @@ -122,6 +123,7 @@ namespace ENI2.Excel var cellToHighlight = targetSheet.Cell(rowidx, colidx); cellToHighlight.Style.Fill.BackgroundColor = diffColor; counter++; + sheetHasDiffs = true; } } else if ((sourceText != null) && (targetText != null)) @@ -131,10 +133,16 @@ namespace ENI2.Excel var cellToHighlight = targetSheet.Cell(rowidx, colidx); cellToHighlight.Style.Fill.BackgroundColor = diffColor; counter++; + sheetHasDiffs = true; } } } } + + if (sheetHasDiffs) + { + targetSheet.SetTabColor(diffColor); + } } else { From a1f6e6c11348fabb2616d1ffde2a12aa84344fb1 Mon Sep 17 00:00:00 2001 From: Daniel Schick Date: Mon, 26 Jan 2026 18:56:24 +0100 Subject: [PATCH 04/12] Changed validation rules for WAS elements (Waste) --- ENI2/DetailRootControl.xaml.cs | 167 ++++++++++++++++++++++++++++----- bsmd.database/RuleEngine.cs | 30 ++++++ bsmd.database/Waste.cs | 10 +- misc/WAS-Regulation.docx | Bin 0 -> 16398 bytes 4 files changed, 181 insertions(+), 26 deletions(-) create mode 100644 misc/WAS-Regulation.docx diff --git a/ENI2/DetailRootControl.xaml.cs b/ENI2/DetailRootControl.xaml.cs index d6066145..3a7b4a1f 100644 --- a/ENI2/DetailRootControl.xaml.cs +++ b/ENI2/DetailRootControl.xaml.cs @@ -1027,35 +1027,37 @@ namespace ENI2 #region Kiel Canal Timing Plausibility - if (!this.Core.IsTransit && (secMessage?.Elements.Count > 0) && (noanodMessage?.Elements.Count > 0)) { - SEC sec = secMessage.Elements[0] as SEC; - NOA_NOD noa_nod = noanodMessage.Elements[0] as NOA_NOD; - - if (sec.KielCanalPassagePlanned ?? false) + if (!this.Core.IsTransit && (secMessage?.Elements.Count > 0) && (noanodMessage?.Elements.Count > 0)) { - // Überprüfung, ob die eingehende NOK-Durchfahrt auch wirklich innerhalb der eingehenden Reise liegt (bei VISIT) - bool isValidIncoming = (noa_nod.ETDFromLastPort < sec.KielCanalPassagePlannedIncomming) && - (sec.KielCanalPassagePlannedIncomming < noa_nod.ETAToPortOfCall); - if (!sec.KielCanalPassagePlannedIncomming.HasValue) isValidIncoming = true; + SEC sec = secMessage.Elements[0] as SEC; + NOA_NOD noa_nod = noanodMessage.Elements[0] as NOA_NOD; - if(!isValidIncoming) + if (sec.KielCanalPassagePlanned ?? false) { - MessageViolation mv = RuleEngine.CreateViolation(ValidationCode.IMPLAUSIBLE, "Kiel Canal incoming implausible (ETD / ETA ports)!", null, "Kiel Canal timing", null, "SEC"); - mv.MessageGroupName = Properties.Resources.textOverview; - vViolations.Add(mv); - } + // Überprüfung, ob die eingehende NOK-Durchfahrt auch wirklich innerhalb der eingehenden Reise liegt (bei VISIT) + bool isValidIncoming = (noa_nod.ETDFromLastPort < sec.KielCanalPassagePlannedIncomming) && + (sec.KielCanalPassagePlannedIncomming < noa_nod.ETAToPortOfCall); + if (!sec.KielCanalPassagePlannedIncomming.HasValue) isValidIncoming = true; + + if (!isValidIncoming) + { + MessageViolation mv = RuleEngine.CreateViolation(ValidationCode.IMPLAUSIBLE, "Kiel Canal incoming implausible (ETD / ETA ports)!", null, "Kiel Canal timing", null, "SEC"); + mv.MessageGroupName = Properties.Resources.textOverview; + vViolations.Add(mv); + } - bool isValidOutgoing = (noa_nod.ETDFromPortOfCall < sec.KielCanalPassagePlannedOutgoing) && - ((noa_nod.NextPort == "ZZUKN") || (sec.KielCanalPassagePlannedOutgoing < noa_nod.ETAToNextPort)); - if (!sec.KielCanalPassagePlannedOutgoing.HasValue) isValidOutgoing = true; + bool isValidOutgoing = (noa_nod.ETDFromPortOfCall < sec.KielCanalPassagePlannedOutgoing) && + ((noa_nod.NextPort == "ZZUKN") || (sec.KielCanalPassagePlannedOutgoing < noa_nod.ETAToNextPort)); + if (!sec.KielCanalPassagePlannedOutgoing.HasValue) isValidOutgoing = true; - if(!isValidOutgoing) - { - MessageViolation mv = RuleEngine.CreateViolation(ValidationCode.IMPLAUSIBLE, "Kiel Canal outgoing implausible (ETD / ETA ports)!", null, "Kiel Canal timing", null, "SEC"); - mv.MessageGroupName = Properties.Resources.textOverview; - vViolations.Add(mv); + if (!isValidOutgoing) + { + MessageViolation mv = RuleEngine.CreateViolation(ValidationCode.IMPLAUSIBLE, "Kiel Canal outgoing implausible (ETD / ETA ports)!", null, "Kiel Canal timing", null, "SEC"); + mv.MessageGroupName = Properties.Resources.textOverview; + vViolations.Add(mv); + } } } } @@ -1212,6 +1214,127 @@ namespace ENI2 #endregion + #region WAS special max capa rules regarding next port + + { + // see WAS-Regulation.docx in parent projects misc folder + if ((noanodMessage?.Elements.Count > 0) && wasMessage?.Elements.Count > 0) + { + NOA_NOD noa_nod = noanodMessage.Elements[0] as NOA_NOD; + WAS was = wasMessage.Elements[0] as WAS; + + bool isSpecialNextPort = RuleEngine.IsSpecialNextPort(noa_nod.NextPort); + + if (isSpecialNextPort) + { + foreach (Waste waste in was.Waste) + { + switch (waste.WasteType) + { + case 101: + case 102: + case 103: + case 104: + case 105: + case 401: + if (waste.WasteAmountRetained_MTQ > waste.WasteCapacity_MTQ * 0.5) + { + MessageViolation mv = RuleEngine.CreateViolation(ValidationCode.IMPLAUSIBLE, "Acc. to EU Regulation 2022/89 the amount retained on board is noticeably", null, "WAS", waste.Identifier, "WAS"); + mv.MessageGroupName = Properties.Resources.textPortNotification; + vViolations.Add(mv); + } + break; + case 501: + case 502: + case 503: + case 504: + case 505: + case 506: + case 507: + case 508: + case 509: + case 510: + case 511: + if (waste.WasteAmountRetained_MTQ > waste.WasteCapacity_MTQ * 0.25) + { + MessageViolation mv = RuleEngine.CreateViolation(ValidationCode.IMPLAUSIBLE, "Acc. to EU Regulation 2022/89 the amount retained on board is noticeably", null, "WAS", waste.Identifier, "WAS"); + mv.MessageGroupName = Properties.Resources.textPortNotification; + vViolations.Add(mv); + } + break; + case 601: + case 602: + if (waste.WasteAmountRetained_MTQ > waste.WasteCapacity_MTQ * 0.75) + { + MessageViolation mv = RuleEngine.CreateViolation(ValidationCode.IMPLAUSIBLE, "Acc. to EU Regulation 2022/89 the amount retained on board is noticeably", null, "WAS", waste.Identifier, "WAS"); + mv.MessageGroupName = Properties.Resources.textPortNotification; + vViolations.Add(mv); + } + break; + } + } + } + else + { + foreach (Waste waste in was.Waste) + { + switch (waste.WasteType) + { + case 101: + case 102: + case 103: + case 104: + case 105: + if (waste.WasteAmountRetained_MTQ > waste.WasteCapacity_MTQ * 0.25) + { + MessageViolation mv = RuleEngine.CreateViolation(ValidationCode.IMPLAUSIBLE, "Acc. to EU Regulation 2022/89 the amount retained on board is noticeably", null, "WAS", waste.Identifier, "WAS"); + mv.MessageGroupName = Properties.Resources.textPortNotification; + vViolations.Add(mv); + } + break; + case 401: + if (waste.WasteAmountRetained_MTQ > waste.WasteCapacity_MTQ * 0.5) + { + MessageViolation mv = RuleEngine.CreateViolation(ValidationCode.IMPLAUSIBLE, "Acc. to EU Regulation 2022/89 the amount retained on board is noticeably", null, "WAS", waste.Identifier, "WAS"); + mv.MessageGroupName = Properties.Resources.textPortNotification; + vViolations.Add(mv); + } + break; + case 501: + case 502: + case 503: + case 504: + case 505: + case 506: + case 507: + case 508: + case 509: + case 510: + case 511: + if (waste.WasteAmountRetained_MTQ > waste.WasteCapacity_MTQ * 0.2) + { + MessageViolation mv = RuleEngine.CreateViolation(ValidationCode.IMPLAUSIBLE, "Acc. to EU Regulation 2022/89 the amount retained on board is noticeably", null, "WAS", waste.Identifier, "WAS"); + mv.MessageGroupName = Properties.Resources.textPortNotification; + vViolations.Add(mv); + } + break; + case 601: + case 602: + if (waste.WasteAmountRetained_MTQ > waste.WasteCapacity_MTQ * 0.25) + { + MessageViolation mv = RuleEngine.CreateViolation(ValidationCode.IMPLAUSIBLE, "Acc. to EU Regulation 2022/89 the amount retained on board is noticeably", null, "WAS", waste.Identifier, "WAS"); + mv.MessageGroupName = Properties.Resources.textPortNotification; + vViolations.Add(mv); + } + break; + } + } + } + } + } + + #endregion + #endregion foreach (MessageError me in vErrors) diff --git a/bsmd.database/RuleEngine.cs b/bsmd.database/RuleEngine.cs index f6c682d6..082712c4 100644 --- a/bsmd.database/RuleEngine.cs +++ b/bsmd.database/RuleEngine.cs @@ -97,6 +97,22 @@ namespace bsmd.database #endregion + #region for extra waste validation + + private static readonly HashSet SpecialNextPortPrefixes = new HashSet + { + "BE", "BG", "DK", "DE", "EE", "FI", "FR", "GR", "IR", "IT", + "HR", "LV", "LT", "LU", "MT", "NL", "AT", "PL", "PT", "RO", + "SE", "SK", "SL", "ES", "CZ", "HU", "CY", "NO", "IS", "GB", "GI" + }; + + private static readonly HashSet SpecialNextPortExact = new HashSet + { + "RUPRI", "RUULU", "RULED", "RUBLT", "RUKGD", "RUVYS" + }; + + #endregion + public enum LocodeMode { STANDARD, @@ -131,6 +147,20 @@ namespace bsmd.database public static LocodeValidHandler LocodeChecker { get { return _locodeChecker; } } public static NationalityValidHandler NationalityChecker { get { return _nationalityChecker; } } + /// + /// Used to test for special next port values for waste messages + /// + /// a locode + /// true if the next port is a special waste port + public static bool IsSpecialNextPort(string nextPort) + { + if (string.IsNullOrEmpty(nextPort) || nextPort.Length < 2) + return false; + + return SpecialNextPortExact.Contains(nextPort) || + SpecialNextPortPrefixes.Contains(nextPort.Substring(0, 2)); + } + #region public static property validation public static void RegisterLocodeChecker(LocodeValidHandler handler) { _locodeChecker = handler; } diff --git a/bsmd.database/Waste.cs b/bsmd.database/Waste.cs index feffc008..42e2b6f2 100644 --- a/bsmd.database/Waste.cs +++ b/bsmd.database/Waste.cs @@ -266,11 +266,13 @@ namespace bsmd.database if (this.WasteAmountGeneratedTillNextPort_MTQ >= 10000) errors.Add(RuleEngine.CreateError(ValidationCode.IMPLAUSIBLE, "Waste generated till next port too high", null, this.Title, this.Identifier, this.Tablename)); - if(this.WasteDisposalAmount_MTQ > this.WasteCapacity_MTQ) - violations.Add(RuleEngine.CreateViolation(ValidationCode.IMPLAUSIBLE, "Disposal greater than capacity!", null, this.Title, this.Identifier, this.Tablename)); + // Removed this for version 7.2.14 (new rules depending on next port implemented in ENI / DetailRootControl.cs) - if((this.WasteAmountGeneratedTillNextPort_MTQ + this.WasteAmountRetained_MTQ) > this.WasteCapacity_MTQ) - violations.Add(RuleEngine.CreateViolation(ValidationCode.IMPLAUSIBLE, "Waste generated+retained greater than capacity!", null, this.Title, this.Identifier, this.Tablename)); + // if(this.WasteDisposalAmount_MTQ > this.WasteCapacity_MTQ) + // violations.Add(RuleEngine.CreateViolation(ValidationCode.IMPLAUSIBLE, "Disposal greater than capacity!", null, this.Title, this.Identifier, this.Tablename)); + + // if((this.WasteAmountGeneratedTillNextPort_MTQ + this.WasteAmountRetained_MTQ) > this.WasteCapacity_MTQ) + // violations.Add(RuleEngine.CreateViolation(ValidationCode.IMPLAUSIBLE, "Waste generated+retained greater than capacity!", null, this.Title, this.Identifier, this.Tablename)); } #endregion diff --git a/misc/WAS-Regulation.docx b/misc/WAS-Regulation.docx new file mode 100644 index 0000000000000000000000000000000000000000..9f016a0016451e8e45c6e8b28525753e21896e04 GIT binary patch literal 16398 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 Date: Tue, 27 Jan 2026 11:24:19 +0100 Subject: [PATCH 05/12] Validation now runs async and hopefully solves the problem of some users where the app got unresponsive in the meantime --- ENI2/DetailRootControl.xaml.cs | 218 +++++++++++++++++++++++---------- 1 file changed, 150 insertions(+), 68 deletions(-) diff --git a/ENI2/DetailRootControl.xaml.cs b/ENI2/DetailRootControl.xaml.cs index 3a7b4a1f..606acd8a 100644 --- a/ENI2/DetailRootControl.xaml.cs +++ b/ENI2/DetailRootControl.xaml.cs @@ -17,6 +17,7 @@ using ENI2.EditControls; using System.Windows.Input; using System.Linq; using ENI2.SheetDisplayControls; +using System.Threading.Tasks; namespace ENI2 { @@ -34,6 +35,9 @@ namespace ENI2 // private readonly Dictionary messageClassControlDict = new Dictionary(); private readonly object messageListLock = new object(); private readonly HighlightService highlightService = new HighlightService(); + private readonly object validationLock = new object(); + private Task activeValidationTask = null; + private bool pendingShowMessages = false; // Referenzen für Fehler/Violation Dialoge (können, müssen aber nicht offen bleiben) protected ErrorListDialog _errorListDialog = null; @@ -703,7 +707,13 @@ namespace ENI2 private void DetailControl_RequestSendValidation() { - this.Validate(false, out _, out List errorList); + DetailControl_RequestSendValidationAsync(); + } + + private async void DetailControl_RequestSendValidationAsync() + { + ValidationResult result = await ValidateAndApplyAsync(false); + List errorList = result.Errors; foreach (Message aMessage in this._messages) { @@ -777,22 +787,61 @@ namespace ENI2 } } - private void DetailControl_RequestValidate(bool showDialog) + private async void DetailControl_RequestValidate(bool showDialog) { - this.Validate(showDialog, out _, out _); + await ValidateAndApplyAsync(showDialog); } - private void Validate(bool showMessages, out List vViolations, out List vErrors) + private async Task ValidateAndApplyAsync(bool showMessages) { - vViolations = new List(); - vErrors = new List(); + Task validationTask = null; + lock (validationLock) + { + if (activeValidationTask != null && !activeValidationTask.IsCompleted) + { + if (showMessages) + pendingShowMessages = true; + validationTask = activeValidationTask; + } + else + { + pendingShowMessages = showMessages; + activeValidationTask = ValidateAndApplyCoreAsync(); + validationTask = activeValidationTask; + } + } - // TODO: clear highlighting + return await validationTask; + } + private async Task ValidateAndApplyCoreAsync() + { Util.UIHelper.SetBusyState(); + ApplyCrewEffectsWarningSuppression(); + + List messagesSnapshot = _messages.ToList(); + ValidationResult result = await Task.Run(() => ValidateCore(messagesSnapshot)); + + bool showMessages; + lock (validationLock) + { + showMessages = pendingShowMessages; + pendingShowMessages = false; + activeValidationTask = null; + } + + ApplyValidationResult(result, showMessages); + return result; + } + + private ValidationResult ValidateCore(List messagesSnapshot) + { + List vViolations = new List(); + List vErrors = new List(); + Dictionary counts = new Dictionary(); RuleEngine ruleEngine = new RuleEngine(); - foreach (Message aMessage in _messages) + foreach (Message aMessage in messagesSnapshot) { if (!aMessage.EvaluateForValidation(this.Core.IsTransit)) continue; @@ -800,20 +849,13 @@ namespace ENI2 List violations = new List(); ruleEngine.ValidateMessage(aMessage, out errors, out violations); - if (errors.Count > 0) - aMessage.ErrorCount = errors.Count; - else - aMessage.ErrorCount = null; - if (violations.Count > 0) + MessageValidationCounts messageCounts = new MessageValidationCounts { - aMessage.ViolationCount = violations.Count; - aMessage.PositionViolationCount = violations.Count(v => !v.Identifier.IsNullOrEmpty()); - } - else - { - aMessage.ViolationCount = null; - aMessage.PositionViolationCount = null; - } + ErrorCount = errors.Count > 0 ? (int?)errors.Count : null, + ViolationCount = violations.Count > 0 ? (int?)violations.Count : null, + PositionViolationCount = violations.Count > 0 ? (int?)violations.Count(v => !v.Identifier.IsNullOrEmpty()) : null + }; + counts[aMessage] = messageCounts; string messageGroup = this.MessageGroupForMessage(aMessage); @@ -831,20 +873,20 @@ namespace ENI2 #region 12.11.18 / 6.3.21 / 23.5.22 / 26.10.24: globale Plausi-Prüfungen - Message crewaMessage = _messages.Find(message => message.MessageNotificationClass == Message.NotificationClass.CREWA); - Message crewdMessage = _messages.Find(message => message.MessageNotificationClass == Message.NotificationClass.CREWD); - Message pasaMessage = _messages.Find(message => message.MessageNotificationClass == Message.NotificationClass.PASA); - Message pasdMessage = _messages.Find(message => message.MessageNotificationClass == Message.NotificationClass.PASD); - Message pobaMessage = _messages.Find(message => message.MessageNotificationClass == Message.NotificationClass.POBA); - Message pobdMessage = _messages.Find(message => message.MessageNotificationClass == Message.NotificationClass.POBD); - Message secMessage = _messages.Find(message => message.MessageNotificationClass == Message.NotificationClass.SEC); - Message noanodMessage = _messages.Find(message => message.MessageNotificationClass == Message.NotificationClass.NOA_NOD); - Message mdhMessage = _messages.Find(message => message.MessageNotificationClass == Message.NotificationClass.MDH); - Message was_rcptMessage = _messages.Find(message => message.MessageNotificationClass == Message.NotificationClass.WAS_RCPT); - Message wasMessage = _messages.Find(message => message.MessageNotificationClass == Message.NotificationClass.WAS); - Message servMessage = _messages.Find(message => message.MessageNotificationClass == Message.NotificationClass.SERV); - Message statMessage = _messages.Find(message => message.MessageNotificationClass == Message.NotificationClass.STAT); - Message pre72hMessage = _messages.Find(message => message.MessageNotificationClass == Message.NotificationClass.PRE72H); + Message crewaMessage = messagesSnapshot.Find(message => message.MessageNotificationClass == Message.NotificationClass.CREWA); + Message crewdMessage = messagesSnapshot.Find(message => message.MessageNotificationClass == Message.NotificationClass.CREWD); + Message pasaMessage = messagesSnapshot.Find(message => message.MessageNotificationClass == Message.NotificationClass.PASA); + Message pasdMessage = messagesSnapshot.Find(message => message.MessageNotificationClass == Message.NotificationClass.PASD); + Message pobaMessage = messagesSnapshot.Find(message => message.MessageNotificationClass == Message.NotificationClass.POBA); + Message pobdMessage = messagesSnapshot.Find(message => message.MessageNotificationClass == Message.NotificationClass.POBD); + Message secMessage = messagesSnapshot.Find(message => message.MessageNotificationClass == Message.NotificationClass.SEC); + Message noanodMessage = messagesSnapshot.Find(message => message.MessageNotificationClass == Message.NotificationClass.NOA_NOD); + Message mdhMessage = messagesSnapshot.Find(message => message.MessageNotificationClass == Message.NotificationClass.MDH); + Message was_rcptMessage = messagesSnapshot.Find(message => message.MessageNotificationClass == Message.NotificationClass.WAS_RCPT); + Message wasMessage = messagesSnapshot.Find(message => message.MessageNotificationClass == Message.NotificationClass.WAS); + Message servMessage = messagesSnapshot.Find(message => message.MessageNotificationClass == Message.NotificationClass.SERV); + Message statMessage = messagesSnapshot.Find(message => message.MessageNotificationClass == Message.NotificationClass.STAT); + Message pre72hMessage = messagesSnapshot.Find(message => message.MessageNotificationClass == Message.NotificationClass.PRE72H); #region CREW / PAS Count Plausibility @@ -984,22 +1026,6 @@ namespace ENI2 #endregion - #region 4.1.23 no CREW effects warning for DE - if (crewaMessage != null) - { - MessageViolation mv = crewaMessage.ViolationList.Find((x) => x.PropertyName.Equals("Effects") && (x.ViolationCode == (int)ValidationCode.TRUNCATE)); - if ((mv != null) && !Core.IsDK) - crewaMessage.ViolationList.Remove(mv); - } - - if(crewdMessage != null) - { - MessageViolation mvd = crewdMessage.ViolationList.Find((x) => x.PropertyName.Equals("Effects") && (x.ViolationCode == (int)ValidationCode.TRUNCATE)); - if ((mvd != null) && !Core.IsDK) - crewdMessage.ViolationList.Remove(mvd); - } - #endregion - #region WAS_RCPT double numbers Dictionary identDict = new Dictionary(); @@ -1337,17 +1363,8 @@ namespace ENI2 #endregion - foreach (MessageError me in vErrors) - { - this.highlightService.HighlightError(me, this.GetContainerForMessageGroupName(me.MessageGroupName)); - } - foreach (MessageViolation mv in vViolations) - { - this.highlightService.HighlightViolation(mv, this.GetContainerForMessageGroupName(mv.MessageGroupName)); - } - // "neue" regelbasierte Validierung: Hier werden die einzelnen Regeln geprüft. - bsmd.database.ValidationRule.PrepareNameLookupDict(this.Core, this._messages); + bsmd.database.ValidationRule.PrepareNameLookupDict(this.Core, messagesSnapshot); List validationRules = DBManager.Instance.GetValidationRules(); @@ -1374,10 +1391,34 @@ namespace ENI2 } } + return new ValidationResult(vViolations, vErrors, counts); + } + + private void ApplyValidationResult(ValidationResult result, bool showMessages) + { + // TODO: clear highlighting + foreach (KeyValuePair entry in result.Counts) + { + Message aMessage = entry.Key; + MessageValidationCounts messageCounts = entry.Value; + aMessage.ErrorCount = messageCounts.ErrorCount; + aMessage.ViolationCount = messageCounts.ViolationCount; + aMessage.PositionViolationCount = messageCounts.PositionViolationCount; + } + + foreach (MessageError me in result.Errors) + { + this.highlightService.HighlightError(me, this.GetContainerForMessageGroupName(me.MessageGroupName)); + } + foreach (MessageViolation mv in result.Violations) + { + this.highlightService.HighlightViolation(mv, this.GetContainerForMessageGroupName(mv.MessageGroupName)); + } + if (showMessages) { // Show error and violation dialog - if (vErrors.Count > 0) + if (result.Errors.Count > 0) { if(this._errorListDialog == null) { @@ -1392,10 +1433,10 @@ namespace ENI2 { this._errorListDialog.BringUp(); } - this._errorListDialog.Errors = vErrors; + this._errorListDialog.Errors = result.Errors; } - if (vViolations.Count > 0) + if (result.Violations.Count > 0) { if(this._violationListDialog == null) { @@ -1410,17 +1451,58 @@ namespace ENI2 { this._violationListDialog.BringUp(); } - _violationListDialog.Violations = vViolations; - } + _violationListDialog.Violations = result.Violations; + } - if((vErrors.Count == 0) && (vViolations.Count == 0)) + if((result.Errors.Count == 0) && (result.Violations.Count == 0)) { MessageBox.Show(Properties.Resources.textValidationOK, Properties.Resources.textValidation, MessageBoxButton.OK, MessageBoxImage.Information); } - } } + private void ApplyCrewEffectsWarningSuppression() + { + // 4.1.23 no CREW effects warning for DE + Message crewaMessage = _messages.Find(message => message.MessageNotificationClass == Message.NotificationClass.CREWA); + Message crewdMessage = _messages.Find(message => message.MessageNotificationClass == Message.NotificationClass.CREWD); + + if (crewaMessage != null) + { + MessageViolation mv = crewaMessage.ViolationList.Find((x) => x.PropertyName.Equals("Effects") && (x.ViolationCode == (int)ValidationCode.TRUNCATE)); + if ((mv != null) && !Core.IsDK) + crewaMessage.ViolationList.Remove(mv); + } + + if(crewdMessage != null) + { + MessageViolation mvd = crewdMessage.ViolationList.Find((x) => x.PropertyName.Equals("Effects") && (x.ViolationCode == (int)ValidationCode.TRUNCATE)); + if ((mvd != null) && !Core.IsDK) + crewdMessage.ViolationList.Remove(mvd); + } + } + + private sealed class ValidationResult + { + internal ValidationResult(List violations, List errors, Dictionary counts) + { + Violations = violations; + Errors = errors; + Counts = counts; + } + + internal List Violations { get; } + internal List Errors { get; } + internal Dictionary Counts { get; } + } + + private sealed class MessageValidationCounts + { + internal int? ErrorCount { get; set; } + internal int? ViolationCount { get; set; } + internal int? PositionViolationCount { get; set; } + } + private void _errorListDialog_RefreshClicked() { DetailControl_RequestValidate(true); From 9d4f6083836f7c61a39e06d48c5c423728b78a5c Mon Sep 17 00:00:00 2001 From: Daniel Schick Date: Wed, 28 Jan 2026 07:50:52 +0100 Subject: [PATCH 06/12] fixed message group name settings in extra WAS validation --- ENI2/DetailRootControl.xaml.cs | 64 ++++++++++++++++++---------------- 1 file changed, 33 insertions(+), 31 deletions(-) diff --git a/ENI2/DetailRootControl.xaml.cs b/ENI2/DetailRootControl.xaml.cs index 606acd8a..e6910ef1 100644 --- a/ENI2/DetailRootControl.xaml.cs +++ b/ENI2/DetailRootControl.xaml.cs @@ -838,7 +838,7 @@ namespace ENI2 { List vViolations = new List(); List vErrors = new List(); - Dictionary counts = new Dictionary(); + Dictionary counts = new Dictionary(); RuleEngine ruleEngine = new RuleEngine(); foreach (Message aMessage in messagesSnapshot) @@ -855,7 +855,7 @@ namespace ENI2 ViolationCount = violations.Count > 0 ? (int?)violations.Count : null, PositionViolationCount = violations.Count > 0 ? (int?)violations.Count(v => !v.Identifier.IsNullOrEmpty()) : null }; - counts[aMessage] = messageCounts; + counts[aMessage] = messageCounts; string messageGroup = this.MessageGroupForMessage(aMessage); @@ -871,7 +871,7 @@ namespace ENI2 vViolations.AddRange(violations); } - #region 12.11.18 / 6.3.21 / 23.5.22 / 26.10.24: globale Plausi-Prüfungen + #region 12.11.18 / 6.3.21 / 23.5.22 / 26.10.24 / 27.1.26: globale Plausi-Prüfungen Message crewaMessage = messagesSnapshot.Find(message => message.MessageNotificationClass == Message.NotificationClass.CREWA); Message crewdMessage = messagesSnapshot.Find(message => message.MessageNotificationClass == Message.NotificationClass.CREWD); @@ -1243,6 +1243,8 @@ namespace ENI2 #region WAS special max capa rules regarding next port { + string wasMessageGroup = this.MessageGroupForMessage(wasMessage); + // see WAS-Regulation.docx in parent projects misc folder if ((noanodMessage?.Elements.Count > 0) && wasMessage?.Elements.Count > 0) { @@ -1266,7 +1268,7 @@ namespace ENI2 if (waste.WasteAmountRetained_MTQ > waste.WasteCapacity_MTQ * 0.5) { MessageViolation mv = RuleEngine.CreateViolation(ValidationCode.IMPLAUSIBLE, "Acc. to EU Regulation 2022/89 the amount retained on board is noticeably", null, "WAS", waste.Identifier, "WAS"); - mv.MessageGroupName = Properties.Resources.textPortNotification; + mv.MessageGroupName = wasMessageGroup; vViolations.Add(mv); } break; @@ -1284,7 +1286,7 @@ namespace ENI2 if (waste.WasteAmountRetained_MTQ > waste.WasteCapacity_MTQ * 0.25) { MessageViolation mv = RuleEngine.CreateViolation(ValidationCode.IMPLAUSIBLE, "Acc. to EU Regulation 2022/89 the amount retained on board is noticeably", null, "WAS", waste.Identifier, "WAS"); - mv.MessageGroupName = Properties.Resources.textPortNotification; + mv.MessageGroupName = wasMessageGroup; vViolations.Add(mv); } break; @@ -1293,7 +1295,7 @@ namespace ENI2 if (waste.WasteAmountRetained_MTQ > waste.WasteCapacity_MTQ * 0.75) { MessageViolation mv = RuleEngine.CreateViolation(ValidationCode.IMPLAUSIBLE, "Acc. to EU Regulation 2022/89 the amount retained on board is noticeably", null, "WAS", waste.Identifier, "WAS"); - mv.MessageGroupName = Properties.Resources.textPortNotification; + mv.MessageGroupName = wasMessageGroup; vViolations.Add(mv); } break; @@ -1314,7 +1316,7 @@ namespace ENI2 if (waste.WasteAmountRetained_MTQ > waste.WasteCapacity_MTQ * 0.25) { MessageViolation mv = RuleEngine.CreateViolation(ValidationCode.IMPLAUSIBLE, "Acc. to EU Regulation 2022/89 the amount retained on board is noticeably", null, "WAS", waste.Identifier, "WAS"); - mv.MessageGroupName = Properties.Resources.textPortNotification; + mv.MessageGroupName = wasMessageGroup; vViolations.Add(mv); } break; @@ -1322,7 +1324,7 @@ namespace ENI2 if (waste.WasteAmountRetained_MTQ > waste.WasteCapacity_MTQ * 0.5) { MessageViolation mv = RuleEngine.CreateViolation(ValidationCode.IMPLAUSIBLE, "Acc. to EU Regulation 2022/89 the amount retained on board is noticeably", null, "WAS", waste.Identifier, "WAS"); - mv.MessageGroupName = Properties.Resources.textPortNotification; + mv.MessageGroupName = wasMessageGroup; vViolations.Add(mv); } break; @@ -1340,7 +1342,7 @@ namespace ENI2 if (waste.WasteAmountRetained_MTQ > waste.WasteCapacity_MTQ * 0.2) { MessageViolation mv = RuleEngine.CreateViolation(ValidationCode.IMPLAUSIBLE, "Acc. to EU Regulation 2022/89 the amount retained on board is noticeably", null, "WAS", waste.Identifier, "WAS"); - mv.MessageGroupName = Properties.Resources.textPortNotification; + mv.MessageGroupName = wasMessageGroup; vViolations.Add(mv); } break; @@ -1349,7 +1351,7 @@ namespace ENI2 if (waste.WasteAmountRetained_MTQ > waste.WasteCapacity_MTQ * 0.25) { MessageViolation mv = RuleEngine.CreateViolation(ValidationCode.IMPLAUSIBLE, "Acc. to EU Regulation 2022/89 the amount retained on board is noticeably", null, "WAS", waste.Identifier, "WAS"); - mv.MessageGroupName = Properties.Resources.textPortNotification; + mv.MessageGroupName = wasMessageGroup; vViolations.Add(mv); } break; @@ -1391,20 +1393,20 @@ namespace ENI2 } } - return new ValidationResult(vViolations, vErrors, counts); - } + return new ValidationResult(vViolations, vErrors, counts); + } private void ApplyValidationResult(ValidationResult result, bool showMessages) { // TODO: clear highlighting - foreach (KeyValuePair entry in result.Counts) - { - Message aMessage = entry.Key; - MessageValidationCounts messageCounts = entry.Value; - aMessage.ErrorCount = messageCounts.ErrorCount; - aMessage.ViolationCount = messageCounts.ViolationCount; - aMessage.PositionViolationCount = messageCounts.PositionViolationCount; - } + foreach (KeyValuePair entry in result.Counts) + { + Message aMessage = entry.Key; + MessageValidationCounts messageCounts = entry.Value; + aMessage.ErrorCount = messageCounts.ErrorCount; + aMessage.ViolationCount = messageCounts.ViolationCount; + aMessage.PositionViolationCount = messageCounts.PositionViolationCount; + } foreach (MessageError me in result.Errors) { @@ -1484,17 +1486,17 @@ namespace ENI2 private sealed class ValidationResult { - internal ValidationResult(List violations, List errors, Dictionary counts) - { - Violations = violations; - Errors = errors; - Counts = counts; - } - - internal List Violations { get; } - internal List Errors { get; } - internal Dictionary Counts { get; } - } + internal ValidationResult(List violations, List errors, Dictionary counts) + { + Violations = violations; + Errors = errors; + Counts = counts; + } + + internal List Violations { get; } + internal List Errors { get; } + internal Dictionary Counts { get; } + } private sealed class MessageValidationCounts { From 79ddbf15727effa94054c7a851cef27c64774540 Mon Sep 17 00:00:00 2001 From: Daniel Schick Date: Wed, 28 Jan 2026 08:35:41 +0100 Subject: [PATCH 07/12] Added a manual grid refresh after validation since this seems not to work automatically anymore --- ENI2/DetailRootControl.xaml.cs | 52 +++++++++++-------- .../OverViewDetailControl.xaml.cs | 13 +++-- 2 files changed, 38 insertions(+), 27 deletions(-) diff --git a/ENI2/DetailRootControl.xaml.cs b/ENI2/DetailRootControl.xaml.cs index e6910ef1..ee6bf533 100644 --- a/ENI2/DetailRootControl.xaml.cs +++ b/ENI2/DetailRootControl.xaml.cs @@ -838,7 +838,7 @@ namespace ENI2 { List vViolations = new List(); List vErrors = new List(); - Dictionary counts = new Dictionary(); + Dictionary counts = new Dictionary(); RuleEngine ruleEngine = new RuleEngine(); foreach (Message aMessage in messagesSnapshot) @@ -855,7 +855,7 @@ namespace ENI2 ViolationCount = violations.Count > 0 ? (int?)violations.Count : null, PositionViolationCount = violations.Count > 0 ? (int?)violations.Count(v => !v.Identifier.IsNullOrEmpty()) : null }; - counts[aMessage] = messageCounts; + counts[aMessage] = messageCounts; string messageGroup = this.MessageGroupForMessage(aMessage); @@ -1393,20 +1393,20 @@ namespace ENI2 } } - return new ValidationResult(vViolations, vErrors, counts); - } + return new ValidationResult(vViolations, vErrors, counts); + } private void ApplyValidationResult(ValidationResult result, bool showMessages) { // TODO: clear highlighting - foreach (KeyValuePair entry in result.Counts) - { - Message aMessage = entry.Key; - MessageValidationCounts messageCounts = entry.Value; - aMessage.ErrorCount = messageCounts.ErrorCount; - aMessage.ViolationCount = messageCounts.ViolationCount; - aMessage.PositionViolationCount = messageCounts.PositionViolationCount; - } + foreach (KeyValuePair entry in result.Counts) + { + Message aMessage = entry.Key; + MessageValidationCounts messageCounts = entry.Value; + aMessage.ErrorCount = messageCounts.ErrorCount; + aMessage.ViolationCount = messageCounts.ViolationCount; + aMessage.PositionViolationCount = messageCounts.PositionViolationCount; + } foreach (MessageError me in result.Errors) { @@ -1461,6 +1461,12 @@ namespace ENI2 MessageBox.Show(Properties.Resources.textValidationOK, Properties.Resources.textValidation, MessageBoxButton.OK, MessageBoxImage.Information); } } + + if (controlCache.TryGetValue(Properties.Resources.textOverview, out DetailBaseControl overviewControl) && + overviewControl is OverViewDetailControl ovdc) + { + ovdc.RefreshMessageGrid(); + } } private void ApplyCrewEffectsWarningSuppression() @@ -1486,17 +1492,17 @@ namespace ENI2 private sealed class ValidationResult { - internal ValidationResult(List violations, List errors, Dictionary counts) - { - Violations = violations; - Errors = errors; - Counts = counts; - } - - internal List Violations { get; } - internal List Errors { get; } - internal Dictionary Counts { get; } - } + internal ValidationResult(List violations, List errors, Dictionary counts) + { + Violations = violations; + Errors = errors; + Counts = counts; + } + + internal List Violations { get; } + internal List Errors { get; } + internal Dictionary Counts { get; } + } private sealed class MessageValidationCounts { diff --git a/ENI2/DetailViewControls/OverViewDetailControl.xaml.cs b/ENI2/DetailViewControls/OverViewDetailControl.xaml.cs index 6a850f5f..cc97db5f 100644 --- a/ENI2/DetailViewControls/OverViewDetailControl.xaml.cs +++ b/ENI2/DetailViewControls/OverViewDetailControl.xaml.cs @@ -341,8 +341,8 @@ namespace ENI2.DetailViewControls } } - public void UpdateCore() - { + public void UpdateCore() + { this.UnregisterTextboxChange(this.textBoxDisplayId); this.textBoxDisplayId.DataContext = null; @@ -367,8 +367,13 @@ namespace ENI2.DetailViewControls //}; //sid.UpdateId(this.Core.DisplayId); //sid.Show(); - this.Core.IsDirty = false; // ist ja schon gespeichert.. - } + this.Core.IsDirty = false; // ist ja schon gespeichert.. + } + + internal void RefreshMessageGrid() + { + this.dataGridMessages?.Items?.Refresh(); + } #endregion From a34c5b19efcd1abb34502a4efdd4002518828b9e Mon Sep 17 00:00:00 2001 From: Daniel Schick Date: Wed, 28 Jan 2026 08:44:57 +0100 Subject: [PATCH 08/12] Bumped Version to 7.2.14.1 --- ENI2/ENI2.csproj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ENI2/ENI2.csproj b/ENI2/ENI2.csproj index 8fc4257d..3ebfe7f0 100644 --- a/ENI2/ENI2.csproj +++ b/ENI2/ENI2.csproj @@ -36,8 +36,8 @@ 5.4.0.0 true publish.html - 0 - 7.2.14.0 + 1 + 7.2.14.1 false true true From fa696172aa52c0915203e0913f716d0965cf9a98 Mon Sep 17 00:00:00 2001 From: Daniel Schick Date: Wed, 28 Jan 2026 08:57:09 +0100 Subject: [PATCH 09/12] Created release version 7.2.14 --- ENI2/App.config | 111 ++----------------- ENI2/ENI2.csproj | 8 +- ENI2/EditControls/CompareExcelDialog.xaml | 4 +- ENI2/EditControls/CopyDeclarationDialog.xaml | 23 ++-- ENI2/EditControls/CoreStatusInfoDialog.xaml | 4 +- ENI2/EditControls/EditRulesDialog.xaml | 6 +- ENI2/EditControls/ErrorListDialog.xaml | 2 +- ENI2/EditControls/MessageHistoryDialog.xaml | 6 +- ENI2/EditControls/NewDGItemDialog.xaml | 6 +- ENI2/EditControls/NewWithIdDialog.xaml | 26 ++--- ENI2/EditControls/SelectPortAreaDialog.xaml | 4 +- ENI2/EditControls/ViolationListDialog.xaml | 4 +- ENI2/EditControls/VisitIdDialog.xaml | 24 ++-- ENI2/MainWindow.xaml | 10 +- ENI2/Resources/EUREPORT.png | Bin 42234 -> 39708 bytes 15 files changed, 73 insertions(+), 165 deletions(-) diff --git a/ENI2/App.config b/ENI2/App.config index 8d424cb1..4c7c4bc1 100644 --- a/ENI2/App.config +++ b/ENI2/App.config @@ -1,18 +1,18 @@ - + -
+
-
+
- - + + @@ -26,119 +26,28 @@ 1000 - http://192.168.2.24/LockingService/LockingService.svc - - - BSMD ReportGenerator + http://192.168.2.24/LockingService/LockingService.svc - Initial Catalog=nswtest;Data Source=192.168.2.24\SQLEXPRESS;Uid=dfuser;pwd=dfpasswd;Persist Security Info=False;Connection Reset=false + Initial Catalog=nsw;Data Source=192.168.2.24\SQLEXPRESS;Uid=dfuser;pwd=dfpasswd;Persist Security Info=False;Connection Reset=false - - - - 825 - - - 450 - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/ENI2/ENI2.csproj b/ENI2/ENI2.csproj index 3ebfe7f0..d3d6ec8d 100644 --- a/ENI2/ENI2.csproj +++ b/ENI2/ENI2.csproj @@ -8,7 +8,7 @@ WinExe Properties ENI2 - ENI2Test + ENI2 v4.8.1 512 {60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} @@ -18,7 +18,7 @@ - eni_test\ + ENI2.publish\ true Web true @@ -28,9 +28,9 @@ false false true - http://192.168.2.24/eni_test/ + http://192.168.2.24/eni2.publish/ http://www.textbausteine.net/ - ENI Testversion + ENI Informatikbüro Daniel Schick NSW 5.4.0.0 diff --git a/ENI2/EditControls/CompareExcelDialog.xaml b/ENI2/EditControls/CompareExcelDialog.xaml index e77d7a89..c789a0dc 100644 --- a/ENI2/EditControls/CompareExcelDialog.xaml +++ b/ENI2/EditControls/CompareExcelDialog.xaml @@ -4,11 +4,11 @@ xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:ENI2.EditControls" - xmlns:enictrl="clr-namespace:ENI2.Controls" + xmlns:enictrl="clr-namespace:ENI2.Controls" xmlns:p="clr-namespace:ENI2.Properties" xmlns:xctk="http://schemas.xceed.com/wpf/xaml/toolkit" mc:Ignorable="d" - Title="{x:Static p:Resources.textCompareExcel}" Height="260" Width="600" Background="AliceBlue" Icon="/ENI2Test;component/Resources/bullet_ball_grey.ico"> + Title="{x:Static p:Resources.textCompareExcel}" Height="260" Width="600" Background="AliceBlue" Icon="/ENI2;component/Resources/bullet_ball_grey.ico"> diff --git a/ENI2/EditControls/CopyDeclarationDialog.xaml b/ENI2/EditControls/CopyDeclarationDialog.xaml index ab1978e3..46ad36ec 100644 --- a/ENI2/EditControls/CopyDeclarationDialog.xaml +++ b/ENI2/EditControls/CopyDeclarationDialog.xaml @@ -4,11 +4,11 @@ xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:ENI2.EditControls" - xmlns:enictrl="clr-namespace:ENI2.Controls" + xmlns:enictrl="clr-namespace:ENI2.Controls" 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="326" Width="440" WindowStyle="SingleBorderWindow" Background="AliceBlue" ResizeMode="NoResize" Icon="/ENI2Test;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"> @@ -34,28 +34,28 @@ - \ No newline at end of file diff --git a/ENI2/EditControls/CoreStatusInfoDialog.xaml b/ENI2/EditControls/CoreStatusInfoDialog.xaml index b09b092d..8dc5339f 100644 --- a/ENI2/EditControls/CoreStatusInfoDialog.xaml +++ b/ENI2/EditControls/CoreStatusInfoDialog.xaml @@ -8,7 +8,7 @@ xmlns:xctk="http://schemas.xceed.com/wpf/xaml/toolkit" xmlns:p="clr-namespace:ENI2.Properties" mc:Ignorable="d" - Title="{x:Static p:Resources.textCoreStatus}" Height="436" Width="600" WindowStyle="SingleBorderWindow" Background="AliceBlue" Icon="/ENI2Test;component/Resources/bullet_ball_grey.ico" > + Title="{x:Static p:Resources.textCoreStatus}" Height="436" Width="600" WindowStyle="SingleBorderWindow" Background="AliceBlue" Icon="/ENI2;component/Resources/bullet_ball_grey.ico" > @@ -22,7 +22,7 @@ - +