diff --git a/WinLineArtikelnummerGenerator.sln b/WinLineArtikelnummerGenerator.sln new file mode 100644 index 0000000..09c8101 --- /dev/null +++ b/WinLineArtikelnummerGenerator.sln @@ -0,0 +1,25 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.29728.190 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "WinLineArtikelnummerGenerator", "WinLineArtikelnummerGenerator\WinLineArtikelnummerGenerator.vbproj", "{BA171D0B-6421-4294-B5DC-BF77D93C91E7}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {BA171D0B-6421-4294-B5DC-BF77D93C91E7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {BA171D0B-6421-4294-B5DC-BF77D93C91E7}.Debug|Any CPU.Build.0 = Debug|Any CPU + {BA171D0B-6421-4294-B5DC-BF77D93C91E7}.Release|Any CPU.ActiveCfg = Release|Any CPU + {BA171D0B-6421-4294-B5DC-BF77D93C91E7}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {2FFA2908-335A-4211-8E21-1E5323B7C645} + EndGlobalSection +EndGlobal diff --git a/WinLineArtikelnummerGenerator/App.config b/WinLineArtikelnummerGenerator/App.config new file mode 100644 index 0000000..f6744a2 --- /dev/null +++ b/WinLineArtikelnummerGenerator/App.config @@ -0,0 +1,23 @@ + + + + +
+ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/WinLineArtikelnummerGenerator/CWLDATEN_MEDSDataSet.Designer.vb b/WinLineArtikelnummerGenerator/CWLDATEN_MEDSDataSet.Designer.vb new file mode 100644 index 0000000..f0b24e3 --- /dev/null +++ b/WinLineArtikelnummerGenerator/CWLDATEN_MEDSDataSet.Designer.vb @@ -0,0 +1,242 @@ +'------------------------------------------------------------------------------ +' +' Dieser Code wurde von einem Tool generiert. +' Laufzeitversion:4.0.30319.42000 +' +' Änderungen an dieser Datei können falsches Verhalten verursachen und gehen verloren, wenn +' der Code erneut generiert wird. +' +'------------------------------------------------------------------------------ + +Option Strict Off +Option Explicit On + + + +''' +'''Represents a strongly typed in-memory cache of data. +''' + _ +Partial Public Class CWLDATEN_MEDSDataSet + Inherits Global.System.Data.DataSet + + Private _schemaSerializationMode As Global.System.Data.SchemaSerializationMode = Global.System.Data.SchemaSerializationMode.IncludeSchema + + _ + Public Sub New() + MyBase.New + Me.BeginInit + Me.InitClass + Dim schemaChangedHandler As Global.System.ComponentModel.CollectionChangeEventHandler = AddressOf Me.SchemaChanged + AddHandler MyBase.Tables.CollectionChanged, schemaChangedHandler + AddHandler MyBase.Relations.CollectionChanged, schemaChangedHandler + Me.EndInit + End Sub + + _ + Protected Sub New(ByVal info As Global.System.Runtime.Serialization.SerializationInfo, ByVal context As Global.System.Runtime.Serialization.StreamingContext) + MyBase.New(info, context, false) + If (Me.IsBinarySerialized(info, context) = true) Then + Me.InitVars(false) + Dim schemaChangedHandler1 As Global.System.ComponentModel.CollectionChangeEventHandler = AddressOf Me.SchemaChanged + AddHandler Me.Tables.CollectionChanged, schemaChangedHandler1 + AddHandler Me.Relations.CollectionChanged, schemaChangedHandler1 + Return + End If + Dim strSchema As String = CType(info.GetValue("XmlSchema", GetType(String)),String) + If (Me.DetermineSchemaSerializationMode(info, context) = Global.System.Data.SchemaSerializationMode.IncludeSchema) Then + Dim ds As Global.System.Data.DataSet = New Global.System.Data.DataSet() + ds.ReadXmlSchema(New Global.System.Xml.XmlTextReader(New Global.System.IO.StringReader(strSchema))) + Me.DataSetName = ds.DataSetName + Me.Prefix = ds.Prefix + Me.Namespace = ds.Namespace + Me.Locale = ds.Locale + Me.CaseSensitive = ds.CaseSensitive + Me.EnforceConstraints = ds.EnforceConstraints + Me.Merge(ds, false, Global.System.Data.MissingSchemaAction.Add) + Me.InitVars + Else + Me.ReadXmlSchema(New Global.System.Xml.XmlTextReader(New Global.System.IO.StringReader(strSchema))) + End If + Me.GetSerializationData(info, context) + Dim schemaChangedHandler As Global.System.ComponentModel.CollectionChangeEventHandler = AddressOf Me.SchemaChanged + AddHandler MyBase.Tables.CollectionChanged, schemaChangedHandler + AddHandler Me.Relations.CollectionChanged, schemaChangedHandler + End Sub + + _ + Public Overrides Property SchemaSerializationMode() As Global.System.Data.SchemaSerializationMode + Get + Return Me._schemaSerializationMode + End Get + Set + Me._schemaSerializationMode = value + End Set + End Property + + _ + Public Shadows ReadOnly Property Tables() As Global.System.Data.DataTableCollection + Get + Return MyBase.Tables + End Get + End Property + + _ + Public Shadows ReadOnly Property Relations() As Global.System.Data.DataRelationCollection + Get + Return MyBase.Relations + End Get + End Property + + _ + Protected Overrides Sub InitializeDerivedDataSet() + Me.BeginInit + Me.InitClass + Me.EndInit + End Sub + + _ + Public Overrides Function Clone() As Global.System.Data.DataSet + Dim cln As CWLDATEN_MEDSDataSet = CType(MyBase.Clone,CWLDATEN_MEDSDataSet) + cln.InitVars + cln.SchemaSerializationMode = Me.SchemaSerializationMode + Return cln + End Function + + _ + Protected Overrides Function ShouldSerializeTables() As Boolean + Return false + End Function + + _ + Protected Overrides Function ShouldSerializeRelations() As Boolean + Return false + End Function + + _ + Protected Overrides Sub ReadXmlSerializable(ByVal reader As Global.System.Xml.XmlReader) + If (Me.DetermineSchemaSerializationMode(reader) = Global.System.Data.SchemaSerializationMode.IncludeSchema) Then + Me.Reset + Dim ds As Global.System.Data.DataSet = New Global.System.Data.DataSet() + ds.ReadXml(reader) + Me.DataSetName = ds.DataSetName + Me.Prefix = ds.Prefix + Me.Namespace = ds.Namespace + Me.Locale = ds.Locale + Me.CaseSensitive = ds.CaseSensitive + Me.EnforceConstraints = ds.EnforceConstraints + Me.Merge(ds, false, Global.System.Data.MissingSchemaAction.Add) + Me.InitVars + Else + Me.ReadXml(reader) + Me.InitVars + End If + End Sub + + _ + Protected Overrides Function GetSchemaSerializable() As Global.System.Xml.Schema.XmlSchema + Dim stream As Global.System.IO.MemoryStream = New Global.System.IO.MemoryStream() + Me.WriteXmlSchema(New Global.System.Xml.XmlTextWriter(stream, Nothing)) + stream.Position = 0 + Return Global.System.Xml.Schema.XmlSchema.Read(New Global.System.Xml.XmlTextReader(stream), Nothing) + End Function + + _ + Friend Overloads Sub InitVars() + Me.InitVars(true) + End Sub + + _ + Friend Overloads Sub InitVars(ByVal initTable As Boolean) + End Sub + + _ + Private Sub InitClass() + Me.DataSetName = "CWLDATEN_MEDSDataSet" + Me.Prefix = "" + Me.Namespace = "http://tempuri.org/CWLDATEN_MEDSDataSet.xsd" + Me.EnforceConstraints = true + Me.SchemaSerializationMode = Global.System.Data.SchemaSerializationMode.IncludeSchema + End Sub + + _ + Private Sub SchemaChanged(ByVal sender As Object, ByVal e As Global.System.ComponentModel.CollectionChangeEventArgs) + If (e.Action = Global.System.ComponentModel.CollectionChangeAction.Remove) Then + Me.InitVars + End If + End Sub + + _ + Public Shared Function GetTypedDataSetSchema(ByVal xs As Global.System.Xml.Schema.XmlSchemaSet) As Global.System.Xml.Schema.XmlSchemaComplexType + Dim ds As CWLDATEN_MEDSDataSet = New CWLDATEN_MEDSDataSet() + Dim type As Global.System.Xml.Schema.XmlSchemaComplexType = New Global.System.Xml.Schema.XmlSchemaComplexType() + Dim sequence As Global.System.Xml.Schema.XmlSchemaSequence = New Global.System.Xml.Schema.XmlSchemaSequence() + Dim any As Global.System.Xml.Schema.XmlSchemaAny = New Global.System.Xml.Schema.XmlSchemaAny() + any.Namespace = ds.Namespace + sequence.Items.Add(any) + type.Particle = sequence + Dim dsSchema As Global.System.Xml.Schema.XmlSchema = ds.GetSchemaSerializable + If xs.Contains(dsSchema.TargetNamespace) Then + Dim s1 As Global.System.IO.MemoryStream = New Global.System.IO.MemoryStream() + Dim s2 As Global.System.IO.MemoryStream = New Global.System.IO.MemoryStream() + Try + Dim schema As Global.System.Xml.Schema.XmlSchema = Nothing + dsSchema.Write(s1) + Dim schemas As Global.System.Collections.IEnumerator = xs.Schemas(dsSchema.TargetNamespace).GetEnumerator + Do While schemas.MoveNext + schema = CType(schemas.Current,Global.System.Xml.Schema.XmlSchema) + s2.SetLength(0) + schema.Write(s2) + If (s1.Length = s2.Length) Then + s1.Position = 0 + s2.Position = 0 + + Do While ((s1.Position <> s1.Length) _ + AndAlso (s1.ReadByte = s2.ReadByte)) + + + Loop + If (s1.Position = s1.Length) Then + Return type + End If + End If + + Loop + Finally + If (Not (s1) Is Nothing) Then + s1.Close + End If + If (Not (s2) Is Nothing) Then + s2.Close + End If + End Try + End If + xs.Add(dsSchema) + Return type + End Function +End Class diff --git a/WinLineArtikelnummerGenerator/CWLDATEN_MEDSDataSet.xsc b/WinLineArtikelnummerGenerator/CWLDATEN_MEDSDataSet.xsc new file mode 100644 index 0000000..5f28270 --- /dev/null +++ b/WinLineArtikelnummerGenerator/CWLDATEN_MEDSDataSet.xsc @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/WinLineArtikelnummerGenerator/CWLDATEN_MEDSDataSet.xsd b/WinLineArtikelnummerGenerator/CWLDATEN_MEDSDataSet.xsd new file mode 100644 index 0000000..3b44de1 --- /dev/null +++ b/WinLineArtikelnummerGenerator/CWLDATEN_MEDSDataSet.xsd @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/WinLineArtikelnummerGenerator/CWLDATEN_MEDSDataSet.xss b/WinLineArtikelnummerGenerator/CWLDATEN_MEDSDataSet.xss new file mode 100644 index 0000000..5f28270 --- /dev/null +++ b/WinLineArtikelnummerGenerator/CWLDATEN_MEDSDataSet.xss @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/WinLineArtikelnummerGenerator/Config.vb b/WinLineArtikelnummerGenerator/Config.vb new file mode 100644 index 0000000..eb345e4 --- /dev/null +++ b/WinLineArtikelnummerGenerator/Config.vb @@ -0,0 +1,5 @@ +Imports DigitalData.Modules.Config.ConfigAttributes + +Public Class Config + Public Property ConnectionString As String +End Class diff --git a/WinLineArtikelnummerGenerator/Database.vb b/WinLineArtikelnummerGenerator/Database.vb new file mode 100644 index 0000000..6f90e37 --- /dev/null +++ b/WinLineArtikelnummerGenerator/Database.vb @@ -0,0 +1,105 @@ +Imports System.Data.SqlClient + +Public Class Database + Private _Config As ConfigManager(Of Config) + Private _LogConfig As LogConfig + Private _Logger As Logger + + Private Const QUERY_TIMEOUT = 120000 + + Public Sub New(LogConfig As LogConfig, ConfigManager As ConfigManager(Of Config)) + _LogConfig = LogConfig + _Logger = LogConfig.GetLogger() + _Config = ConfigManager + End Sub + + Public Function LoadVendors() As DataTable + Return GetDatatable("SELECT C229, C003 FROM V050 WHERE C229 IS NOT NULL") + End Function + + Public Function LoadVendorIdByCode(VendorCode As String) As String + Return GetScalarValue($"SELECT SUBSTRING(C000,0,6) C999 FROM T309 WHERE C001 = '{VendorCode}' AND C002 = 1") + End Function + + Public Function LoadGroupsByVendor(VendorId As String) As DataTable + Return GetDatatable($"SELECT C001, SUBSTRING(C000,7,5) C999 FROM T309 WHERE C000 LIKE '{VendorId}%' AND C002 = 2 AND C001 LIKE '__ | %'") + End Function + + Public Function LoadVersionsByVendorAndGroup(VendorId As String, GroupId As String) As DataTable + Return GetDatatable($"SELECT C001 FROM T309 WHERE C000 LIKE '{VendorId}-{GroupId}-%' AND C002 = 3 AND C001 LIKE '__ | %'") + End Function + +#Region "Database-Access" + Private Function GetSQLConnection() As SqlConnection + Return GetSQLConnection(_Config.Config.ConnectionString) + End Function + + Private Function GetSQLConnection(ConnectionString As String) As SqlConnection + Try + Dim oConnection As New SqlConnection(ConnectionString) + oConnection.Open() + + Dim oMaskedConnectionString = MaskConnectionString(ConnectionString) + _Logger.Debug("The Following Connection is open: {0}", oMaskedConnectionString) + + Return oConnection + Catch ex As Exception + _Logger.Error(ex) + + Return Nothing + End Try + End Function + + Private Function MaskConnectionString(ConnectionString As String) As String + Try + Dim oBuilder As New SqlConnectionStringBuilder() With {.ConnectionString = ConnectionString} + Dim oConnectionString = ConnectionString.Replace(oBuilder.Password, "XXXXX") + Return oConnectionString + Catch ex As Exception + _Logger.Error(ex) + Return "Invalid ConnectionString" + End Try + End Function + + Public Function GetDatatable(SqlCommand As String) As DataTable + Try + _Logger.Debug("GetDatatable: Running Query [{0}]", SqlCommand) + + Using oConnection = GetSQLConnection() + Using oSQLCOmmand = oConnection.CreateCommand() + oSQLCOmmand.CommandText = SqlCommand + oSQLCOmmand.CommandTimeout = QUERY_TIMEOUT + + Dim dt As DataTable = New DataTable() + Dim oAdapter As SqlDataAdapter = New SqlDataAdapter(oSQLCOmmand) + oAdapter.Fill(dt) + Return dt + End Using + End Using + Catch ex As Exception + _Logger.Warn($"GetDatatable failed SQLCommand [{SqlCommand}] - ERROR: {ex.Message}") + Return Nothing + End Try + End Function + + Public Function GetScalarValue(SQLCommand As String) As Object + Try + _Logger.Debug("GetScalarValue: Running Query [{0}]", SQLCommand) + + Using oConnection As SqlConnection = GetSQLConnection() + Using oSQLCOmmand = oConnection.CreateCommand() + oSQLCOmmand.CommandText = SQLCommand + oSQLCOmmand.CommandTimeout = QUERY_TIMEOUT + Dim oResult As Object = oSQLCOmmand.ExecuteScalar() + Return oResult + End Using + End Using + Catch ex As Exception + _Logger.Warn($"GetScalarValue failed SQLCommand [{SQLCommand}] - ERROR: {ex.Message}") + + Return Nothing + End Try + End Function +#End Region + +End Class diff --git a/WinLineArtikelnummerGenerator/Models/Article.vb b/WinLineArtikelnummerGenerator/Models/Article.vb new file mode 100644 index 0000000..a07c034 --- /dev/null +++ b/WinLineArtikelnummerGenerator/Models/Article.vb @@ -0,0 +1,11 @@ +Public Class Article + Public VendorId As String + Public ProductGroupId As String + Public ProductVersionId As String + Public RunningNumber As String + + Public AddedWho As String + Public ChangedWho As String + Public AddedWhen As Date + Public ChangedWhen As Date +End Class diff --git a/WinLineArtikelnummerGenerator/Models/ProductGroup.vb b/WinLineArtikelnummerGenerator/Models/ProductGroup.vb new file mode 100644 index 0000000..0924337 --- /dev/null +++ b/WinLineArtikelnummerGenerator/Models/ProductGroup.vb @@ -0,0 +1,11 @@ +Public Class ProductGroup + Public Guid As Integer + Public Name As String + Public NickName As String + + Public Property Versions As List(Of ProductVersion) + + Public Sub New() + Versions = New List(Of ProductVersion) + End Sub +End Class diff --git a/WinLineArtikelnummerGenerator/Models/ProductVersion.vb b/WinLineArtikelnummerGenerator/Models/ProductVersion.vb new file mode 100644 index 0000000..48406bb --- /dev/null +++ b/WinLineArtikelnummerGenerator/Models/ProductVersion.vb @@ -0,0 +1,4 @@ +Public Class ProductVersion + Public Guid As Integer + Public Name As String +End Class diff --git a/WinLineArtikelnummerGenerator/Models/Vendor.vb b/WinLineArtikelnummerGenerator/Models/Vendor.vb new file mode 100644 index 0000000..691aa37 --- /dev/null +++ b/WinLineArtikelnummerGenerator/Models/Vendor.vb @@ -0,0 +1,5 @@ +Public Class Vendor + Public Guid As Integer + Public Id As String + Public Name As String +End Class diff --git a/WinLineArtikelnummerGenerator/Modules/ConfigManager.vb b/WinLineArtikelnummerGenerator/Modules/ConfigManager.vb new file mode 100644 index 0000000..25fbb52 --- /dev/null +++ b/WinLineArtikelnummerGenerator/Modules/ConfigManager.vb @@ -0,0 +1,333 @@ +Imports System.IO +Imports System.Reflection +Imports System.Xml.Serialization +Imports DigitalData.Modules.Logging +Imports DigitalData.Modules.Config.ConfigAttributes + +Public Class ConfigManager(Of T) + Private Const USER_CONFIG_NAME As String = "UserConfig.xml" + Private Const COMPUTER_CONFIG_NAME As String = "ComputerConfig.xml" + Private Const APP_CONFIG_NAME As String = "AppConfig.xml" + + Private ReadOnly _LogConfig As LogConfig + Private ReadOnly _Logger As Logger + Private ReadOnly _File As File + + Private ReadOnly _UserDirectory As String + Private ReadOnly _UserConfigPath As String + Private ReadOnly _ComputerDirectory As String + Private ReadOnly _ComputerConfigPath As String + Private ReadOnly _AppConfigPath As String + Private ReadOnly _AppConfigDirectory As String + + Private ReadOnly _TestMode As Boolean = False + + Private ReadOnly _Blueprint As T + Private ReadOnly _BlueprintType As Type + Private ReadOnly _Serializer As XmlSerializer + + Private ReadOnly _ExcludedAttributes = New List(Of Type) From { + GetType(ConnectionStringAttribute), + GetType(ConnectionStringTestAttribute), + GetType(GlobalSettingAttribute) + } + + Private _WriteAllValuesToUserConfig As Boolean = False + + ''' + ''' Returns the currently loaded config object + ''' + ''' + Public ReadOnly Property Config As T + + ''' + ''' Path to the current user config. + ''' + ''' + Public ReadOnly Property UserConfigPath As String + Get + Return _UserConfigPath + End Get + End Property + + ''' + ''' Path to the current computer config. Maybe the same as `UserConfigPath` + ''' + ''' + Public ReadOnly Property ComputerConfigPath As String + Get + Return _ComputerConfigPath + End Get + End Property + Public ReadOnly Property AppConfigPath As String + Get + Return _AppConfigPath + End Get + End Property + + ''' + ''' Creates a new instance of the ConfigManager + ''' + ''' + ''' LogConfig instance + ''' The path to check for a user config file, eg. AppData (Usually Application.UserAppDataPath or Application.LocalUserAppDataPath) + ''' The path to check for a computer config file, eg. ProgramData (Usually Application.CommonAppDataPath) + ''' The path to check for a third config file. This is useful when running the Application in an environment where AppData/ProgramData directories are not available + ''' Override values from ComputerConfig with UserConfig + Public Sub New(LogConfig As LogConfig, UserConfigPath As String, ComputerConfigPath As String, Optional ApplicationStartupPath As String = "", Optional ForceUserConfig As Boolean = False) + _LogConfig = LogConfig + _Logger = LogConfig.GetLogger() + _File = New File(_LogConfig) + + _Blueprint = Activator.CreateInstance(Of T) + _BlueprintType = _Blueprint.GetType + _Serializer = New XmlSerializer(_BlueprintType) + + _UserDirectory = _File.CreateDirectory(UserConfigPath) + _UserConfigPath = Path.Combine(_UserDirectory, USER_CONFIG_NAME) + + If ComputerConfigPath <> String.Empty Then + _ComputerDirectory = _File.CreateDirectory(ComputerConfigPath) + _ComputerConfigPath = Path.Combine(_ComputerDirectory, COMPUTER_CONFIG_NAME) + End If + + If ApplicationStartupPath <> String.Empty Then + _AppConfigPath = Path.Combine(ApplicationStartupPath, APP_CONFIG_NAME) + End If + + _WriteAllValuesToUserConfig = ForceUserConfig + + Config = LoadConfig() + End Sub + + ''' + ''' Creates a new ConfigManager with a single (user)config path + ''' + ''' LogConfig instance + ''' The path to check for a user config file, eg. AppData (Usually Application.UserAppDataPath or Application.LocalUserAppDataPath) + Public Sub New(LogConfig As LogConfig, ConfigPath As String) + MyClass.New(LogConfig, ConfigPath, String.Empty, String.Empty, ForceUserConfig:=True) + End Sub + + ''' + ''' Save the current config object to `UserConfigPath` + ''' + ''' Force saving all attributes including the attributes marked as excluded + ''' True if save was successful, False otherwise + Public Function Save(Optional ForceAll As Boolean = False) As Boolean + Try + WriteToFile(Config, _UserConfigPath, ForceAll) + Return True + Catch ex As Exception + _Logger.Error(ex) + Return False + End Try + End Function + + ''' + ''' Copies all properties from Source to Target, except those who have an attribute + ''' listed in ExcludedAttributeTypes + ''' + ''' Source config object + ''' Target config object + ''' List of Attribute type to exclude + Private Sub CopyValues(Source As T, Target As T, Optional ExcludedAttributeTypes As List(Of Type) = Nothing) + Dim oType As Type = GetType(T) + Dim oExcludedAttributeTypes = IIf(IsNothing(ExcludedAttributeTypes), New List(Of Type), ExcludedAttributeTypes) + Dim oProperties = oType.GetProperties(). + Where(Function(p) + Return p.CanRead And p.CanWrite + End Function). + Where(Function(p) + For Each oAttributeType As Type In oExcludedAttributeTypes + If Attribute.IsDefined(p, oAttributeType) Then + Return False + End If + Next + Return True + End Function) + + For Each oProperty As PropertyInfo In oProperties + Dim oValue = oProperty.GetValue(Source, Nothing) + If Not IsNothing(oValue) Then + oProperty.SetValue(Target, oValue, Nothing) + End If + Next + End Sub + + ''' + ''' Filters a config object by copying all values except `ExcludedAttributeTypes` + ''' + ''' Config object + ''' List of Attribute type to exclude + ''' + Private Function FilterValues(ByVal Data As T, ExcludedAttributeTypes As List(Of Type)) As T + Dim oResult As T = Activator.CreateInstance(Of T) + + CopyValues(Data, oResult, ExcludedAttributeTypes) + Return oResult + End Function + + Private Function LoadConfig() As T + ' first create an empty/default config object + Dim oConfig = Activator.CreateInstance(_BlueprintType) + + ' try to load the special app config + oConfig = LoadAppConfig(oConfig) + + ' try to load the computer config + oConfig = LoadComputerConfig(oConfig) + + ' now try to load userconfig + oConfig = LoadUserConfig(oConfig) + Return oConfig + End Function + + Private Function LoadAppConfig(ByVal Config As T) As T + If Not String.IsNullOrEmpty(_AppConfigPath) AndAlso System.IO.File.Exists(_AppConfigPath) Then + Try + Dim oAppConfig = ReadFromFile(_AppConfigPath) + CopyValues(oAppConfig, Config) + Catch ex As Exception + _Logger.Error(ex) + _Logger.Warn("ApplicationConfig could not be loaded!") + End Try + _WriteAllValuesToUserConfig = False + Else + _Logger.Debug("ApplicationConfig does not exist.") + _WriteAllValuesToUserConfig = True + End If + + Return Config + End Function + + Private Function LoadComputerConfig(ByVal Config As T) As T + If System.IO.File.Exists(_ComputerConfigPath) Then + Try + Dim oComputerConfig = ReadFromFile(_ComputerConfigPath) + CopyValues(oComputerConfig, Config) + Catch ex As Exception + _Logger.Error(ex) + _Logger.Warn("Computer config could not be loaded!") + End Try + _WriteAllValuesToUserConfig = False + Else + _Logger.Debug("Computer config does not exist.") + _WriteAllValuesToUserConfig = True + End If + + Return Config + End Function + + Private Function LoadUserConfig(ByVal Config As T) As T + If System.IO.File.Exists(_UserConfigPath) Then + Try + Dim oUserConfig = ReadFromFile(_UserConfigPath) + + ' if user config exists + If Not IsNothing(oUserConfig) Then + Dim oExcludedAttributes As New List(Of Type) + + ' Copy values from user config to final config + If _WriteAllValuesToUserConfig Then + CopyValues(oUserConfig, Config, New List(Of Type)) + Else + CopyValues(oUserConfig, Config, _ExcludedAttributes) + End If + End If + Catch ex As Exception + _Logger.Error(ex) + _Logger.Warn("User config could not be loaded!") + End Try + Else + _Logger.Debug("User config does not exist.") + End If + + Return Config + End Function + + Private Function TestHasAttribute(Config As T, AttributeType As Type) As Boolean + For Each oProperty As PropertyInfo In Config.GetType.GetProperties() + If Attribute.IsDefined(oProperty, GetType(ConnectionStringAttribute)) Then + Return True + End If + Next + + Return False + End Function + + ''' + ''' Serialize a config object to byte array + ''' + ''' + ''' + Private Function Serialize(Data As T) As Byte() + Try + _Logger.Debug("Serializing config object") + + Using oStream = New MemoryStream() + _Serializer.Serialize(oStream, Data) + Return oStream.ToArray() + End Using + Catch ex As Exception + _Logger.Error(ex) + Throw ex + End Try + End Function + + ''' + ''' Write an object to disk as xml + ''' + ''' The object to write + ''' The file name to write to + Private Sub WriteToFile(Data As T, Path As String, ForceAll As Boolean) + Try + _Logger.Debug("Saving config to: {0}", Path) + + ' If config was loaded from computer config, + ' DO NOT save connection string, etc. to user config + If _WriteAllValuesToUserConfig = False And ForceAll = False Then + Data = FilterValues(Data, _ExcludedAttributes) + End If + + Dim oBytes = Serialize(Data) + + Using oFileStream = New FileStream(Path, FileMode.Create, FileAccess.Write) + oFileStream.Write(oBytes, 0, oBytes.Length) + oFileStream.Flush() + End Using + Catch ex As Exception + _Logger.Warn("Could not save config to {0}", Path) + _Logger.Error(ex) + Throw ex + End Try + End Sub + + ''' + ''' Reads an xml from disk and deserializes to object + ''' + ''' + Private Function ReadFromFile(Path As String) As T + Try + _Logger.Debug("Loading config from: {0}", Path) + Dim oConfig As T + + Using oReader As New StreamReader(Path) + oConfig = _Serializer.Deserialize(oReader) + End Using + + ' If oConfig is Nothing, a config file was created but nothing was written to it. + ' In this case we need to create oConfig from defaults so we have at least some config object + If oConfig Is Nothing Then + _Logger.Debug("Config file is valid but empty. Loading default values") + oConfig = Activator.CreateInstance(_BlueprintType) + End If + + Return oConfig + Catch ex As Exception + _Logger.Warn("Could not load config from {0}", Path) + _Logger.Error(ex) + Throw ex + End Try + End Function +End Class diff --git a/WinLineArtikelnummerGenerator/Modules/File.vb b/WinLineArtikelnummerGenerator/Modules/File.vb new file mode 100644 index 0000000..af4dae4 --- /dev/null +++ b/WinLineArtikelnummerGenerator/Modules/File.vb @@ -0,0 +1,267 @@ +Imports System.IO +Imports System.Text.RegularExpressions +Imports DigitalData.Modules.Logging + +''' File +''' 0.0.0.1 +''' 11.10.2018 +''' +''' Module that provides variouse File operations +''' +''' +''' NLog, >= 4.5.8 +''' +''' +''' LogConfig, DigitalData.Module.Logging.LogConfig +''' A LogConfig object +''' +''' +''' +''' +''' +''' +''' +Public Class File + Private ReadOnly _logger As Logger + Private ReadOnly _logConfig As LogConfig + + Private ReadOnly _invalidFilenameChars As String + Private ReadOnly _invalidPathChars As String + + Private Const REGEX_CLEAN_FILENAME As String = "[\\/:""<>|\b\0\r\n\t]" + Private Const REGEX_CLEAN_PATH As String = "[:""<>|\b\0\r\n\t]" + + Private Const FILE_NAME_ACCESS_TEST = "accessTest.txt" + + Public Sub New(LogConfig As LogConfig) + _logConfig = LogConfig + _logger = LogConfig.GetLogger() + + _invalidFilenameChars = String.Join("", Path.GetInvalidFileNameChars()) + _invalidPathChars = String.Join("", Path.GetInvalidPathChars()) + End Sub + + Public Function GetCleanFilename(FileName As String) As String + _logger.Debug("Filename before cleaning: [{0}]", FileName) + + Dim oCleanName As String = FileName + oCleanName = Regex.Replace(oCleanName, _invalidFilenameChars, String.Empty) + oCleanName = Regex.Replace(oCleanName, REGEX_CLEAN_FILENAME, String.Empty, RegexOptions.Singleline) + + _logger.Debug("Filename after cleaning: [{0}]", oCleanName) + + Return oCleanName + End Function + + Public Function GetCleanPath(FilePath As String) As String + _logger.Debug("Path before cleaning: [{0}]", FilePath) + + Dim oCleanName As String = FilePath + oCleanName = Regex.Replace(oCleanName, _invalidPathChars, String.Empty) + oCleanName = Regex.Replace(oCleanName, REGEX_CLEAN_PATH, String.Empty, RegexOptions.Singleline) + + _logger.Debug("Path after cleaning: [{0}]", oCleanName) + + Return oCleanName + End Function + + ''' + ''' Adds fileversions to given filename `Destination` if that file already exists. + ''' + ''' + ''' + Public Function GetVersionedFilename(Destination As String) As String + Try + Dim oFileName As String = Destination + Dim oFinalFileName = oFileName + + Dim oDestinationDir = Path.GetDirectoryName(oFileName) + Dim oExtension = Path.GetExtension(oFileName) + + Dim oVersionSeparator As Char = "~"c + Dim oFileVersion As Integer = Nothing + + ' Split Filename without extension at version separator to: + ' - Check if file is already versioned + ' - Get the file version of an already versioned file + ' + ' Example: + ' test1.pdf --> test1 --> ['test1'] --> no fileversion + ' test1~2.pdf --> test1~2 --> ['test1', '2'] --> version 2 + ' test1~12345~2.pdf --> test1~12345~2 --> ['test1', '12345', '2'] --> still version 2 + Dim oFileNameWithoutExtension = Path.GetFileNameWithoutExtension(oFileName) + Dim oSplitFilename = oFileNameWithoutExtension.Split(oVersionSeparator).ToList() + + ' if file is already versioned, extract file version + ' else just use the filename and set version to 1 + If oSplitFilename.Count > 1 Then + Dim oVersion As Integer = 1 + Try + oVersion = Integer.Parse(oSplitFilename.Last()) + oFileNameWithoutExtension = String.Join("", oSplitFilename.Take(oSplitFilename.Count - 1)) + Catch ex As Exception + ' oFilenameWithoutExtension does NOT change + oFileNameWithoutExtension = oFileNameWithoutExtension + Finally + oFileVersion = oVersion + End Try + Else + oFileVersion = 1 + End If + + ' while file exists, increment version + Do + oFinalFileName = Path.Combine(oDestinationDir, GetFilenameWithVersion(oFileNameWithoutExtension, oVersionSeparator, oFileVersion, oExtension)) + _logger.Debug("Intermediate Filename is {0}", oFinalFileName) + _logger.Debug("File version: {0}", oFileVersion) + oFileVersion += 1 + Loop While (IO.File.Exists(oFinalFileName)) + + _logger.Debug("Final Filename is {0}", oFinalFileName) + + Return oFinalFileName + Catch ex As Exception + _logger.Warn("Filename {0} could not be versioned. Original filename will be returned!", Destination) + _logger.Error(ex) + Return Destination + End Try + End Function + + Private Function GetFilenameWithVersion(FileNameWithoutExtension As String, VersionSeparator As Char, FileVersion As Integer, Extension As String) As String + If FileVersion <= 1 Then + Return $"{FileNameWithoutExtension}{Extension}" + Else + Return $"{FileNameWithoutExtension}{VersionSeparator}{FileVersion}{Extension}" + End If + End Function + + ''' + ''' Removes files in a directory filtered by filename, extension and last write date + ''' + ''' The directory in which files will be deleted + ''' Only delete files which are older than x days. Must be between 0 and 1000 days. + ''' A filename filter which will be checked + ''' A file extension which will be checked + ''' Should the function continue with deleting when a file could not be deleted? + ''' True if all files were deleted or if no files were deleted, otherwise false + Public Function RemoveFiles(Path As String, FileKeepTime As Integer, FileBaseName As String, Optional FileExtension As String = "log", Optional ContinueOnError As Boolean = True) As Boolean + If Not TestPathIsDirectory(Path) Then + Throw New ArgumentException($"Path {Path} is not a directory!") + End If + + If Not Directory.Exists(Path) Then + Throw New DirectoryNotFoundException($"Path {Path} does not exist!") + End If + + If FileKeepTime < 0 Or FileKeepTime > 1000 Then + Throw New ArgumentOutOfRangeException("FileKeepTime must be an integer between 0 and 1000!") + End If + + Dim oUnableToDeleteCounter = 0 + Dim oDirectory As New DirectoryInfo(Path) + Dim oDateLimit As DateTime = DateTime.Now.AddDays(FileKeepTime) + Dim oFiles As List(Of FileInfo) = oDirectory. + EnumerateFiles($"*{FileBaseName}*"). + Where(Function(oFileInfo As FileInfo) + Return oFileInfo.Extension = FileExtension And oFileInfo.LastWriteTime < oDateLimit + End Function) + + If oFiles.Count = 0 Then + _logger.Debug("No files found that match the criterias.") + Return True + End If + + _logger.Debug("Deleting old files (Found {0}).", oFiles.Count) + + For Each oFile As FileInfo In oFiles + Try + oFile.Delete() + Catch ex As Exception + If ContinueOnError = False Then + _logger.Warn("Deleting files was aborted at file {0}.", oFile.FullName) + Return False + End If + oUnableToDeleteCounter = oUnableToDeleteCounter + 1 + _logger.Warn("File {0} could not be deleted!") + End Try + Next + + If oUnableToDeleteCounter > 0 Then + _logger.Debug("Old files partially removed. {0} files could not be removed.", oUnableToDeleteCounter) + Else + _logger.Debug("Old files removed.") + End If + + Return True + End Function + + + Public Sub MoveTo(FilePath As String, Directory As String) + Dim oFileInfo As New FileInfo(FilePath) + IO.File.Move(FilePath, Path.Combine(Directory, oFileInfo.Name)) + End Sub + + + Public Sub MoveTo(FilePath As String, NewFileName As String, Directory As String) + IO.File.Move(FilePath, Path.Combine(Directory, NewFileName)) + End Sub + + ''' + ''' Tries to create a directory and returns its path. + ''' Returns a temp path if `DirectoryPath` can not be created or written to. + ''' + ''' The directory to create + ''' Should a write access test be performed? + ''' The used path + Public Function CreateDirectory(DirectoryPath As String, Optional TestWriteAccess As Boolean = True) As String + Dim oFinalPath As String + If Directory.Exists(DirectoryPath) Then + _logger.Debug("Directory {0} already exists. Skipping.", DirectoryPath) + oFinalPath = DirectoryPath + Else + Try + Directory.CreateDirectory(DirectoryPath) + oFinalPath = DirectoryPath + Catch ex As Exception + _logger.Error(ex) + _logger.Warn("Directory {0} could not be created. Temp path will be used instead.", DirectoryPath) + oFinalPath = Path.GetTempPath() + End Try + End If + + If TestWriteAccess AndAlso Not TestPathIsWritable(DirectoryPath) Then + _logger.Warn("Directory {0} is not writable. Temp path will be used instead.", DirectoryPath) + oFinalPath = Path.GetTempPath() + Else + oFinalPath = DirectoryPath + End If + + _logger.Debug("Using path {0}", oFinalPath) + + Return oFinalPath + End Function + + Public Function TestPathIsWritable(DirectoryPath As String) As Boolean + Try + Dim fileAccessPath = Path.Combine(DirectoryPath, FILE_NAME_ACCESS_TEST) + Using fs As FileStream = IO.File.Create(fileAccessPath) + fs.WriteByte(0) + End Using + + IO.File.Delete(fileAccessPath) + Return True + Catch ex As Exception + Return False + End Try + End Function + + Public Function TestPathIsDirectory(Path As String) As Boolean + If Not Directory.Exists(Path) Then + Return False + End If + + Dim oIsDirectory As Boolean = (System.IO.File.GetAttributes(Path) And FileAttributes.Directory) = FileAttributes.Directory + Return oIsDirectory + End Function + +End Class diff --git a/WinLineArtikelnummerGenerator/Modules/LogConfig.vb b/WinLineArtikelnummerGenerator/Modules/LogConfig.vb new file mode 100644 index 0000000..6449dce --- /dev/null +++ b/WinLineArtikelnummerGenerator/Modules/LogConfig.vb @@ -0,0 +1,455 @@ +Imports System.IO +Imports System.Reflection +Imports NLog +Imports NLog.Config +Imports NLog.Targets + +''' LogConfig +''' 0.0.1.0 +''' 02.10.2018 +''' +''' Module that writes file-logs to different locations: +''' local application data, the current directory or a custom path. +''' Files and directories will be automatically created. +''' +''' +''' NLog, >= 4.5.8 +''' +''' +''' Imports DigitalData.Modules.Logging +''' +''' Class FooProgram +''' Private Logger as Logger +''' Private LogConfig as LogConfig +''' +''' Public Sub New() +''' LogConfig = new LogConfig(args) +''' Logger = LogConfig.GetLogger() +''' End Sub +''' +''' Public Sub Bar() +''' Logger.Info("Baz") +''' End Sub +''' End Class +''' +''' Class FooLib +''' Private Logger as NLog.Logger +''' +''' Public Sub New(LogConfig as LogConfig) +''' Logger = LogConfig.GetLogger() +''' End Sub +''' +''' Public Sub Bar() +''' Logger.Info("Baz") +''' End Sub +''' End Class +''' +''' +''' If logpath can not be written to, falls back to temp folder as defined in: +''' https://docs.microsoft.com/de-de/dotnet/api/system.io.path.gettemppath?view=netframework-4.7.2 +''' +''' If used in a service, LogPath must be set to CustomPath, otherwise the Log will be written to System32! +''' +''' For NLog Troubleshooting, set the following Environment variables to write the NLog internal Log: +''' - NLOG_INTERNAL_LOG_LEVEL: Debug +''' - NLOG_INTERNAL_LOG_FILE: ex. C:\Temp\Nlog_Internal.log +''' +Public Class LogConfig +#Region "Private Properties" + Private Const OPEN_FILE_CACHE_TIMEOUT As Integer = 5 + Private Const OPEN_FILE_FLUSH_TIMEOUT As Integer = 5 + Private Const AUTO_FLUSH As Boolean = True + + Private Const KEEP_FILES_OPEN As Boolean = False + Private Const KEEP_FILES_OPEN_DEBUG As Boolean = True + + ' MAX_ARCHIVES_FILES works like this (in version 4.5.8): + ' 0 = keep ALL archives files + ' 1 = only keep latest logfile and NO archive files + ' n = keep n archive files + Private Const MAX_ARCHIVE_FILES_DEFAULT As Integer = 0 + Private Const MAX_ARCHIVE_FILES_DEBUG_DETAIL As Integer = 0 + Private Const ARCHIVE_EVERY As FileArchivePeriod = FileArchivePeriod.Day + + Private Const FILE_NAME_FORMAT_DEFAULT As String = "${shortdate}-${var:product}${var:suffix}.log" + Private Const FILE_NAME_FORMAT_DEBUG As String = "${shortdate}-${var:product}${var:suffix}-Debug.log" + Private Const FILE_NAME_FORMAT_ERROR As String = "${shortdate}-${var:product}${var:suffix}-Error.log" + + Private Const TARGET_DEFAULT As String = "defaultTarget" + Private Const TARGET_ERROR_EX As String = "errorExceptionTarget" + Private Const TARGET_ERROR As String = "errorTarget" + Private Const TARGET_DEBUG As String = "debugTarget" + Private Const TARGET_MEMORY As String = "memoryTarget" + + Private Const DATE_FORMAT_LONG As String = "${longdate}" + Private Const DATE_FORMAT_DEFAULT As String = "${date:format=yyyy-MM-dd HH\:mm\:ss}" + + Private Const LOG_FORMAT_BASE As String = DATE_FORMAT_DEFAULT & "|${logger:shortName=True}|${level:uppercase=true}" + Private Const LOG_FORMAT_BASE_LONG_DATE As String = DATE_FORMAT_LONG & "|${logger:shortName=True}|${level:uppercase=true}" + Private Const LOG_FORMAT_CALLSITE As String = "${callsite:className=false:fileName=true:includeSourcePath=false:methodName=true}" + + Private Const LOG_FORMAT_DEFAULT As String = LOG_FORMAT_BASE & " >> ${message}" + Private Const LOG_FORMAT_EXCEPTION As String = LOG_FORMAT_BASE & " >> ${exception:format=Message}${newline}${exception:format=StackTrace}" + Private Const LOG_FORMAT_DEBUG As String = LOG_FORMAT_BASE_LONG_DATE & " >> " & LOG_FORMAT_CALLSITE & " -> ${message}" + Private Const LOG_FORMAT_MEMORY As String = LOG_FORMAT_BASE_LONG_DATE & " >> ${message}${newline}${exception:format=Message}${newline}${exception:format=StackTrace}" + + Private Const FILE_NAME_ACCESS_TEST = "accessTest.txt" + Private Const FOLDER_NAME_LOG = "Log" + + Private ReadOnly failSafePath As String = Path.GetTempPath() + Private ReadOnly basePath As String = failSafePath + + Private config As LoggingConfiguration + Private isDebug As Boolean = False +#End Region +#Region "Public Properties" + Public Enum PathType As Integer + AppData = 0 + CurrentDirectory = 1 + CustomPath = 2 + Temp = 3 + End Enum + + ''' + ''' Returns the NLog.LogFactory object that is used to create Loggers + ''' + ''' LogFactory object + Public ReadOnly Property LogFactory As LogFactory + + ''' + ''' Returns the path to the current default logfile + ''' + ''' Filepath to the logfile + Public ReadOnly Property LogFile As String + + ''' + ''' Returns the path to the current log directory + ''' + ''' Directory path to the log directory + Public ReadOnly Property LogDirectory As String + + ''' + ''' Determines if a debug log will be written + ''' + ''' True, if debug log will be written. False otherwise. + Public Property Debug As Boolean + Get + Return isDebug + End Get + Set(isDebug As Boolean) + Me.isDebug = isDebug + 'GetLogger().Debug("=> Debug is now {0}", isDebug) + ReloadConfig(isDebug) + End Set + End Property + + ''' + ''' Returns Logs in Memory as List(Of String) if Debug is enabled + ''' Returns an empty list if debug is disabled + ''' + ''' A list of log messages + Public ReadOnly Property Logs As List(Of String) + Get + Dim oTarget = config.FindTargetByName(Of MemoryTarget)(TARGET_MEMORY) + Return oTarget?.Logs.ToList() + End Get + End Property + + Public ReadOnly Property NLogConfig As LoggingConfiguration + Get + Return config + End Get + End Property + +#End Region + + ''' + ''' Initializes a new LogConfig object with a logpath and optinally a filename-suffix. + ''' + ''' The basepath to write logs to. Can be AppData, CurrentDirectory or CustomPath. + ''' If `logPath` is set to custom, this defines the custom logPath. + ''' If set to anything other than Nothing, extends the logfile name with this suffix. + ''' CompanyName is used to construct log-path in when LogPath is set to PathType:AppData + ''' ProductName is used to construct log-path in when LogPath is set to PathType:AppData + Public Sub New(LogPath As PathType, + Optional CustomLogPath As String = Nothing, + Optional Suffix As String = Nothing, + Optional CompanyName As String = Nothing, + Optional ProductName As String = Nothing) + + If LogPath = PathType.AppData And (ProductName Is Nothing Or CompanyName Is Nothing) Then + Throw New ArgumentException("Modules.Logging: PathType is AppData and either CompanyName or ProductName was not supplied!") + End If + + If LogPath = PathType.CurrentDirectory Then + Throw New ArgumentException("Modules.Logging: LogPath.CurrentDirectory is deprecated. Please use LogPath.CustomPath!") + End If + + If LogPath = PathType.AppData Then + Dim appDataDir = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData) + basePath = Path.Combine(appDataDir, CompanyName, ProductName, FOLDER_NAME_LOG) + ElseIf LogPath = PathType.Temp Then + basePath = failSafePath + Else 'Custom Path + basePath = CustomLogPath + End If + + ' If directory does not exist, try to create it! + If Not Directory.Exists(basePath) Then + Try + Directory.CreateDirectory(basePath) + Catch ex As Exception + ' If creation fails, use failSafe path + basePath = failSafePath + End Try + End If + + ' Try to create a file in `basePath` to check write permissions + Try + Dim fileAccessPath = Path.Combine(basePath, FILE_NAME_ACCESS_TEST) + Using fs As FileStream = System.IO.File.Create(fileAccessPath) + fs.WriteByte(0) + End Using + + IO.File.Delete(fileAccessPath) + Catch ex As Exception + ' If creation fails, use failSafe path + basePath = failSafePath + End Try + + ' Set the suffix to the given string if it exists + Dim logFileSuffix As String = String.Empty + + If Suffix IsNot Nothing AndAlso Suffix.Count > 0 Then + logFileSuffix = $"-{Suffix}" + End If + + Dim oProductName As String = "Main" + + If ProductName IsNot Nothing Then + oProductName = ProductName + End If + + ' Create config object and initalize it + config = GetConfig(oProductName, logFileSuffix) + + ' Save config + LogFactory = New LogFactory With { + .Configuration = config + } + + ' Save log paths for files/directory + LogDirectory = basePath + LogFile = GetCurrentLogFilePath() + End Sub + + Private Sub CheckMyApplication() + Dim oAssembly = Assembly.GetEntryAssembly() + Dim oMyApp = Nothing + For Each oType As Type In oAssembly.DefinedTypes + If oType.Name = "MyApplication" Then + oMyApp = oType + Exit For + End If + Next + + oMyApp.GetType().GetProperty("") + End Sub + + ''' + ''' Returns the Logger for the calling class + ''' + ''' An object of Logging.Logger + + Public Function GetLogger() As Logger + Dim oClassName As String = GetClassFullName() + Return LogFactory.GetLogger(Of Logger)(oClassName) + End Function + + ''' + ''' Returns the Logger for a class specified by `ClassName` + ''' + ''' The name of the class the logger belongs to + ''' An object of Logging.Logger + + Public Function GetLogger(ClassName As String) As Logger + Return LogFactory.GetLogger(Of Logger)(ClassName) + End Function + + ''' + ''' Clears the internal log + ''' + Public Sub ClearLogs() + Dim oTarget = config.FindTargetByName(Of MemoryTarget)(TARGET_MEMORY) + oTarget?.Logs.Clear() + End Sub + + ''' + ''' Gets the fully qualified name of the class invoking the calling method, + ''' including the namespace but Not the assembly. + ''' + ''' The fully qualified class name + ''' This method is very resource-intensive! + + Public Shared Function GetClassFullName() As String + Dim oFramesToSkip As Integer = 2 + Dim oClassName As String = String.Empty + Dim oStackTrace = Environment.StackTrace + Dim oStackTraceLines = oStackTrace.Replace(vbCr, "").Split({vbLf}, StringSplitOptions.RemoveEmptyEntries) + + For i As Integer = 0 To oStackTraceLines.Length - 1 + Dim oCallingClassAndMethod = oStackTraceLines(i).Split({" ", "<>", "(", ")"}, StringSplitOptions.RemoveEmptyEntries)(1) + Dim oMethodStartIndex As Integer = oCallingClassAndMethod.LastIndexOf(".", StringComparison.Ordinal) + + If oMethodStartIndex > 0 Then + Dim oCallingClass = oCallingClassAndMethod.Substring(0, oMethodStartIndex) + oClassName = oCallingClass.TrimEnd("."c) + + If Not oClassName.StartsWith("System.Environment") AndAlso oFramesToSkip <> 0 Then + i += oFramesToSkip - 1 + oFramesToSkip = 0 + Continue For + End If + + If Not oClassName.StartsWith("System.") Then Exit For + End If + Next + + Return oClassName + End Function + + ''' + ''' Returns the initial log configuration + ''' + ''' The chosen productname + ''' The chosen suffix + ''' A NLog.LoggingConfiguration object + Private Function GetConfig(productName As String, logFileSuffix As String) As LoggingConfiguration + config = New LoggingConfiguration() + config.Variables("product") = productName + config.Variables("suffix") = logFileSuffix + + ' Add default targets + config.AddTarget(TARGET_ERROR_EX, GetErrorExceptionLogTarget(basePath)) + config.AddTarget(TARGET_ERROR, GetErrorLogTarget(basePath)) + config.AddTarget(TARGET_DEFAULT, GetDefaultLogTarget(basePath)) + config.AddTarget(TARGET_DEBUG, GetDebugLogTarget(basePath)) + config.AddTarget(TARGET_MEMORY, GetMemoryDebugTarget()) + + ' Add default rules + AddDefaultRules(config) + + Return config + End Function + + ''' + ''' Adds the default rules + ''' + ''' A NLog.LoggingConfiguration object + Private Sub AddDefaultRules(ByRef config As LoggingConfiguration) + config.AddRuleForOneLevel(LogLevel.Error, TARGET_ERROR_EX) + config.AddRuleForOneLevel(LogLevel.Fatal, TARGET_ERROR_EX) + config.AddRuleForOneLevel(LogLevel.Warn, TARGET_ERROR) + config.AddRuleForOneLevel(LogLevel.Warn, TARGET_DEFAULT) + config.AddRuleForOneLevel(LogLevel.Info, TARGET_DEFAULT) + End Sub + + ''' + ''' Returns the full path of the current default log file. + ''' + ''' Full path of the current default log file + Private Function GetCurrentLogFilePath() + Dim logEventInfo As New LogEventInfo() With {.TimeStamp = Date.Now} + Dim target As FileTarget = config.FindTargetByName(TARGET_DEFAULT) + Dim fileName As String = target.FileName.Render(logEventInfo) + + Return fileName + End Function + + ''' + ''' Reconfigures and re-adds all loggers, optionally adding the debug rule. + ''' + ''' Adds the Debug rule if true. + Private Sub ReloadConfig(Optional Debug As Boolean = False) + ' Clear Logging Rules + config.LoggingRules.Clear() + + ' Add default rules + AddDefaultRules(config) + + ' Add debug rule, if configured + If Debug Then + config.AddRuleForOneLevel(LogLevel.Debug, TARGET_DEBUG) + config.AddRuleForAllLevels(TARGET_MEMORY) + End If + + ' Reload all running loggers + LogFactory.ReconfigExistingLoggers() + End Sub + +#Region "Log Targets" + Private Function GetDefaultLogTarget(basePath As String) As FileTarget + Dim defaultLog As New FileTarget() With { + .FileName = Path.Combine(basePath, FILE_NAME_FORMAT_DEFAULT), + .Name = TARGET_DEFAULT, + .Layout = LOG_FORMAT_DEFAULT, + .MaxArchiveFiles = MAX_ARCHIVE_FILES_DEFAULT, + .ArchiveEvery = ARCHIVE_EVERY, + .KeepFileOpen = KEEP_FILES_OPEN + } + + Return defaultLog + End Function + Private Function GetErrorExceptionLogTarget(basePath As String) As FileTarget + Dim errorLogWithExceptions As New FileTarget() With { + .FileName = Path.Combine(basePath, FILE_NAME_FORMAT_ERROR), + .Name = TARGET_ERROR_EX, + .Layout = LOG_FORMAT_EXCEPTION, + .MaxArchiveFiles = MAX_ARCHIVE_FILES_DEFAULT, + .ArchiveEvery = ARCHIVE_EVERY, + .KeepFileOpen = KEEP_FILES_OPEN + } + + Return errorLogWithExceptions + End Function + + Private Function GetErrorLogTarget(basePath As String) As FileTarget + Dim errorLog As New FileTarget() With { + .FileName = Path.Combine(basePath, FILE_NAME_FORMAT_ERROR), + .Name = TARGET_ERROR, + .Layout = LOG_FORMAT_DEFAULT, + .MaxArchiveFiles = MAX_ARCHIVE_FILES_DEFAULT, + .ArchiveEvery = ARCHIVE_EVERY, + .KeepFileOpen = KEEP_FILES_OPEN + } + + Return errorLog + End Function + + Private Function GetDebugLogTarget(basePath As String) As FileTarget + Dim debugLog As New FileTarget() With { + .FileName = Path.Combine(basePath, FILE_NAME_FORMAT_DEBUG), + .Name = TARGET_DEBUG, + .Layout = LOG_FORMAT_DEBUG, + .MaxArchiveFiles = MAX_ARCHIVE_FILES_DEBUG_DETAIL, + .ArchiveEvery = ARCHIVE_EVERY, + .KeepFileOpen = KEEP_FILES_OPEN_DEBUG, + .OpenFileCacheTimeout = OPEN_FILE_CACHE_TIMEOUT, + .AutoFlush = AUTO_FLUSH, + .OpenFileFlushTimeout = OPEN_FILE_FLUSH_TIMEOUT + } + + Return debugLog + End Function + + Private Function GetMemoryDebugTarget() As MemoryTarget + Dim memoryLog As New MemoryTarget() With { + .Layout = LOG_FORMAT_MEMORY, + .Name = TARGET_MEMORY, + .OptimizeBufferReuse = True + } + + Return memoryLog + End Function +#End Region +End Class diff --git a/WinLineArtikelnummerGenerator/Modules/Logger.vb b/WinLineArtikelnummerGenerator/Modules/Logger.vb new file mode 100644 index 0000000..c7f56c7 --- /dev/null +++ b/WinLineArtikelnummerGenerator/Modules/Logger.vb @@ -0,0 +1,28 @@ +Imports NLog + +Public Class Logger + Inherits NLog.Logger + Implements ILogger + + ''' + ''' Prints a preformatted Block including a block identifier + ''' + ''' A unique Identifier for this block, eg. DocId, FullPath, .. + + Public Sub NewBlock(blockId As String) + Dim message As String = $"-----> Start of Block {blockId}" + Dim logEventInfo As New LogEventInfo(LogLevel.Info, Name, message) + Dim WrapperType As Type = GetType(Logger) + + Log(WrapperType, logEventInfo) + End Sub + + + Public Sub EndBlock() + Dim message As String = $"<----- End of Block" + Dim logEventInfo As New LogEventInfo(LogLevel.Info, Name, message) + Dim WrapperType As Type = GetType(Logger) + + Log(WrapperType, logEventInfo) + End Sub +End Class \ No newline at end of file diff --git a/WinLineArtikelnummerGenerator/My Project/Application.Designer.vb b/WinLineArtikelnummerGenerator/My Project/Application.Designer.vb new file mode 100644 index 0000000..3319c45 --- /dev/null +++ b/WinLineArtikelnummerGenerator/My Project/Application.Designer.vb @@ -0,0 +1,38 @@ +'------------------------------------------------------------------------------ +' +' This code was generated by a tool. +' Runtime Version:4.0.30319.42000 +' +' Changes to this file may cause incorrect behavior and will be lost if +' the code is regenerated. +' +'------------------------------------------------------------------------------ + +Option Strict On +Option Explicit On + + +Namespace My + + 'NOTE: This file is auto-generated; do not modify it directly. To make changes, + ' or if you encounter build errors in this file, go to the Project Designer + ' (go to Project Properties or double-click the My Project node in + ' Solution Explorer), and make changes on the Application tab. + ' + Partial Friend Class MyApplication + + _ + Public Sub New() + MyBase.New(Global.Microsoft.VisualBasic.ApplicationServices.AuthenticationMode.Windows) + Me.IsSingleInstance = false + Me.EnableVisualStyles = true + Me.SaveMySettingsOnExit = true + Me.ShutDownStyle = Global.Microsoft.VisualBasic.ApplicationServices.ShutdownMode.AfterMainFormCloses + End Sub + + _ + Protected Overrides Sub OnCreateMainForm() + Me.MainForm = Global.WinLineArtikelnummerGenerator.frmMain + End Sub + End Class +End Namespace diff --git a/WinLineArtikelnummerGenerator/My Project/Application.myapp b/WinLineArtikelnummerGenerator/My Project/Application.myapp new file mode 100644 index 0000000..1243847 --- /dev/null +++ b/WinLineArtikelnummerGenerator/My Project/Application.myapp @@ -0,0 +1,11 @@ + + + true + Form1 + false + 0 + true + 0 + 0 + true + diff --git a/WinLineArtikelnummerGenerator/My Project/AssemblyInfo.vb b/WinLineArtikelnummerGenerator/My Project/AssemblyInfo.vb new file mode 100644 index 0000000..a9cd2b2 --- /dev/null +++ b/WinLineArtikelnummerGenerator/My Project/AssemblyInfo.vb @@ -0,0 +1,35 @@ +Imports System +Imports System.Reflection +Imports System.Runtime.InteropServices + +' Allgemeine Informationen über eine Assembly werden über die folgenden +' Attribute gesteuert. Ändern Sie diese Attributwerte, um die Informationen zu ändern, +' die einer Assembly zugeordnet sind. + +' Werte der Assemblyattribute überprüfen + + + + + + + + + + +'Die folgende GUID wird für die typelib-ID verwendet, wenn dieses Projekt für COM verfügbar gemacht wird. + + +' Versionsinformationen für eine Assembly bestehen aus den folgenden vier Werten: +' +' Hauptversion +' Nebenversion +' Buildnummer +' Revision +' +' Sie können alle Werte angeben oder Standardwerte für die Build- und Revisionsnummern verwenden, +' indem Sie "*" wie unten gezeigt eingeben: +' + + + diff --git a/WinLineArtikelnummerGenerator/My Project/Resources.Designer.vb b/WinLineArtikelnummerGenerator/My Project/Resources.Designer.vb new file mode 100644 index 0000000..93d083e --- /dev/null +++ b/WinLineArtikelnummerGenerator/My Project/Resources.Designer.vb @@ -0,0 +1,62 @@ +'------------------------------------------------------------------------------ +' +' This code was generated by a tool. +' Runtime Version:4.0.30319.42000 +' +' Changes to this file may cause incorrect behavior and will be lost if +' the code is regenerated. +' +'------------------------------------------------------------------------------ + +Option Strict On +Option Explicit On + + +Namespace My.Resources + + 'This class was auto-generated by the StronglyTypedResourceBuilder + 'class via a tool like ResGen or Visual Studio. + 'To add or remove a member, edit your .ResX file then rerun ResGen + 'with the /str option, or rebuild your VS project. + ''' + ''' A strongly-typed resource class, for looking up localized strings, etc. + ''' + _ + Friend Module Resources + + Private resourceMan As Global.System.Resources.ResourceManager + + Private resourceCulture As Global.System.Globalization.CultureInfo + + ''' + ''' Returns the cached ResourceManager instance used by this class. + ''' + _ + Friend ReadOnly Property ResourceManager() As Global.System.Resources.ResourceManager + Get + If Object.ReferenceEquals(resourceMan, Nothing) Then + Dim temp As Global.System.Resources.ResourceManager = New Global.System.Resources.ResourceManager("WinLineArtikelnummerGenerator.Resources", GetType(Resources).Assembly) + resourceMan = temp + End If + Return resourceMan + End Get + End Property + + ''' + ''' Overrides the current thread's CurrentUICulture property for all + ''' resource lookups using this strongly typed resource class. + ''' + _ + Friend Property Culture() As Global.System.Globalization.CultureInfo + Get + Return resourceCulture + End Get + Set(ByVal value As Global.System.Globalization.CultureInfo) + resourceCulture = value + End Set + End Property + End Module +End Namespace diff --git a/WinLineArtikelnummerGenerator/My Project/Resources.resx b/WinLineArtikelnummerGenerator/My Project/Resources.resx new file mode 100644 index 0000000..af7dbeb --- /dev/null +++ b/WinLineArtikelnummerGenerator/My Project/Resources.resx @@ -0,0 +1,117 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/WinLineArtikelnummerGenerator/My Project/Settings.Designer.vb b/WinLineArtikelnummerGenerator/My Project/Settings.Designer.vb new file mode 100644 index 0000000..06f00a9 --- /dev/null +++ b/WinLineArtikelnummerGenerator/My Project/Settings.Designer.vb @@ -0,0 +1,96 @@ +'------------------------------------------------------------------------------ +' +' Dieser Code wurde von einem Tool generiert. +' Laufzeitversion:4.0.30319.42000 +' +' Änderungen an dieser Datei können falsches Verhalten verursachen und gehen verloren, wenn +' der Code erneut generiert wird. +' +'------------------------------------------------------------------------------ + +Option Strict On +Option Explicit On + + +Namespace My + + _ + Partial Friend NotInheritable Class MySettings + Inherits Global.System.Configuration.ApplicationSettingsBase + + Private Shared defaultInstance As MySettings = CType(Global.System.Configuration.ApplicationSettingsBase.Synchronized(New MySettings()),MySettings) + +#Region "Automatische My.Settings-Speicherfunktion" +#If _MyType = "WindowsForms" Then + Private Shared addedHandler As Boolean + + Private Shared addedHandlerLockObject As New Object + + _ + Private Shared Sub AutoSaveSettings(sender As Global.System.Object, e As Global.System.EventArgs) + If My.Application.SaveMySettingsOnExit Then + My.Settings.Save() + End If + End Sub +#End If +#End Region + + Public Shared ReadOnly Property [Default]() As MySettings + Get + +#If _MyType = "WindowsForms" Then + If Not addedHandler Then + SyncLock addedHandlerLockObject + If Not addedHandler Then + AddHandler My.Application.Shutdown, AddressOf AutoSaveSettings + addedHandler = True + End If + End SyncLock + End If +#End If + Return defaultInstance + End Get + End Property + + _ + Public Property ConnectionString() As String + Get + Return CType(Me("ConnectionString"),String) + End Get + Set + Me("ConnectionString") = value + End Set + End Property + + _ + Public ReadOnly Property MyConnectionString() As String + Get + Return CType(Me("MyConnectionString"),String) + End Get + End Property + End Class +End Namespace + +Namespace My + + _ + Friend Module MySettingsProperty + + _ + Friend ReadOnly Property Settings() As Global.WinLineArtikelnummerGenerator.My.MySettings + Get + Return Global.WinLineArtikelnummerGenerator.My.MySettings.Default + End Get + End Property + End Module +End Namespace diff --git a/WinLineArtikelnummerGenerator/My Project/Settings.settings b/WinLineArtikelnummerGenerator/My Project/Settings.settings new file mode 100644 index 0000000..493047d --- /dev/null +++ b/WinLineArtikelnummerGenerator/My Project/Settings.settings @@ -0,0 +1,17 @@ + + + + + + + + + <?xml version="1.0" encoding="utf-16"?> +<SerializableConnectionString xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> + <ConnectionString>Data Source=SDD-VMP04-SQL17\MEDACOM;Initial Catalog=CWLDATEN_MEDS;User ID=sa;Password=dd</ConnectionString> + <ProviderName>System.Data.SqlClient</ProviderName> +</SerializableConnectionString> + Data Source=SDD-VMP04-SQL17\MEDACOM;Initial Catalog=CWLDATEN_MEDS;User ID=sa;Password=dd + + + \ No newline at end of file diff --git a/WinLineArtikelnummerGenerator/My Project/licenses.licx b/WinLineArtikelnummerGenerator/My Project/licenses.licx new file mode 100644 index 0000000..d39415a --- /dev/null +++ b/WinLineArtikelnummerGenerator/My Project/licenses.licx @@ -0,0 +1,2 @@ +DevExpress.XtraGrid.GridControl, DevExpress.XtraGrid.v20.1, Version=20.1.3.0, Culture=neutral, PublicKeyToken=b88d1754d700e49a +DevExpress.XtraBars.Ribbon.RibbonControl, DevExpress.XtraBars.v20.1, Version=20.1.3.0, Culture=neutral, PublicKeyToken=b88d1754d700e49a diff --git a/WinLineArtikelnummerGenerator/WinLineArtikelnummerGenerator.vbproj b/WinLineArtikelnummerGenerator/WinLineArtikelnummerGenerator.vbproj new file mode 100644 index 0000000..b73b935 --- /dev/null +++ b/WinLineArtikelnummerGenerator/WinLineArtikelnummerGenerator.vbproj @@ -0,0 +1,186 @@ + + + + + Debug + AnyCPU + {BA171D0B-6421-4294-B5DC-BF77D93C91E7} + WinExe + WinLineArtikelnummerGenerator.My.MyApplication + WinLineArtikelnummerGenerator + WinLineArtikelnummerGenerator + 512 + WindowsForms + v4.7.2 + true + true + + + AnyCPU + true + full + true + true + bin\Debug\ + WinLineArtikelnummerGenerator.xml + 42016,41999,42017,42018,42019,42032,42036,42020,42021,42022 + + + AnyCPU + pdbonly + false + true + true + bin\Release\ + WinLineArtikelnummerGenerator.xml + 42016,41999,42017,42018,42019,42032,42036,42020,42021,42022 + + + On + + + Binary + + + Off + + + On + + + + + + + + + + + + + + ..\..\DDMonorepo\Modules.Config\bin\Debug\DigitalData.Modules.Config.dll + + + ..\..\DDMonorepo\Modules.Database\bin\Debug\DigitalData.Modules.Database.dll + + + ..\..\DDMonorepo\Modules.Filesystem\bin\Debug\DigitalData.Modules.Filesystem.dll + + + ..\..\DDMonorepo\Modules.Language\bin\Debug\DigitalData.Modules.Language.dll + + + ..\..\DDMonorepo\Modules.Logging\bin\Debug\DigitalData.Modules.Logging.dll + + + + ..\packages\NLog.4.7.4\lib\net45\NLog.dll + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + True + True + CWLDATEN_MEDSDataSet.xsd + + + frmMain.vb + + + Form + + + + + + + + + + True + Application.myapp + + + True + True + Resources.resx + + + True + Settings.settings + True + + + + + + + frmMain.vb + + + + VbMyResourcesResXFileCodeGenerator + Resources.Designer.vb + My.Resources + Designer + + + + + CWLDATEN_MEDSDataSet.xsd + + + MSDataSetGenerator + CWLDATEN_MEDSDataSet.Designer.vb + Designer + + + CWLDATEN_MEDSDataSet.xsd + + + MyApplicationCodeGenerator + Application.Designer.vb + + + SettingsSingleFileGenerator + My + Settings.Designer.vb + + + + + + \ No newline at end of file diff --git a/WinLineArtikelnummerGenerator/frmMain.Designer.vb b/WinLineArtikelnummerGenerator/frmMain.Designer.vb new file mode 100644 index 0000000..5f33330 --- /dev/null +++ b/WinLineArtikelnummerGenerator/frmMain.Designer.vb @@ -0,0 +1,161 @@ + _ +Partial Class frmMain + Inherits System.Windows.Forms.Form + + 'Das Formular überschreibt den Löschvorgang, um die Komponentenliste zu bereinigen. + _ + Protected Overrides Sub Dispose(ByVal disposing As Boolean) + Try + If disposing AndAlso components IsNot Nothing Then + components.Dispose() + End If + Finally + MyBase.Dispose(disposing) + End Try + End Sub + + 'Wird vom Windows Form-Designer benötigt. + Private components As System.ComponentModel.IContainer + + 'Hinweis: Die folgende Prozedur ist für den Windows Form-Designer erforderlich. + 'Das Bearbeiten ist mit dem Windows Form-Designer möglich. + 'Das Bearbeiten mit dem Code-Editor ist nicht möglich. + _ + Private Sub InitializeComponent() + Me.listboxVendors = New System.Windows.Forms.ListBox() + Me.listboxProductGroups = New System.Windows.Forms.ListBox() + Me.Label1 = New System.Windows.Forms.Label() + Me.Label2 = New System.Windows.Forms.Label() + Me.Button1 = New System.Windows.Forms.Button() + Me.Button2 = New System.Windows.Forms.Button() + Me.listBoxProductVersion = New System.Windows.Forms.ListBox() + Me.Button3 = New System.Windows.Forms.Button() + Me.Label3 = New System.Windows.Forms.Label() + Me.SuspendLayout() + ' + 'listboxVendors + ' + Me.listboxVendors.Font = New System.Drawing.Font("Consolas", 9.75!, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, CType(0, Byte)) + Me.listboxVendors.FormattingEnabled = True + Me.listboxVendors.ItemHeight = 15 + Me.listboxVendors.Location = New System.Drawing.Point(12, 67) + Me.listboxVendors.Margin = New System.Windows.Forms.Padding(3, 4, 3, 4) + Me.listboxVendors.Name = "listboxVendors" + Me.listboxVendors.Size = New System.Drawing.Size(327, 244) + Me.listboxVendors.TabIndex = 0 + ' + 'listboxProductGroups + ' + Me.listboxProductGroups.Font = New System.Drawing.Font("Consolas", 9.75!, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, CType(0, Byte)) + Me.listboxProductGroups.FormattingEnabled = True + Me.listboxProductGroups.ItemHeight = 15 + Me.listboxProductGroups.Location = New System.Drawing.Point(345, 67) + Me.listboxProductGroups.Margin = New System.Windows.Forms.Padding(3, 4, 3, 4) + Me.listboxProductGroups.Name = "listboxProductGroups" + Me.listboxProductGroups.Size = New System.Drawing.Size(327, 244) + Me.listboxProductGroups.TabIndex = 0 + ' + 'Label1 + ' + Me.Label1.AutoSize = True + Me.Label1.Font = New System.Drawing.Font("Segoe UI Semibold", 9.0!, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, CType(0, Byte)) + Me.Label1.Location = New System.Drawing.Point(9, 18) + Me.Label1.Name = "Label1" + Me.Label1.Size = New System.Drawing.Size(69, 15) + Me.Label1.TabIndex = 1 + Me.Label1.Text = "Lieferanten:" + ' + 'Label2 + ' + Me.Label2.AutoSize = True + Me.Label2.Font = New System.Drawing.Font("Segoe UI Semibold", 9.0!, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, CType(0, Byte)) + Me.Label2.Location = New System.Drawing.Point(342, 18) + Me.Label2.Name = "Label2" + Me.Label2.Size = New System.Drawing.Size(97, 15) + Me.Label2.TabIndex = 1 + Me.Label2.Text = "Produktgruppen:" + ' + 'Button1 + ' + Me.Button1.Location = New System.Drawing.Point(345, 36) + Me.Button1.Name = "Button1" + Me.Button1.Size = New System.Drawing.Size(140, 23) + Me.Button1.TabIndex = 2 + Me.Button1.TabStop = False + Me.Button1.Text = "Neue Produktgruppe" + Me.Button1.UseVisualStyleBackColor = True + ' + 'Button2 + ' + Me.Button2.Location = New System.Drawing.Point(12, 37) + Me.Button2.Name = "Button2" + Me.Button2.Size = New System.Drawing.Size(140, 23) + Me.Button2.TabIndex = 2 + Me.Button2.TabStop = False + Me.Button2.Text = "Neuer Lieferant" + Me.Button2.UseVisualStyleBackColor = True + ' + 'listBoxProductVersion + ' + Me.listBoxProductVersion.Font = New System.Drawing.Font("Consolas", 9.75!, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, CType(0, Byte)) + Me.listBoxProductVersion.FormattingEnabled = True + Me.listBoxProductVersion.ItemHeight = 15 + Me.listBoxProductVersion.Location = New System.Drawing.Point(678, 67) + Me.listBoxProductVersion.Margin = New System.Windows.Forms.Padding(3, 4, 3, 4) + Me.listBoxProductVersion.Name = "listBoxProductVersion" + Me.listBoxProductVersion.Size = New System.Drawing.Size(327, 244) + Me.listBoxProductVersion.TabIndex = 0 + ' + 'Button3 + ' + Me.Button3.Location = New System.Drawing.Point(678, 36) + Me.Button3.Name = "Button3" + Me.Button3.Size = New System.Drawing.Size(140, 23) + Me.Button3.TabIndex = 2 + Me.Button3.TabStop = False + Me.Button3.Text = "Neue Produktversion" + Me.Button3.UseVisualStyleBackColor = True + ' + 'Label3 + ' + Me.Label3.AutoSize = True + Me.Label3.Font = New System.Drawing.Font("Segoe UI Semibold", 9.0!, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, CType(0, Byte)) + Me.Label3.Location = New System.Drawing.Point(675, 18) + Me.Label3.Name = "Label3" + Me.Label3.Size = New System.Drawing.Size(90, 15) + Me.Label3.TabIndex = 1 + Me.Label3.Text = "Produktversion:" + ' + 'frmMain + ' + Me.AutoScaleDimensions = New System.Drawing.SizeF(7.0!, 15.0!) + Me.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font + Me.ClientSize = New System.Drawing.Size(1105, 430) + Me.Controls.Add(Me.Button2) + Me.Controls.Add(Me.Button3) + Me.Controls.Add(Me.Button1) + Me.Controls.Add(Me.Label3) + Me.Controls.Add(Me.Label2) + Me.Controls.Add(Me.Label1) + Me.Controls.Add(Me.listBoxProductVersion) + Me.Controls.Add(Me.listboxProductGroups) + Me.Controls.Add(Me.listboxVendors) + Me.Font = New System.Drawing.Font("Segoe UI", 9.0!, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, CType(0, Byte)) + Me.Margin = New System.Windows.Forms.Padding(3, 4, 3, 4) + Me.Name = "frmMain" + Me.Text = "frmMain" + Me.ResumeLayout(False) + Me.PerformLayout() + + End Sub + + Friend WithEvents listboxVendors As ListBox + Friend WithEvents listboxProductGroups As ListBox + Friend WithEvents Label1 As Label + Friend WithEvents Label2 As Label + Friend WithEvents Button1 As Button + Friend WithEvents Button2 As Button + Friend WithEvents listBoxProductVersion As ListBox + Friend WithEvents Button3 As Button + Friend WithEvents Label3 As Label +End Class diff --git a/WinLineArtikelnummerGenerator/frmMain.resx b/WinLineArtikelnummerGenerator/frmMain.resx new file mode 100644 index 0000000..1af7de1 --- /dev/null +++ b/WinLineArtikelnummerGenerator/frmMain.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/WinLineArtikelnummerGenerator/frmMain.vb b/WinLineArtikelnummerGenerator/frmMain.vb new file mode 100644 index 0000000..9863f9c --- /dev/null +++ b/WinLineArtikelnummerGenerator/frmMain.vb @@ -0,0 +1,60 @@ +Public Class frmMain + Private _Logger As Logger + Private _LogConfig As LogConfig + Private _Config As ConfigManager(Of Config) + Private _Database As Database + + Private Sub frmMain_Load(sender As Object, e As EventArgs) Handles MyBase.Load + _LogConfig = New LogConfig(LogPath:=LogConfig.PathType.AppData, CompanyName:="Digital Data", ProductName:="WinLineProductNumberGenerator") + _Logger = _LogConfig.GetLogger() + _Config = New ConfigManager(Of Config)(_LogConfig, Application.UserAppDataPath) + _Database = New Database(_LogConfig, _Config) + + listboxVendors.DataSource = Nothing + + Dim oVendorDT = _Database.LoadVendors() + Dim oVendors = New List(Of Vendor) + + listboxVendors.DataSource = oVendorDT + listboxVendors.DisplayMember = "c003" + listboxVendors.ValueMember = "c229" + End Sub + + Private Sub frmMain_FormClosed(sender As Object, e As FormClosedEventArgs) Handles Me.FormClosed + _Config.Save() + End Sub + + Private Sub listboxVendors_SelectedIndexChanged(sender As Object, e As EventArgs) Handles listboxVendors.SelectedIndexChanged + If listboxVendors.SelectedIndex >= 0 Then + Dim oVendor As DataRowView = listboxVendors.SelectedItem() + Dim oVendorCode = oVendor.Item("C229") + Dim oVendorId = _Database.LoadVendorIdByCode(oVendorCode) + + listboxProductGroups.DataSource = Nothing + + If oVendorId Is Nothing Then + _Logger.Warn("VendorId does not match any 'Artikeluntergruppen'.") + Exit Sub + End If + + Dim oGroups = _Database.LoadGroupsByVendor(oVendorId) + + listboxProductGroups.DataSource = oGroups + listboxProductGroups.DisplayMember = "C001" + listboxProductGroups.ValueMember = "C999" + End If + End Sub + + Private Sub listboxProductGroups_SelectedIndexChanged(sender As Object, e As EventArgs) Handles listboxProductGroups.SelectedIndexChanged + If listboxProductGroups.SelectedIndex >= 0 Then + Dim oVendor As DataRowView = listboxVendors.SelectedItem() + Dim oGroup As DataRowView = listboxProductGroups.SelectedItem() + + Dim oVendorCode = oVendor.Item("C229") + Dim oVendorId = _Database.LoadVendorIdByCode(oVendorCode) + Dim oGroupId = oGroup.Item("C999") + + Dim Versions = _Database.LoadVersionsByVendorAndGroup(oVendorId, oGroupId) + End If + End Sub +End Class \ No newline at end of file diff --git a/WinLineArtikelnummerGenerator/packages.config b/WinLineArtikelnummerGenerator/packages.config new file mode 100644 index 0000000..b68a5f8 --- /dev/null +++ b/WinLineArtikelnummerGenerator/packages.config @@ -0,0 +1,4 @@ + + + + \ No newline at end of file