diff --git a/bsmd.Tool/App.config b/bsmd.Tool/App.config
index ec50e784..9a2087dd 100644
--- a/bsmd.Tool/App.config
+++ b/bsmd.Tool/App.config
@@ -1,36 +1,72 @@
-
+
-
-
-
+
+
+
-
-
+
+
-
-
-
-
-
-
+
+
+
+
+
+
-
+
-
+
-
-
-
- replace me!
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ replace me!
+
+
+
+
+
+ 4
+
+
+ C:\temp\hisnord
+
+
+ C:\temp\dbh
+
+
+
diff --git a/bsmd.Tool/Echolot.cs b/bsmd.Tool/Echolot.cs
new file mode 100644
index 00000000..1e3dcf88
--- /dev/null
+++ b/bsmd.Tool/Echolot.cs
@@ -0,0 +1,224 @@
+// Copyright (c) 2020- schick Informatik
+// Description: The purpose of this tool is to evaluate files sent both through HIS-Nord and dbh
+// to evaluate how many classes were sent at what time and by whom to the purpose of improved employee
+// time planning
+
+
+using ClosedXML.Excel;
+using log4net;
+using System;
+using System.Collections.Concurrent;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text.RegularExpressions;
+using System.Threading.Tasks;
+using System.Xml.Linq;
+
+namespace bsmd.Tool
+{
+ internal static class Echolot
+ {
+
+ private static readonly ILog _log = LogManager.GetLogger(typeof(Echolot));
+
+ static readonly HashSet ValidGroupingKeys = new HashSet
+ {
+ "VISIT",
+ "TRANSIT",
+ "NOA_NOD",
+ "NOANOD",
+ "ATA",
+ "ATD",
+ "SEC",
+ "POBA",
+ "POBD",
+ "NAME",
+ "TIEFA",
+ "TIEFD",
+ "BKRA",
+ "BKRD",
+ "STAT",
+ "LADG",
+ "INFO",
+ "SERV",
+ "PRE72H",
+ "MDH",
+ "WAS",
+ "CREWA",
+ "PASA",
+ "BPOL",
+ "TOWA",
+ "TOWD",
+ "HAZA",
+ "HAZD",
+ "AGNT",
+ "STO",
+ "CREWD",
+ "PASD",
+ "WAS_RCPT"
+ };
+
+ static readonly HashSet IgnoreGroupingKeys = new HashSet
+ {
+ "VISIT",
+ "TRANSIT",
+ "ATA",
+ "ATD"
+ };
+
+ internal static void Evaluate(string outputFolder, int maxThreads)
+ {
+ DateTime executionTime = DateTime.Now;
+
+ #region first scan: dbh files
+
+ string inputFolder = Properties.Settings.Default.DBH_Folder;
+ var files = Directory.GetFiles(inputFolder, "*.xml");
+ var results = new ConcurrentBag();
+
+ Parallel.ForEach(files, new ParallelOptions { MaxDegreeOfParallelism = maxThreads }, file =>
+ {
+ try
+ {
+ var doc = XDocument.Load(file);
+
+ // Look for a valid grouping key at the root level
+ var groupingElem = doc.Root.Elements()
+ .FirstOrDefault(x => ValidGroupingKeys.Contains(x.Name.LocalName) && !IgnoreGroupingKeys.Contains(x.Name.LocalName));
+
+ if (groupingElem == null)
+ {
+ _log.InfoFormat("skipping {0}", file);
+ return; // Skip file
+ }
+
+ var lastName = doc.Descendants("RPLastName").FirstOrDefault()?.Value?.Trim();
+ var firstName = doc.Descendants("RPFirstName").FirstOrDefault()?.Value?.Trim();
+ var timestampStr = doc.Descendants("Timestamp").FirstOrDefault()?.Value?.Trim();
+
+ DateTime timestamp = DateTime.Parse(timestampStr);
+
+ results.Add(new ResultRow
+ {
+ FirstName = firstName,
+ LastName = lastName,
+ Timestamp = timestamp,
+ WeekStart = GetWeekStart(timestamp, executionTime.DayOfWeek),
+ Provider = "DBH"
+ });
+ }
+ catch (Exception ex)
+ {
+ _log.Error(ex.ToString());
+ }
+ });
+
+ #endregion
+
+ #region second scan: his-nord files
+
+ var inputFolder2 = Properties.Settings.Default.HISNORD_Folder;
+ var files2 = Directory.GetFiles(inputFolder2, "*.xml");
+
+ Parallel.ForEach(files2, new ParallelOptions { MaxDegreeOfParallelism = maxThreads }, file =>
+ {
+ try
+ {
+ var doc = XDocument.Load(file);
+
+ var match = Regex.Match(file, @"-([A-Z0-9_]+)\.xml$", RegexOptions.None);
+
+ string key = "";
+ if (match.Success)
+ {
+ key = match.Groups[1].Value;
+ }
+
+ if((key.Length == 0) || IgnoreGroupingKeys.Contains(key))
+ {
+ _log.InfoFormat("skipping {0}", file);
+ return; // Skip file
+ }
+
+ var username = doc.Descendants("firstname").FirstOrDefault()?.Value?.Trim();
+ if(username == null)
+ {
+ _log.WarnFormat("Username not found in file {0}", file);
+ return;
+ }
+ var splitname = username.Split(' ');
+ var lastName = splitname[1].Trim();
+ var firstName = splitname[0].Trim();
+
+ DateTime timestamp = File.GetCreationTime(file);
+
+ results.Add(new ResultRow
+ {
+ FirstName = firstName,
+ LastName = lastName,
+ Timestamp = timestamp,
+ WeekStart = GetWeekStart(timestamp, executionTime.DayOfWeek),
+ Provider = "HIS-NORD"
+ });
+ }
+ catch (Exception ex)
+ {
+ _log.Error(ex.ToString());
+ }
+ });
+
+
+ #endregion
+
+ var grouped = results
+ .GroupBy(r => r.WeekStart)
+ .OrderBy(g => g.Key);
+
+
+ // Write Excel
+ string excelFile = Path.Combine(outputFolder, $"echolot_{executionTime:yyyyMMdd_HHmmss}.xlsx");
+ using (var workbook = new XLWorkbook())
+ {
+ foreach (var weekGroup in grouped)
+ {
+ var ws = workbook.Worksheets.Add(weekGroup.Key.ToString("yyyy-MM-dd"));
+ ws.Cell(1, 1).Value = "Firstname";
+ ws.Cell(1, 2).Value = "Lastname";
+ ws.Cell(1, 3).Value = "Count";
+ int row = 2;
+
+ var orderedGroups = weekGroup
+ .GroupBy(x => new { x.FirstName, x.LastName })
+ .OrderByDescending(g => g.Count()); // Use OrderBy for ascending
+
+
+ foreach (var nameGroup in orderedGroups)
+ {
+ ws.Cell(row, 1).Value = nameGroup.Key.FirstName;
+ ws.Cell(row, 2).Value = nameGroup.Key.LastName;
+ ws.Cell(row, 3).Value = nameGroup.Count();
+ row++;
+ }
+ }
+ workbook.SaveAs(excelFile);
+ }
+ }
+
+ static DateTime GetWeekStart(DateTime date, DayOfWeek weekStart)
+ {
+ int diff = (7 + (date.DayOfWeek - weekStart)) % 7;
+ return date.Date.AddDays(-1 * diff);
+ }
+
+ class ResultRow
+ {
+ public string FirstName { get; set; }
+ public string LastName { get; set; }
+ public DateTime Timestamp { get; set; }
+ public DateTime WeekStart { get; set; }
+ public string Provider { get; set; }
+ }
+
+ }
+}
diff --git a/bsmd.Tool/Options.cs b/bsmd.Tool/Options.cs
index 026e703c..ae1a507d 100644
--- a/bsmd.Tool/Options.cs
+++ b/bsmd.Tool/Options.cs
@@ -25,6 +25,18 @@ namespace bsmd.Tool
[Option("locodes", HelpText = "use this flag if you want to import locodes")]
public bool ImportLocodes { get; set; }
+ [Option("echolot", HelpText = "use this flag to run the echolot output file evaluation")]
+ public bool Echolot { get; set; }
+
+ [Option('i', "input_folder", HelpText = "Input folder")]
+ public string InputFolder { get; set; }
+
+ [Option('o', "output_folder", HelpText = "Output folder")]
+ public string OutputFolder { get; set; }
+
+ [Option("max_threads", HelpText = "Maximum amount of parallelism for folder parsing")]
+ public int? MaxThreads { get; set; }
+
[Option('s', "staledays", Default = 30, HelpText ="Delete files older than X days")]
public int StaleDays { get; set; }
diff --git a/bsmd.Tool/Program.cs b/bsmd.Tool/Program.cs
index 54909cb8..82e2b3ac 100644
--- a/bsmd.Tool/Program.cs
+++ b/bsmd.Tool/Program.cs
@@ -1,4 +1,5 @@
-using CommandLine;
+using bsmd.database;
+using CommandLine;
using log4net;
using System;
@@ -40,15 +41,24 @@ namespace bsmd.Tool
LocodeSQliteImport.Import(o.LocodeDB, o.LocodeCSV);
}
}
+ if(o.Echolot)
+ {
+ string outputFolder = Properties.Settings.Default.EcholotOutputFolder;
+ if (!o.OutputFolder.IsNullOrEmpty())
+ outputFolder = o.OutputFolder;
+ int maxThreads = 2;
+ if (o.MaxThreads.HasValue) maxThreads = o.MaxThreads.Value;
+ Echolot.Evaluate(outputFolder, maxThreads);
+ }
});
}
catch (Exception ex)
{
log.Fatal(ex.ToString());
+ Console.WriteLine(ex.Message);
result = 1;
- }
- Console.Read();
+ }
return result;
}
}
diff --git a/bsmd.Tool/Properties/Settings.Designer.cs b/bsmd.Tool/Properties/Settings.Designer.cs
index 4d40f00d..a26903d7 100644
--- a/bsmd.Tool/Properties/Settings.Designer.cs
+++ b/bsmd.Tool/Properties/Settings.Designer.cs
@@ -12,7 +12,7 @@ namespace bsmd.Tool.Properties {
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
- [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "16.10.0.0")]
+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "17.14.0.0")]
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
@@ -23,15 +23,48 @@ namespace bsmd.Tool.Properties {
}
}
- [global::System.Configuration.UserScopedSettingAttribute()]
+ [global::System.Configuration.ApplicationScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("replace me!")]
public string ConnectionString {
get {
return ((string)(this["ConnectionString"]));
}
- set {
- this["ConnectionString"] = value;
+ }
+
+ [global::System.Configuration.ApplicationScopedSettingAttribute()]
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [global::System.Configuration.DefaultSettingValueAttribute("")]
+ public string EcholotOutputFolder {
+ get {
+ return ((string)(this["EcholotOutputFolder"]));
+ }
+ }
+
+ [global::System.Configuration.ApplicationScopedSettingAttribute()]
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [global::System.Configuration.DefaultSettingValueAttribute("4")]
+ public int EcholotMaxThreads {
+ get {
+ return ((int)(this["EcholotMaxThreads"]));
+ }
+ }
+
+ [global::System.Configuration.ApplicationScopedSettingAttribute()]
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [global::System.Configuration.DefaultSettingValueAttribute("C:\\temp\\hisnord")]
+ public string HISNORD_Folder {
+ get {
+ return ((string)(this["HISNORD_Folder"]));
+ }
+ }
+
+ [global::System.Configuration.ApplicationScopedSettingAttribute()]
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [global::System.Configuration.DefaultSettingValueAttribute("C:\\temp\\dbh")]
+ public string DBH_Folder {
+ get {
+ return ((string)(this["DBH_Folder"]));
}
}
}
diff --git a/bsmd.Tool/Properties/Settings.settings b/bsmd.Tool/Properties/Settings.settings
index 07cf4d90..3785f743 100644
--- a/bsmd.Tool/Properties/Settings.settings
+++ b/bsmd.Tool/Properties/Settings.settings
@@ -2,8 +2,20 @@
-
+
replace me!
+
+
+
+
+ 4
+
+
+ C:\temp\hisnord
+
+
+ C:\temp\dbh
+
\ No newline at end of file
diff --git a/bsmd.Tool/bsmd.Tool.csproj b/bsmd.Tool/bsmd.Tool.csproj
index 92d23e99..877acf69 100644
--- a/bsmd.Tool/bsmd.Tool.csproj
+++ b/bsmd.Tool/bsmd.Tool.csproj
@@ -44,25 +44,62 @@
..\bsmd.database\bin\Debug\bsmd.database.dll
+
+ ..\packages\ClosedXML.0.105.0\lib\netstandard2.0\ClosedXML.dll
+
+
+ ..\packages\ClosedXML.Parser.2.0.0\lib\netstandard2.0\ClosedXML.Parser.dll
+
..\packages\CommandLineParser.2.9.1\lib\net461\CommandLine.dll
-
- ..\packages\log4net.2.0.15\lib\net45\log4net.dll
+
+ ..\packages\DocumentFormat.OpenXml.3.1.1\lib\net46\DocumentFormat.OpenXml.dll
+
+
+ ..\packages\DocumentFormat.OpenXml.Framework.3.1.1\lib\net46\DocumentFormat.OpenXml.Framework.dll
+
+
+ ..\packages\ExcelNumberFormat.1.1.0\lib\net20\ExcelNumberFormat.dll
+
+
+ ..\packages\log4net.3.1.0\lib\net462\log4net.dll
+
+
+ ..\packages\Microsoft.Bcl.HashCode.1.1.1\lib\net461\Microsoft.Bcl.HashCode.dll
+
+
+ ..\packages\RBush.Signed.4.0.0\lib\net47\RBush.dll
+
+
+ ..\packages\SixLabors.Fonts.1.0.0\lib\netstandard2.0\SixLabors.Fonts.dll
+
+ ..\packages\System.Buffers.4.5.1\lib\net461\System.Buffers.dll
+
-
- ..\packages\Stub.System.Data.SQLite.Core.NetFramework.1.0.117.0\lib\net46\System.Data.SQLite.dll
+
+ ..\packages\Stub.System.Data.SQLite.Core.NetFramework.1.0.119.0\lib\net46\System.Data.SQLite.dll
+
+
+ ..\packages\System.Memory.4.5.5\lib\net461\System.Memory.dll
+
+ ..\packages\System.Numerics.Vectors.4.5.0\lib\net46\System.Numerics.Vectors.dll
+
+
+ ..\packages\System.Runtime.CompilerServices.Unsafe.4.7.0\lib\netstandard2.0\System.Runtime.CompilerServices.Unsafe.dll
+
+
@@ -76,6 +113,7 @@
+
@@ -89,6 +127,7 @@
+
SettingsSingleFileGenerator
@@ -96,12 +135,12 @@
-
+
This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.
-
+
\ No newline at end of file
diff --git a/bsmd.Tool/packages.config b/bsmd.Tool/packages.config
index 31f24d70..6fb49e25 100644
--- a/bsmd.Tool/packages.config
+++ b/bsmd.Tool/packages.config
@@ -1,7 +1,19 @@
+
+
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file