Compare commits

...

8 Commits

22 changed files with 425 additions and 123 deletions

View File

@ -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

View File

@ -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<Message.NotificationClass, string> messageClassControlDict = new Dictionary<Message.NotificationClass, string>();
private readonly object messageListLock = new object();
private readonly HighlightService highlightService = new HighlightService();
private readonly object validationLock = new object();
private Task<ValidationResult> 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<MessageError> errorList);
DetailControl_RequestSendValidationAsync();
}
private async void DetailControl_RequestSendValidationAsync()
{
ValidationResult result = await ValidateAndApplyAsync(false);
List<MessageError> 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<MessageViolation> vViolations, out List<MessageError> vErrors)
private async Task<ValidationResult> ValidateAndApplyAsync(bool showMessages)
{
vViolations = new List<MessageViolation>();
vErrors = new List<MessageError>();
Task<ValidationResult> 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<ValidationResult> ValidateAndApplyCoreAsync()
{
Util.UIHelper.SetBusyState();
ApplyCrewEffectsWarningSuppression();
List<Message> 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<Message> messagesSnapshot)
{
List<MessageViolation> vViolations = new List<MessageViolation>();
List<MessageError> vErrors = new List<MessageError>();
Dictionary<Message, MessageValidationCounts> counts = new Dictionary<Message, MessageValidationCounts>();
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<MessageViolation> violations = new List<MessageViolation>();
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);
@ -829,22 +871,22 @@ 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 = _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<string, string> identDict = new Dictionary<string, string>();
@ -1027,35 +1053,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,19 +1240,133 @@ namespace ENI2
#endregion
#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)
{
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 = wasMessageGroup;
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 = wasMessageGroup;
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 = wasMessageGroup;
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 = wasMessageGroup;
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 = wasMessageGroup;
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 = wasMessageGroup;
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 = wasMessageGroup;
vViolations.Add(mv);
}
break;
}
}
}
}
}
#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));
}
#endregion
// "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<bsmd.database.ValidationRule> validationRules = DBManager.Instance.GetValidationRules();
@ -1251,10 +1393,34 @@ namespace ENI2
}
}
return new ValidationResult(vViolations, vErrors, counts);
}
private void ApplyValidationResult(ValidationResult result, bool showMessages)
{
// TODO: clear highlighting
foreach (KeyValuePair<Message, MessageValidationCounts> 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)
{
@ -1269,10 +1435,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)
{
@ -1287,15 +1453,62 @@ 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);
}
}
if (controlCache.TryGetValue(Properties.Resources.textOverview, out DetailBaseControl overviewControl) &&
overviewControl is OverViewDetailControl ovdc)
{
ovdc.RefreshMessageGrid();
}
}
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<MessageViolation> violations, List<MessageError> errors, Dictionary<Message, MessageValidationCounts> counts)
{
Violations = violations;
Errors = errors;
Counts = counts;
}
internal List<MessageViolation> Violations { get; }
internal List<MessageError> Errors { get; }
internal Dictionary<Message, MessageValidationCounts> 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()

View File

@ -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

View File

@ -370,6 +370,11 @@ namespace ENI2.DetailViewControls
this.Core.IsDirty = false; // ist ja schon gespeichert..
}
internal void RefreshMessageGrid()
{
this.dataGridMessages?.Items?.Refresh();
}
#endregion
#region private methods

View File

@ -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

View File

@ -36,8 +36,8 @@
<MinimumRequiredVersion>5.4.0.0</MinimumRequiredVersion>
<CreateWebPageOnPublish>true</CreateWebPageOnPublish>
<WebPage>publish.html</WebPage>
<ApplicationRevision>2</ApplicationRevision>
<ApplicationVersion>7.2.13.2</ApplicationVersion>
<ApplicationRevision>1</ApplicationRevision>
<ApplicationVersion>7.2.14.1</ApplicationVersion>
<UseApplicationTrust>false</UseApplicationTrust>
<CreateDesktopShortcut>true</CreateDesktopShortcut>
<PublishWizardCompleted>true</PublishWizardCompleted>

View File

@ -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<string, IXLDefinedName> _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)
{

View File

@ -53,7 +53,8 @@ namespace ENI2.Excel
{
File.Copy(targetPath, comparisonFileName, true);
using (var sourceWorkbook = new XLWorkbook(sourcePath))
using (var sourceStream = new FileStream(sourcePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
using (var sourceWorkbook = new XLWorkbook(sourceStream))
using (var comparisonWorkbook = new XLWorkbook(comparisonFileName))
{
// Es werden Zellen der "used range" miteinander verglichen
@ -76,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++)
{
@ -111,6 +113,7 @@ namespace ENI2.Excel
var cellToHighlight = targetSheet.Cell(rowidx, colidx);
cellToHighlight.Style.Fill.BackgroundColor = diffColor;
counter++;
sheetHasDiffs = true;
}
}
else if (targetText == null)
@ -120,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))
@ -129,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
{

View File

@ -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();

View File

@ -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();

View File

@ -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();
}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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<string, Name>();
int bookCnt = 0;
foreach(Name name in _portcall.Names)

View File

@ -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("")]

View File

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

View File

@ -97,6 +97,22 @@ namespace bsmd.database
#endregion
#region for extra waste validation
private static readonly HashSet<string> SpecialNextPortPrefixes = new HashSet<string>
{
"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<string> SpecialNextPortExact = new HashSet<string>
{
"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; } }
/// <summary>
/// Used to test for special next port values for waste messages
/// </summary>
/// <param name="nextPort">a locode</param>
/// <returns>true if the next port is a special waste port</returns>
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; }

View File

@ -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

BIN
misc/WAS-Regulation.docx Normal file

Binary file not shown.