From a1f6e6c11348fabb2616d1ffde2a12aa84344fb1 Mon Sep 17 00:00:00 2001 From: Daniel Schick Date: Mon, 26 Jan 2026 18:56:24 +0100 Subject: [PATCH] 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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