Rename Shared to Common

This commit is contained in:
Jonathan Jenne
2022-04-06 14:55:15 +02:00
parent 54ba722ecb
commit 8b6821adde
66 changed files with 268 additions and 152 deletions

View File

@@ -0,0 +1,17 @@
Imports DigitalData.Modules.Database
Imports DigitalData.Modules.Logging
Public Class BaseClass
Inherits DigitalData.Modules.Base.BaseClass
Friend Database As MSSQLServer
Public Sub New(pLogConfig As LogConfig)
MyBase.New(pLogConfig)
End Sub
Public Sub New(pLogConfig As LogConfig, pDatabase As MSSQLServer)
MyBase.New(pLogConfig)
Database = pDatabase
End Sub
End Class

View File

@@ -0,0 +1,8 @@
Imports DigitalData.Modules.Config.ConfigAttributes
Public Class Config
<ConnectionString>
Public Property ConnectionString As String = ""
Public Property LastUsedMandator As String = ""
Public Property Debug As Boolean = False
End Class

View File

@@ -0,0 +1,63 @@
Public Class Constants
Public Const HTTP_REQUEST_TIMEOUT_IN_SECONDS = 60
Public Const COLUMN_GUID = "GUID"
Public Const FUNCTION_GLN = "GLN"
Public Const FUNCTION_EAN = "EAN"
Public Const FUNCTION_PRICE = "PRICE"
Public Const FUNCTION_SQL = "SQL"
Public Const FUNCTION_FIELD = "FIELD"
Public Const TEMPLATE_TYPE_DATE = "xs:date"
Public Const TEMPLATE_TYPE_INTEGER = "xs:integer"
Public Const TEMPLATE_TYPE_DECIMAL = "xs:decimal"
Public Const TEMPLATE_TYPE_BOOLEAN = "xs:boolean"
Public Const DB_TYPE_DATE = "DATE"
Public Const DB_TYPE_INTEGER = "INTEGER"
Public Const DB_TYPE_DECIMAL = "DECIMAL"
Public Const DB_TYPE_BOOLEAN = "BOOLEAN"
Public Const ALL_MESOCOMP = "mesocomp"
Public Const V21_ARTICLENUMBER = "c002"
Public Const V21_ARTICLEDESCRIPTION = "c003"
Public Const V21_MAINARTICLENUMBER = "c011"
Public Const V21_REPLACEMENTARTICLENUMBER = "c123"
Public Const V21_EAN = "c075"
Public Const V50_ACCOUNTNUMBER = "c002"
Public Const V50_ACCOUNTNAME = "c003"
Public Const V50_STREETNAME = "c050"
Public Const V50_ZIPCODE = "c051"
Public Const V50_CITYNAME = "c052"
Public Const V50_GLN = "c260"
Public Const T45_KEY = "c000"
Public Const T45_NAME = "c001"
Public Const T45_CONTACTNUMBER = "c063"
Public Const V05_ACCOUNTID = "c002"
Public Const V05_ACCOUNTNAME = "c003"
Public Const T357_KINDID = "c030"
Public Const T357_KINDNAME = "c001"
Public Const T01_DATABASEINFO = "c004"
Public Const T01_MANDATORID = "c000"
Public Const T01_MANDATORNAME = "c003"
Public Enum ColumnType As Integer
[String]
[Integer]
[Date]
[Boolean]
[Decimal]
End Enum
Public Enum XmlFunction
None = 0
GLN = 1
EAN = 2
End Enum
End Class

View File

@@ -0,0 +1,75 @@
Imports System.IO
Imports MultiTool.Common.Templates
Imports MultiTool.Common.Winline.Entities
Namespace Documents
Public Class Document
Public File As FileInfo
Public Property Type As DocumentType
Public Schema As Template
Public Mandator As Mandator
Public TemplateName As String
Public Property TemplateType As Integer
Public [Option] As Integer
Public PrintVoucher As Integer
''' <summary>
''' Original Values, read-only
''' </summary>
Public Property Rows As New List(Of DocumentRow)
Public Property Selected As Boolean = False
Public Property Imported As Boolean = False
Public ReadOnly Property HasErrors As Boolean
Get
Return Mandator Is Nothing Or Rows.Any(Function(r As DocumentRow) r.HasErrors)
End Get
End Property
Public ReadOnly Property MandatorId As String
Get
Return Mandator?.Id
End Get
End Property
Public ReadOnly Property CreatedAt As Date
Get
Return File?.CreationTime
End Get
End Property
Public ReadOnly Property FullName As String
Get
Return File?.FullName
End Get
End Property
Public ReadOnly Property FileName As String
Get
Return File?.Name
End Get
End Property
''' <summary>
''' Finds the first occurrence of Field and returns its value
''' </summary>
Public Function GetFieldValue(pField As String) As String
For Each oRow In Rows
For Each oField In oRow.Fields
If oField.Key = pField Then
Return oField.Value.Final
End If
Next
Next
Return Nothing
End Function
Public Overrides Function Equals(obj As Object) As Boolean
Return FullName = DirectCast(obj, Document).FullName
End Function
End Class
End Namespace

View File

@@ -0,0 +1,40 @@
Imports System.IO
Imports DigitalData.Modules.Logging
Imports MultiTool.Common.Templates
Namespace Documents
Public Class DocumentCleaner
Inherits BaseClass
Private ReadOnly Template As Template
Private ReadOnly FileEx As DigitalData.Modules.Filesystem.File
Public Sub New(pLogConfig As LogConfig, pTemplate As Template)
MyBase.New(pLogConfig)
Template = pTemplate
FileEx = New DigitalData.Modules.Filesystem.File(LogConfig)
End Sub
Public Function CleanImportedDocuments(pDocuments As List(Of Document)) As Boolean
Dim oResult = True
Dim oOutputDirectory = FileEx.CreateDateDirectory(Template.ArchiveDirectory)
Dim oImportedDocuments = pDocuments.
Where(Function(doc) doc.Imported = True).
ToList()
For Each oDocument As Document In oImportedDocuments
Try
Dim oFileinfo = New FileInfo(oDocument.FullName)
Dim oDestination = Path.Combine(oOutputDirectory, oFileinfo.Name)
File.Move(oFileinfo.FullName, oDestination)
Catch ex As Exception
Logger.Warn("File [{0}] could not be moved to output directory!", oDocument.FullName)
Logger.Error(ex)
oResult = False
End Try
Next
Return oResult
End Function
End Class
End Namespace

View File

@@ -0,0 +1,539 @@
Imports System.IO
Imports System.Text.RegularExpressions
Imports DigitalData.Modules.Logging
Imports DigitalData.Modules.Language
Imports MultiTool.Common.Exceptions
Imports MultiTool.Common.Templates
Imports MultiTool.Common.Winline
Imports MultiTool.Common.Winline.Entities
Namespace Documents
Public Class DocumentLoader
Inherits BaseClass
Private ReadOnly Winline As WinlineData
Private ReadOnly MappingConfig As MappingConfig
Private ReadOnly TemplateConfig As TemplateConfig
Public Property Files As New List(Of Document)
Public Event FileLoadComplete As EventHandler(Of FileLoadInfo)
Public Structure FileLoadInfo
Public FilesLoaded As Integer
Public FilesTotal As Integer
End Structure
Public Sub New(pLogConfig As LogConfig, pWinline As WinlineData, pMappingConfig As MappingConfig, pTemplateConfig As TemplateConfig)
MyBase.New(pLogConfig)
Winline = pWinline
MappingConfig = pMappingConfig
TemplateConfig = pTemplateConfig
End Sub
Public Async Function LoadFiles(pTemplate As Template, pMandator As Mandator) As Task(Of Boolean)
Logger.Info("Loading files from directory [{0}]", pTemplate.InputDirectory)
Files.Clear()
Try
Dim oDirectory As New DirectoryInfo(pTemplate.InputDirectory)
Dim oFiles = oDirectory.GetFiles()
Logger.Debug("Found [{0}] files in directory [{1}]", oFiles.Count, oDirectory)
For Each oFile In oFiles
Try
Dim oDocument = Await LoadFile(oFile, pTemplate, pMandator)
Files.Add(oDocument)
Dim oInfo As FileLoadInfo
oInfo.FilesLoaded = Files.Count
oInfo.FilesTotal = oFiles.Count
RaiseEvent FileLoadComplete(Me, oInfo)
Catch ex As MissingAttributeException
Logger.Error(ex)
Throw New DocumentLoaderException($"Missing Attribute '{ex.Message}' in File '{oFile.Name}'")
Catch ex As Exception
Logger.Error(ex)
Throw ex
End Try
Next
Return True
Catch ex As Exception
Logger.Error(ex)
Throw ex
End Try
End Function
Public Async Function LoadFile(pFileInfo As FileInfo, pTemplate As Template, pMandator As Mandator) As Task(Of Document)
Dim oFileList As New List(Of FileInfo) From {pFileInfo}
Logger.Info("Loading file [{0}]", pFileInfo.Name)
Try
Return Await oFileList.
Select(AddressOf WrapFileInfo).
Select(Function(d) IncludeSchema(d, pTemplate)).
Select(Function(d) LoadDocumentData(d, pTemplate, TemplateConfig)).
Select(Async Function(d) Await MatchDataFromWinLine(d, Winline.Mandators, pMandator, pTemplate)).
SingleOrDefault()
Catch ex As Exception
Logger.Error(ex)
Throw ex
End Try
End Function
Public Sub ReplaceDocument(pDocument As Document)
Dim oIndex = Files.IndexOf(pDocument)
Files.Item(oIndex) = pDocument
End Sub
Private Function IncludeSchema(pDocument As Document, pTemplate As Template) As Document
pDocument.Schema = pTemplate
Return pDocument
End Function
''' <summary>
''' Loads a single document from the FullName Property in the Document Object
''' </summary>
''' <example>
''' A document might look like this:
''' <MESOWebService>
''' <Row1></Row1>
''' <Row2></Row2>
''' <Row3></Row3>
''' </MESOWebService>
''' </example>
Private Function LoadDocumentData(pDocument As Document, pTemplate As Template, pTemplateConfig As TemplateConfig) As Document
Dim oText As String = IO.File.ReadAllText(pDocument.FullName)
Dim oDoc = XDocument.Parse(oText)
Dim oRootElement As XElement = XmlData.GetElement(oDoc, "MESOWebService")
If oRootElement Is Nothing Then
Throw New MalformedXmlException("Datei enthält kein MESOWebService-Element")
End If
Dim oTemplateName = XmlData.GetElementAttribute(oRootElement, "Template")
If oTemplateName Is Nothing Then
Throw New MalformedXmlException("Datei enthält kein Template-Attribut")
End If
Dim oTemplateType = XmlData.GetElementAttribute(oRootElement, "TemplateType")
If oTemplateType Is Nothing Then
Throw New MalformedXmlException("Datei enthält kein TemplateType-Attribut")
End If
Dim oOption = XmlData.GetElementAttribute(oRootElement, "option")
If oOption Is Nothing Then
Throw New MalformedXmlException("Datei enthält kein option-Attribut")
End If
Dim oPrintVoucher = XmlData.GetElementAttribute(oRootElement, "printVoucher")
If oPrintVoucher Is Nothing Then
Throw New MalformedXmlException("Datei enthält kein printVoucher-Attribut")
End If
' The first level of Elements are the document Rows
Dim oTopLevelElements As List(Of XElement) = oRootElement.Elements.ToList
Dim oDocumentRows As New List(Of DocumentRow)
Dim oRowSortKey As Integer = 0
' TODO: Somehow add all fields in the correct order
'
' Right now, the method of
' - first the filled field from xml
' - then the rest from schema
'
' leads to unordered fields.
For Each oTopLevelElement As XElement In oTopLevelElements
Dim oColumnSortKey = 0
Dim oFields As New Dictionary(Of String, DocumentRow.FieldValue)
Dim oSubElements = oTopLevelElement.Descendants().ToList()
Dim oTable = pTemplate.Tables.
Where(Function(t) t.Name = oTopLevelElement.Name).
FirstOrDefault()
For Each oColumn In oTable.Columns
Dim oSubElement = oSubElements.
Where(Function(e) e.Name = oColumn.Name).
SingleOrDefault()
If oSubElement IsNot Nothing Then
Dim oRequired = oColumn.IsRequired
Dim oValue = oSubElement.Value.Trim()
' TODO: Needed when we have time for date times
'If oTemplateField.DataType = Constants.ColumnType.Date Then
' Dim oDate = Date.ParseExact(oValue, "yyyy-MM-dd", CultureInfo.InvariantCulture)
' oValue = oDate.ToString("d")
'End If
oFields.Add(oSubElement.Name.ToString, New DocumentRow.FieldValue With {
.Original = oValue,
.Final = oValue,
.DataType = oColumn.DataType,
.IsRequired = oRequired,
.SortKey = oColumnSortKey
})
Else
Dim oColumnError = DocumentRow.FieldError.None
If oColumn.Config?.IsRequired Then
oColumnError = DocumentRow.FieldError.MissingValue
End If
oFields.Add(oColumn.Name, New DocumentRow.FieldValue With {
.[Error] = oColumnError,
.SortKey = oColumnSortKey
})
End If
oColumnSortKey += 1
Next
' Create a DocumentRow object for each Top Level Element
Dim oRow = New DocumentRow With {
.SortKey = oRowSortKey,
.TableName = oTopLevelElement.Name.ToString,
.Fields = oFields
}
oRowSortKey += 1
oDocumentRows.Add(oRow)
Next
' Update the document
pDocument.TemplateName = oTemplateName
pDocument.TemplateType = oTemplateType
pDocument.Option = oOption
pDocument.PrintVoucher = oPrintVoucher
pDocument.Rows = oDocumentRows
Return pDocument
End Function
Private Async Function MatchDataFromWinLine(pDocument As Document, pMandators As List(Of Mandator), pMandator As Mandator, pTemplate As Template) As Task(Of Document)
Dim oMandators As List(Of Mandator) = pMandators.
Where(Function(m) m.IsWhitelisted = True).
OrderBy(Function(m) m.Order).
ToList()
Dim oMandator As Mandator = Nothing
If pMandator IsNot Nothing Then
oMandator = pMandator
Else
oMandator = Winline.FindMatchingMandatorFromOrder(pDocument)
End If
If oMandator Is Nothing Then
Logger.Warn("Mandator not found for File [{0}]", pDocument.File.Name)
Else
' Set mandator befor applying any functions that depend on a valid mandator
pDocument.Mandator = oMandator
pDocument = ApplyDefinedItemFunctionsForImport(pDocument, oMandator, pTemplate)
pDocument = ApplyDynamicItemFunctionsForImport(pDocument, oMandator)
' These functions will only be applied if the document does not have errors
pDocument = Await MaybeApplyPriceFunctions(pDocument, oMandator, pTemplate)
' This function needs to be the last one because
' it can relate to any previously set value
ApplyFieldFunctionForImport(pDocument, oMandator, pTemplate)
End If
Return pDocument
End Function
''' <summary>
''' Apply price calculation to the documents products
'''
''' This needs to be strictly seperated from `ApplyDefinedItemFunctionsForImport`
''' because prices can only be calculated if GLN and EAN functions were already (successfully) processed
''' </summary>
Public Async Function MaybeApplyPriceFunctions(pDocument As Document, pMandator As Mandator, pTemplate As Template) As Task(Of Document)
If pDocument.HasErrors Then
Return pDocument
End If
For Each oRow As DocumentRow In pDocument.Rows
Dim oTable = pTemplate.Tables.Where(Function(table) table.Name = oRow.TableName).SingleOrDefault()
For Each oField In oRow.Fields
If oTable Is Nothing Then
Exit For
End If
Dim oColumn = oTable.Columns.Where(Function(c) c.Name = oField.Key).SingleOrDefault()
If oColumn Is Nothing Then
Continue For
End If
Dim oFunctionName = oColumn.Config.FunctionName
Dim oFunctionParams = oColumn.Config.FunctionParams
Dim oParamsDict = ParseFunctionParamsAsDict(oFunctionParams)
If oFunctionName = Constants.FUNCTION_PRICE Then
Await SetPrice(oRow, oField.Key, oParamsDict, pDocument, pMandator, pTemplate)
End If
Next
Next
Return pDocument
End Function
Private Function ApplyDefinedItemFunctionsForImport(pDocument As Document, pMandator As Mandator, pTemplate As Template) As Document
For Each oRow As DocumentRow In pDocument.Rows
Dim oTable = pTemplate.Tables.Where(Function(table) table.Name = oRow.TableName).SingleOrDefault()
For Each oField In oRow.Fields
If oTable Is Nothing Then
Exit For
End If
Dim oColumn = oTable.Columns.Where(Function(c) c.Name = oField.Key).SingleOrDefault()
If oColumn Is Nothing Then
Continue For
End If
Dim oFunctionName = oColumn.Config.FunctionName
Dim oFunctionParams = oColumn.Config.FunctionParams
Dim oParamsDict = ParseFunctionParamsAsDict(oFunctionParams)
If oFunctionName = Constants.FUNCTION_GLN Then
SetAccountByGLN(oRow, pMandator, oField.Key, Nothing, oParamsDict)
End If
If oFunctionName = Constants.FUNCTION_EAN Then
SetArticleByEAN(oRow, pMandator, oField.Key)
End If
Next
Next
Return pDocument
End Function
Private Function ApplyFieldFunctionForImport(pDocument As Document, pMandator As Mandator, pTemplate As Template) As Document
For Each oRow As DocumentRow In pDocument.Rows
Dim oTable = pDocument.Schema.Tables.Where(Function(table) table.Name = oRow.TableName).SingleOrDefault()
For Each oField In oRow.Fields
If oTable Is Nothing Then
Logger.Warn("Table [{0}] was not found in the Schema. Exiting.", oRow.TableName)
Exit For
End If
Dim oColumn = oTable.Columns.Where(Function(c) c.Name = oField.Key).SingleOrDefault()
If oColumn Is Nothing Then
Logger.Warn("Column [{0}] was not found in Table [{0}]. Skipping.", oField.Key, oTable.Name)
Continue For
End If
Dim oFunctionName = oColumn.Config.FunctionName
Dim oFunctionParams = oColumn.Config.FunctionParams
Dim oParamsDict = ParseFunctionParamsAsDict(oFunctionParams)
If oFunctionName = Constants.FUNCTION_FIELD Then
Try
Logger.Debug("Applying function FIELD to field [{0}]", oField.Key)
Dim oParam = oParamsDict.FirstOrDefault()
If IsNothing(oParam) Then
Logger.Warn("Function FIELD needs exactly one parameter. Skipping")
Continue For
End If
Dim oFieldName = oParam.Key
Dim oSubKey = oParam.Value
Dim oReferencedField = oRow.Fields.
Where(Function(field) field.Key = oFieldName).
FirstOrDefault()
If IsNothing(oReferencedField) = False Then
Dim oRawValue = oReferencedField.Value?.GetValue(oSubKey)
Dim oValue As String = Utils.NotNull(oRawValue, String.Empty)
If oValue <> String.Empty Then
oField.Value.Final = oValue
End If
Else
Logger.Warn("Referenced Field [{0}] was not found. Skipping.", oFieldName)
Continue For
End If
Catch ex As Exception
Logger.Warn("Function FIELD could not be applied to field [{0}]. Skipping.", oField.Key)
Continue For
End Try
End If
Next
Next
Return pDocument
End Function
''' <summary>
''' Execute Mappings defined in TBMT_MAPPING_CONFIG,
''' for example mapping Article Numbers to Winline Mandators
''' </summary>
Private Function ApplyDynamicItemFunctionsForImport(pDocument As Document, pMandator As Mandator) As Document
' We only want the mapping config for things in the xml file.
' that excludes things like setting the mandator.
Dim oFilteredMappingConfig = MappingConfig.Items.
Where(Function(item) item.DestinationItem <> String.Empty).
ToList()
For Each oMapping As MappingConfigItem In oFilteredMappingConfig
' Get Source Value
Dim oField As KeyValuePair(Of String, DocumentRow.FieldValue) = pDocument.Rows.
SelectMany(Function(row) row.Fields).
Where(Function(field) field.Key = oMapping.SourceItem).
FirstOrDefault()
' Test on Regex
Dim oRegex As New Regex(oMapping.SourceRegex)
If oRegex.IsMatch(oField.Value.Final) Then
pDocument.Rows.
SelectMany(Function(row) row.Fields).
Where(Function(field) field.Key = oMapping.DestinationItem).
SetValue(Sub(field)
field.Value.Final = oMapping.DestinationValue
End Sub)
Else
' don't do anything
End If
Next
Return pDocument
End Function
Private Async Function SetPrice(pRow As DocumentRow, pPriceField As String, oFieldMap As Dictionary(Of String, String), pDocument As Document, pMandator As Mandator, pTemplate As Template) As Task
Dim oPriceItem As DocumentRow.FieldValue = pRow.Fields.GetOrDefault(pPriceField)
' These fields are fetched from the current row
Dim oArticleNumberField As String = oFieldMap.GetOrDefault("Article", Nothing)
Dim oArticleNumber As String = pRow.Fields.Item(oArticleNumberField).Final
Dim oQuantityField As String = oFieldMap.GetOrDefault("Quantity", Nothing)
Dim oQuantity As Integer = 1
If Integer.TryParse(pRow.Fields.Item(oQuantityField).Final, oQuantity) = False Then
Logger.Warn("Value for parameter Quantity could not be parsed. Setting to 1.")
End If
' These fields a fetched from the head row, ie. the first row
Dim oAccountNumberField As String = oFieldMap.GetOrDefault("Account", Nothing)
Dim oAccountNumber = pDocument.GetFieldValue(oAccountNumberField)
Dim oDocumentDateField As String = oFieldMap.GetOrDefault("DocumentDate", Nothing)
Dim oDocumentDate = pDocument.GetFieldValue(oDocumentDateField)
Dim oDocumentKindField As String = oFieldMap.GetOrDefault("DocumentKind", Nothing)
Dim oDocumentKind As Integer = 0
If Integer.TryParse(pDocument.GetFieldValue(oDocumentKindField), oDocumentKind) Then
Logger.Warn("Value for parameter DocumentKind could not be parsed. Setting to 0.")
End If
' TODO: Add Field Names as Constants
' TODO: Check for missing values
' TODO: This function should not be hardcoded, but be replaced with virtual field or something..
' It is related to customer SCHAUM and nothing general
Dim oWaitingDays As Integer = Await Winline.TryGetWaitingDays(oDocumentKind, pMandator)
' END TODO
Dim oArticlePrice As Double = Await Winline.TryGetArticlePrice(oArticleNumber, oAccountNumber, oQuantity, oDocumentDate, pMandator, pTemplate, oWaitingDays)
If oArticlePrice > 0 Then
oPriceItem.External = oArticlePrice
oPriceItem.Final = oArticlePrice
Logger.Info("Price for Item [{0}] set to [{1}]", pPriceField, oArticlePrice)
Else
Logger.Warn("Price for Item [{0}] could not be found!", pPriceField)
End If
End Function
Private Sub SetArticleByEAN(pRow As DocumentRow, pMandator As Mandator, pArticleField As String)
Dim oNumberItem As DocumentRow.FieldValue = pRow.Fields.GetOrDefault(pArticleField)
Dim oArticleNumber = Winline.TryGetArticleNumber(oNumberItem.Original, pMandator)
If oArticleNumber IsNot Nothing Then
oNumberItem.External = oArticleNumber
oNumberItem.Final = oArticleNumber
Else
oNumberItem.Error = DocumentRow.FieldError.ArticleNotFound
End If
End Sub
Private Sub SetAccountByGLN(oRow As DocumentRow, pMandator As Mandator, pNumberField As String, pNameField As String, pParams As Dictionary(Of String, String))
' Try to read the Account number (which is a GLN really) and account Name
Dim oNumberItem As DocumentRow.FieldValue = oRow.Fields.GetOrDefault(pNumberField)
Dim oNameItem As DocumentRow.FieldValue = oRow.Fields.GetOrDefault(pNameField)
Dim oContainsAccountName As Boolean = Not IsNothing(oNameItem)
If oNumberItem Is Nothing Then
Exit Sub
End If
' Try to find an account that matches the GLN
Dim oAlternateField = pParams.GetOrDefault("AltField", String.Empty)
Dim oAccount = Winline.TryGetAccount(oNumberItem.Original, pMandator, "c260", oAlternateField)
' If an account was found, set it for External and Final value
If oAccount IsNot Nothing Then
oNumberItem.External = oAccount.Id
oNumberItem.Final = oAccount.Id
If oContainsAccountName Then
oNameItem.External = oAccount.Name
oNameItem.Final = oAccount.Name
Else
' TODO: What to to if name field is missing or not set?
'oRow.Fields.Add(pNameField, New DocumentRow.FieldValue() With {
' .External = oAccount.Name,
' .Final = oAccount.Name
'})
End If
Else
oNumberItem.Error = DocumentRow.FieldError.AccountNotFound
End If
End Sub
Private Function WrapFileInfo(pFileInfo As FileInfo) As Document
Return New Document With {.File = pFileInfo}
End Function
Private Function ParseFunctionParamsAsDict(pParams As String) As Dictionary(Of String, String)
Dim oParamsDict As New Dictionary(Of String, String)
If pParams <> String.Empty Then
Dim oParamList = pParams.Split("|").ToList()
For Each oParam In oParamList
Dim oParamSplit = oParam.Split("=")
oParamsDict.Add(oParamSplit(0), oParamSplit(1))
Next
End If
Return oParamsDict
End Function
End Class
End Namespace

View File

@@ -0,0 +1,93 @@
Namespace Documents
Public Class DocumentRow
Implements IComparable
''' <summary>
''' GUID to match DocumentRow with Row from Grid/DataTable
''' </summary>
Public Property Id As New Guid
''' <summary>
''' Counter to ensure consistency and order when writing XML
''' </summary>
Public Property SortKey As Integer
''' <summary>
''' Tabellen/Elementname aus XML
''' </summary>
Public Property TableName As String
''' <summary>
''' List of Row Values
''' </summary>
''' <returns></returns>
Public Property Fields As Dictionary(Of String, FieldValue)
Public ReadOnly Property HasErrors As Boolean
Get
If Errors.Count > 0 Then
Return True
Else
Return False
End If
End Get
End Property
Public ReadOnly Property Errors As List(Of String)
Get
Return Fields.
Where(Function(f) f.Value.HasError).
Select(Function(f) f.Key).ToList()
End Get
End Property
Public Sub New()
Id = Guid.NewGuid()
End Sub
Public Function CompareTo(other As Object) As Integer Implements IComparable.CompareTo
Return SortKey.CompareTo(DirectCast(other, DocumentRow).SortKey)
End Function
Public Enum FieldError
None
MissingValue
AccountNotFound
ArticleNotFound
End Enum
Public Class FieldValue
Public Property DataType As Constants.ColumnType = Constants.ColumnType.String
Public Property [Error] As FieldError = FieldError.None
Public Property Original As String = ""
Public Property External As String = ""
Public Property Final As String = ""
Public Property IsRequired As Boolean = False
Public Property IsVirtual As Boolean = False
Public Property SortKey As Integer = 0
Public Function GetValue(pValueType) As String
Select Case pValueType
Case "Original"
Return Original
Case "External"
Return External
Case "Final"
Return Final
Case Else
Return Nothing
End Select
End Function
Public ReadOnly Property HasError As Boolean
Get
Return [Error] <> FieldError.None Or (IsRequired And Final = String.Empty)
End Get
End Property
Public Overrides Function ToString() As String
Return Final
End Function
End Class
End Class
End Namespace

View File

@@ -0,0 +1,8 @@
Namespace Documents
Public Enum DocumentType
Order ' Auftrag
OrderResponse ' Bestellbestätigung
DispatchNotification ' Lieferavis/ Eingangs Lieferschein
Invoice ' Rechnung
End Enum
End Namespace

View File

@@ -0,0 +1,76 @@
Public Class Exceptions
''' <summary>
''' Abstract class
''' </summary>
Public MustInherit Class MultiToolException
Inherits ApplicationException
Public Sub New(message As String)
MyBase.New(message)
End Sub
End Class
''' -----------------------------------------------
Public Class DocumentLoaderException
Inherits MultiToolException
Public Sub New(message As String)
MyBase.New(message)
End Sub
End Class
Public Class DatabaseException
Inherits MultiToolException
Public Sub New(message As String)
MyBase.New(message)
End Sub
End Class
Public Class WebServiceException
Inherits MultiToolException
Public Sub New(message As String)
MyBase.New(message)
End Sub
End Class
Public Class MissingAttributeException
Inherits MultiToolException
Public Sub New(attributeName As String)
MyBase.New(attributeName)
End Sub
End Class
Public Class MultipleAccountsException
Inherits MultiToolException
Public Sub New(message As String)
MyBase.New(message)
End Sub
End Class
Public Class NoAccountException
Inherits MultiToolException
Public Sub New(message As String)
MyBase.New(message)
End Sub
End Class
Public Class NoMandatorException
Inherits MultiToolException
Public Sub New(message As String)
MyBase.New(message)
End Sub
End Class
Public Class MalformedXmlException
Inherits MultiToolException
Public Sub New(message As String)
MyBase.New(message)
End Sub
End Class
End Class

View File

@@ -0,0 +1,22 @@
Imports System.Runtime.CompilerServices
Module IDictionaryEx
<Extension()>
Function GetOrDefault(Of TKey, TValue)(pDictionary As Dictionary(Of TKey, TValue), pKey As TKey, Optional pOnMissing As TValue = Nothing) As TValue
Dim oValue As TValue
If pKey Is Nothing Then
Return Nothing
End If
Return IIf(pDictionary.TryGetValue(pKey, oValue), oValue, pOnMissing)
End Function
<Extension()>
Function GetOrInsertNew(Of T, U As New)(dic As Dictionary(Of T, U), key As T) As U
If dic.ContainsKey(key) Then Return dic(key)
Dim newObj As U = New U()
dic(key) = newObj
Return newObj
End Function
End Module

View File

@@ -0,0 +1,12 @@
Imports System.Runtime.CompilerServices
Module IEnumerableEx
<Extension()>
Function SetValue(Of T)(items As IEnumerable(Of T), updateMethod As Action(Of T)) As IEnumerable(Of T)
For Each item As T In items
updateMethod(item)
Next
Return items
End Function
End Module

View File

@@ -0,0 +1,146 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{DD1AC3B9-7595-4D3C-B9BB-97C46A480FA0}</ProjectGuid>
<OutputType>Library</OutputType>
<RootNamespace>ImporterShared</RootNamespace>
<AssemblyName>ImporterShared</AssemblyName>
<FileAlignment>512</FileAlignment>
<MyType>Windows</MyType>
<TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
<Deterministic>true</Deterministic>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<DefineDebug>true</DefineDebug>
<DefineTrace>true</DefineTrace>
<OutputPath>bin\Debug\</OutputPath>
<DocumentationFile>ImporterShared.xml</DocumentationFile>
<NoWarn>42016,41999,42017,42018,42019,42032,42036,42020,42021,42022</NoWarn>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<DefineDebug>false</DefineDebug>
<DefineTrace>true</DefineTrace>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DocumentationFile>ImporterShared.xml</DocumentationFile>
<NoWarn>42016,41999,42017,42018,42019,42032,42036,42020,42021,42022</NoWarn>
</PropertyGroup>
<PropertyGroup>
<OptionExplicit>On</OptionExplicit>
</PropertyGroup>
<PropertyGroup>
<OptionCompare>Binary</OptionCompare>
</PropertyGroup>
<PropertyGroup>
<OptionStrict>Off</OptionStrict>
</PropertyGroup>
<PropertyGroup>
<OptionInfer>On</OptionInfer>
</PropertyGroup>
<ItemGroup>
<Reference Include="AutoMapper, Version=10.0.0.0, Culture=neutral, PublicKeyToken=be96cd2c38ef1005, processorArchitecture=MSIL">
<HintPath>..\packages\AutoMapper.10.1.1\lib\net461\AutoMapper.dll</HintPath>
</Reference>
<Reference Include="DevExpress.DataAccess.v19.2, Version=19.2.3.0, Culture=neutral, PublicKeyToken=b88d1754d700e49a, processorArchitecture=MSIL" />
<Reference Include="DigitalData.Modules.Database">
<HintPath>..\..\DDMonorepo\Modules.Database\bin\Debug\DigitalData.Modules.Database.dll</HintPath>
</Reference>
<Reference Include="DigitalData.Modules.Filesystem">
<HintPath>..\..\DDMonorepo\Modules.Filesystem\bin\Debug\DigitalData.Modules.Filesystem.dll</HintPath>
</Reference>
<Reference Include="DigitalData.Modules.Language">
<HintPath>..\..\DDMonorepo\Modules.Language\bin\Release\DigitalData.Modules.Language.dll</HintPath>
</Reference>
<Reference Include="DigitalData.Modules.Logging">
<HintPath>..\..\DDMonorepo\Modules.Logging\bin\Release\DigitalData.Modules.Logging.dll</HintPath>
</Reference>
<Reference Include="Microsoft.CSharp" />
<Reference Include="NLog, Version=4.0.0.0, Culture=neutral, PublicKeyToken=5120e14c03d0593c, processorArchitecture=MSIL">
<HintPath>..\packages\NLog.4.7.10\lib\net45\NLog.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Configuration" />
<Reference Include="System.Data" />
<Reference Include="System.IO.Compression" />
<Reference Include="System.Runtime.Serialization" />
<Reference Include="System.ServiceModel" />
<Reference Include="System.Transactions" />
<Reference Include="System.Xml" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="System.Net.Http" />
</ItemGroup>
<ItemGroup>
<Import Include="Microsoft.VisualBasic" />
<Import Include="System" />
<Import Include="System.Collections" />
<Import Include="System.Collections.Generic" />
<Import Include="System.Data" />
<Import Include="System.Diagnostics" />
<Import Include="System.Linq" />
<Import Include="System.Xml.Linq" />
<Import Include="System.Threading.Tasks" />
</ItemGroup>
<ItemGroup>
<Compile Include="BaseClass.vb" />
<Compile Include="Config.vb" />
<Compile Include="Documents\Document.vb" />
<Compile Include="Documents\DocumentMatch.vb" />
<Compile Include="Documents\DocumentType.vb" />
<Compile Include="Documents\DocumentLoader.vb" />
<Compile Include="IEnumerableEx.vb" />
<Compile Include="My Project\AssemblyInfo.vb" />
<Compile Include="My Project\Application.Designer.vb">
<AutoGen>True</AutoGen>
<DependentUpon>Application.myapp</DependentUpon>
</Compile>
<Compile Include="My Project\Resources.Designer.vb">
<AutoGen>True</AutoGen>
<DesignTime>True</DesignTime>
<DependentUpon>Resources.resx</DependentUpon>
</Compile>
<Compile Include="My Project\Settings.Designer.vb">
<AutoGen>True</AutoGen>
<DependentUpon>Settings.settings</DependentUpon>
<DesignTimeSharedInput>True</DesignTimeSharedInput>
</Compile>
<Compile Include="Mapper.vb" />
<Compile Include="Schemas\Orders\Input.vb" />
<Compile Include="Schemas\Orders\Output.vb" />
<Compile Include="Schemas\Orders\ReportSource.vb" />
<Compile Include="Serializer.vb" />
<Compile Include="Winline\Account.vb" />
<Compile Include="Winline\Data.vb" />
<Compile Include="Winline\Mandator.vb" />
<Compile Include="Winline\WebService.vb" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="My Project\Resources.resx">
<Generator>VbMyResourcesResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.Designer.vb</LastGenOutput>
<CustomToolNamespace>My.Resources</CustomToolNamespace>
<SubType>Designer</SubType>
</EmbeddedResource>
</ItemGroup>
<ItemGroup>
<None Include="My Project\Application.myapp">
<Generator>MyApplicationCodeGenerator</Generator>
<LastGenOutput>Application.Designer.vb</LastGenOutput>
</None>
<None Include="My Project\Settings.settings">
<Generator>SettingsSingleFileGenerator</Generator>
<CustomToolNamespace>My</CustomToolNamespace>
<LastGenOutput>Settings.Designer.vb</LastGenOutput>
</None>
<None Include="packages.config" />
</ItemGroup>
<ItemGroup />
<Import Project="$(MSBuildToolsPath)\Microsoft.VisualBasic.targets" />
</Project>

127
MultiTool.Common/Mapper.vb Normal file
View File

@@ -0,0 +1,127 @@
Imports System.Globalization
Imports System.Text.RegularExpressions
Imports AutoMapper
Imports AutoMapper.Configuration
Imports DigitalData.Modules.Logging
Imports MultiTool.Common.Documents.DocumentRow
Public Class Mapper
Private MapperConfig As MapperConfiguration
Private ReadOnly LogConfig As LogConfig
Private ReadOnly Logger As Logger
Public Sub New(pLogConfig As LogConfig)
LogConfig = pLogConfig
Logger = pLogConfig.GetLogger
End Sub
Public Function GetMapper(Of T)(pPropertyMap As Dictionary(Of String, String)) As IMapper
MapperConfig = New MapperConfiguration(CreateMapperConfig(Of T)(pPropertyMap))
MapperConfig.AssertConfigurationIsValid()
Return MapperConfig.CreateMapper()
End Function
Private Function CreateMapperConfig(Of T)(pPropertyMap As Dictionary(Of String, String)) As MapperConfigurationExpression
Logger.Info("Creating mapper config for type [{0}]", GetType(T).Name)
Dim oConfig As New MapperConfigurationExpression()
oConfig.AddProfile(New MappingProfile(Of T)(LogConfig, pPropertyMap))
Return oConfig
End Function
Public Class MappingProfile(Of T)
Inherits Profile
Private ReadOnly LogConfig As LogConfig
Public Overrides ReadOnly Property ProfileName As String
Get
Return "MappingProfile"
End Get
End Property
Public Sub New(pLogConfig As LogConfig, pPropertyMap As Dictionary(Of String, String))
LogConfig = pLogConfig
CreateMap(Of Dictionary(Of String, FieldValue), T).ConvertUsing(New ReportTypeConverter(Of T)(LogConfig, pPropertyMap))
End Sub
End Class
Private Class ReportTypeConverter(Of TDestination)
Implements ITypeConverter(Of Dictionary(Of String, FieldValue), TDestination)
Private ReadOnly PropertyMap As Dictionary(Of String, String)
Private ReadOnly KeyWithSubkey As New Regex("(?<Key>[\w\s-]+)(?:\[(?<Subkey>[\w]+)\])?")
Private ReadOnly Logger As Logger
Public Sub New(pLogConfig As LogConfig, pPropertyMap As Dictionary(Of String, String))
MyBase.New()
Logger = pLogConfig.GetLogger()
PropertyMap = pPropertyMap
End Sub
Public Function Convert(pSource As Dictionary(Of String, FieldValue), pDestination As TDestination, pContext As ResolutionContext) As TDestination Implements ITypeConverter(Of Dictionary(Of String, FieldValue), TDestination).Convert
If pSource Is Nothing Then
Return Nothing
End If
Dim oResult = Activator.CreateInstance(Of TDestination)
Logger.Info("Mapping object of Type [{0}]", GetType(TDestination).Name)
For Each oMapItem As KeyValuePair(Of String, String) In PropertyMap
Try
' SourceKey will be something like 'Fakt_Kontonummer[Final]'
' DestinationKey will be something like 'Text1'
Dim oSourceKeyCombined As String = oMapItem.Key
Dim oDestinationKey As String = oMapItem.Value
' Resolve SourceKey into Key and Subkey
Dim oMatch As Match = KeyWithSubkey.Match(oSourceKeyCombined)
Dim oSourceKey As String = oMatch.Groups("Key")?.Value
Dim oSourceSubkey As String = oMatch.Groups("Subkey")?.Value
' Set property value if property exists in source
If pSource.ContainsKey(oSourceKey) Then
' Try to get the value from 'source'
Dim oFieldValue As FieldValue = pSource.Item(oSourceKey)
' Get the destination property by DestinationKey
Dim oProperty = GetType(TDestination).
GetProperties().
SingleOrDefault(Function(p) p.Name = oDestinationKey)
' Set the property if it exists
If oProperty IsNot Nothing Then
Dim oValue = GetFieldValue(oFieldValue, oSourceSubkey)
Logger.Info("Transferring value [{0}] from [{1}] -> [{2}]", oValue, oSourceKeyCombined, oDestinationKey)
oProperty.SetValue(oResult, oValue)
Else
Logger.Warn("Property [{0}] does not exist in destination object. Possible error in configuration.", oDestinationKey)
End If
End If
Catch ex As Exception
Logger.Warn("Could not transfer key [{0}] to destination object", oMapItem.Key)
Logger.Error(ex)
End Try
Next
Return oResult
End Function
Private Function GetFieldValue(pValue As FieldValue, pKey As String) As String
If pKey = "Original" Then
Return pValue.Original
ElseIf pKey = "External" Then
Return pValue.External
Else
Return pValue.Final
End If
End Function
End Class
End Class

View File

@@ -0,0 +1,180 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{DD1AC3B9-7595-4D3C-B9BB-97C46A480FA0}</ProjectGuid>
<OutputType>Library</OutputType>
<RootNamespace>MultiTool.Common</RootNamespace>
<AssemblyName>MultiTool.Common</AssemblyName>
<FileAlignment>512</FileAlignment>
<MyType>Windows</MyType>
<TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
<Deterministic>true</Deterministic>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<DefineDebug>true</DefineDebug>
<DefineTrace>true</DefineTrace>
<OutputPath>bin\Debug\</OutputPath>
<DocumentationFile>MultiTool.Common.xml</DocumentationFile>
<NoWarn>42016,41999,42017,42018,42019,42032,42036,42020,42021,42022</NoWarn>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<DefineDebug>false</DefineDebug>
<DefineTrace>true</DefineTrace>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DocumentationFile>MultiTool.Common.xml</DocumentationFile>
<NoWarn>42016,41999,42017,42018,42019,42032,42036,42020,42021,42022</NoWarn>
</PropertyGroup>
<PropertyGroup>
<OptionExplicit>On</OptionExplicit>
</PropertyGroup>
<PropertyGroup>
<OptionCompare>Binary</OptionCompare>
</PropertyGroup>
<PropertyGroup>
<OptionStrict>Off</OptionStrict>
</PropertyGroup>
<PropertyGroup>
<OptionInfer>On</OptionInfer>
</PropertyGroup>
<ItemGroup>
<Reference Include="AutoMapper, Version=10.0.0.0, Culture=neutral, PublicKeyToken=be96cd2c38ef1005, processorArchitecture=MSIL">
<HintPath>..\packages\AutoMapper.10.1.1\lib\net461\AutoMapper.dll</HintPath>
</Reference>
<Reference Include="DevExpress.Data.v21.2, Version=21.2.4.0, Culture=neutral, PublicKeyToken=b88d1754d700e49a" />
<Reference Include="DevExpress.DataAccess.v21.2, Version=21.2.4.0, Culture=neutral, PublicKeyToken=b88d1754d700e49a, processorArchitecture=MSIL" />
<Reference Include="DevExpress.Printing.v21.2.Core, Version=21.2.4.0, Culture=neutral, PublicKeyToken=b88d1754d700e49a, processorArchitecture=MSIL" />
<Reference Include="DigitalData.Modules.Base">
<HintPath>..\..\DDMonorepo\Modules.Base\Base\bin\Debug\DigitalData.Modules.Base.dll</HintPath>
</Reference>
<Reference Include="DigitalData.Modules.Config">
<HintPath>..\..\DDMonorepo\Modules.Config\bin\Debug\DigitalData.Modules.Config.dll</HintPath>
</Reference>
<Reference Include="DigitalData.Modules.Database">
<HintPath>..\..\DDMonorepo\Modules.Database\bin\Debug\DigitalData.Modules.Database.dll</HintPath>
</Reference>
<Reference Include="DigitalData.Modules.Filesystem">
<HintPath>..\..\DDMonorepo\Modules.Filesystem\bin\Debug\DigitalData.Modules.Filesystem.dll</HintPath>
</Reference>
<Reference Include="DigitalData.Modules.Interfaces">
<HintPath>..\..\DDMonorepo\Modules.Interfaces\bin\Debug\DigitalData.Modules.Interfaces.dll</HintPath>
</Reference>
<Reference Include="DigitalData.Modules.Language, Version=1.0.1.0, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\DDMonorepo\Modules.Language\bin\Debug\DigitalData.Modules.Language.dll</HintPath>
</Reference>
<Reference Include="DigitalData.Modules.Logging">
<HintPath>..\..\DDMonorepo\Modules.Logging\bin\Release\DigitalData.Modules.Logging.dll</HintPath>
</Reference>
<Reference Include="Microsoft.CSharp" />
<Reference Include="NLog, Version=4.0.0.0, Culture=neutral, PublicKeyToken=5120e14c03d0593c, processorArchitecture=MSIL">
<HintPath>..\packages\NLog.4.7.10\lib\net45\NLog.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Configuration" />
<Reference Include="System.Data" />
<Reference Include="System.IO.Compression" />
<Reference Include="System.Runtime.Serialization" />
<Reference Include="System.ServiceModel" />
<Reference Include="System.Transactions" />
<Reference Include="System.Xml" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="System.Net.Http" />
</ItemGroup>
<ItemGroup>
<Import Include="Microsoft.VisualBasic" />
<Import Include="System" />
<Import Include="System.Collections" />
<Import Include="System.Collections.Generic" />
<Import Include="System.Data" />
<Import Include="System.Diagnostics" />
<Import Include="System.Linq" />
<Import Include="System.Xml.Linq" />
<Import Include="System.Threading.Tasks" />
</ItemGroup>
<ItemGroup>
<Compile Include="BaseClass.vb" />
<Compile Include="Config.vb" />
<Compile Include="Constants.vb" />
<Compile Include="Documents\Document.vb" />
<Compile Include="Documents\DocumentCleaner.vb" />
<Compile Include="Documents\DocumentRow.vb" />
<Compile Include="Documents\DocumentType.vb" />
<Compile Include="Documents\DocumentLoader.vb" />
<Compile Include="Exceptions.vb" />
<Compile Include="IDictionaryEx.vb" />
<Compile Include="IEnumerableEx.vb" />
<Compile Include="Mapper.vb" />
<Compile Include="My Project\AssemblyInfo.vb" />
<Compile Include="My Project\Application.Designer.vb">
<AutoGen>True</AutoGen>
<DependentUpon>Application.myapp</DependentUpon>
<DesignTime>True</DesignTime>
</Compile>
<Compile Include="My Project\Resources.Designer.vb">
<AutoGen>True</AutoGen>
<DesignTime>True</DesignTime>
<DependentUpon>Resources.resx</DependentUpon>
</Compile>
<Compile Include="My Project\Settings.Designer.vb">
<AutoGen>True</AutoGen>
<DependentUpon>Settings.settings</DependentUpon>
<DesignTimeSharedInput>True</DesignTimeSharedInput>
</Compile>
<Compile Include="Patterns.vb" />
<Compile Include="Report\ReportGenerator.vb" />
<Compile Include="Templates\GeneralConfig.vb" />
<Compile Include="Templates\MandatorConfig.vb" />
<Compile Include="Templates\MandatorConfigItem.vb" />
<Compile Include="Templates\MappingConfig.vb" />
<Compile Include="Templates\MappingConfigItem.vb" />
<Compile Include="Report\ReportHead.vb" />
<Compile Include="Report\ReportPosition.vb" />
<Compile Include="Report\ReportSource.vb" />
<Compile Include="Winline\Entities\ExportDocument.vb" />
<Compile Include="Winline\Entities\Response.vb" />
<Compile Include="Templates\Template.vb" />
<Compile Include="Templates\TemplateLoader.vb" />
<Compile Include="Serializer.vb" />
<Compile Include="Templates\TemplateConfig.vb" />
<Compile Include="Winline\Entities\Account.vb" />
<Compile Include="Winline\WinlineData.vb" />
<Compile Include="Winline\Entities\Article.vb" />
<Compile Include="Winline\Entities\Contact.vb" />
<Compile Include="Winline\Entities\DocumentKind.vb" />
<Compile Include="Winline\Entities\Mandator.vb" />
<Compile Include="Templates\TemplateConfigItem.vb" />
<Compile Include="Winline\WebServiceData.vb" />
<Compile Include="XmlData.vb" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="My Project\Resources.resx">
<Generator>VbMyResourcesResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.Designer.vb</LastGenOutput>
<CustomToolNamespace>My.Resources</CustomToolNamespace>
<SubType>Designer</SubType>
</EmbeddedResource>
</ItemGroup>
<ItemGroup>
<None Include="My Project\Application.myapp">
<Generator>MyApplicationCodeGenerator</Generator>
<LastGenOutput>Application.Designer.vb</LastGenOutput>
</None>
<None Include="My Project\Settings.settings">
<Generator>SettingsSingleFileGenerator</Generator>
<CustomToolNamespace>My</CustomToolNamespace>
<LastGenOutput>Settings.Designer.vb</LastGenOutput>
</None>
<None Include="packages.config" />
</ItemGroup>
<ItemGroup />
<Import Project="$(MSBuildToolsPath)\Microsoft.VisualBasic.targets" />
</Project>

View File

@@ -0,0 +1,175 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{DD1AC3B9-7595-4D3C-B9BB-97C46A480FA0}</ProjectGuid>
<OutputType>Library</OutputType>
<RootNamespace>MultiTool.Shared</RootNamespace>
<AssemblyName>MultiTool.Shared</AssemblyName>
<FileAlignment>512</FileAlignment>
<MyType>Windows</MyType>
<TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
<Deterministic>true</Deterministic>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<DefineDebug>true</DefineDebug>
<DefineTrace>true</DefineTrace>
<OutputPath>bin\Debug\</OutputPath>
<DocumentationFile>MultiTool.Shared.xml</DocumentationFile>
<NoWarn>42016,41999,42017,42018,42019,42032,42036,42020,42021,42022</NoWarn>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<DefineDebug>false</DefineDebug>
<DefineTrace>true</DefineTrace>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DocumentationFile>MultiTool.Shared.xml</DocumentationFile>
<NoWarn>42016,41999,42017,42018,42019,42032,42036,42020,42021,42022</NoWarn>
</PropertyGroup>
<PropertyGroup>
<OptionExplicit>On</OptionExplicit>
</PropertyGroup>
<PropertyGroup>
<OptionCompare>Binary</OptionCompare>
</PropertyGroup>
<PropertyGroup>
<OptionStrict>Off</OptionStrict>
</PropertyGroup>
<PropertyGroup>
<OptionInfer>On</OptionInfer>
</PropertyGroup>
<ItemGroup>
<Reference Include="AutoMapper, Version=10.0.0.0, Culture=neutral, PublicKeyToken=be96cd2c38ef1005, processorArchitecture=MSIL">
<HintPath>..\packages\AutoMapper.10.1.1\lib\net461\AutoMapper.dll</HintPath>
</Reference>
<Reference Include="DevExpress.Data.v19.2, Version=19.2.3.0, Culture=neutral, PublicKeyToken=b88d1754d700e49a" />
<Reference Include="DevExpress.DataAccess.v19.2, Version=19.2.3.0, Culture=neutral, PublicKeyToken=b88d1754d700e49a, processorArchitecture=MSIL" />
<Reference Include="DevExpress.Printing.v19.2.Core, Version=19.2.3.0, Culture=neutral, PublicKeyToken=b88d1754d700e49a, processorArchitecture=MSIL" />
<Reference Include="DigitalData.Modules.Config">
<HintPath>..\..\DDMonorepo\Modules.Config\bin\Debug\DigitalData.Modules.Config.dll</HintPath>
</Reference>
<Reference Include="DigitalData.Modules.Database">
<HintPath>..\..\DDMonorepo\Modules.Database\bin\Debug\DigitalData.Modules.Database.dll</HintPath>
</Reference>
<Reference Include="DigitalData.Modules.Filesystem">
<HintPath>..\..\DDMonorepo\Modules.Filesystem\bin\Debug\DigitalData.Modules.Filesystem.dll</HintPath>
</Reference>
<Reference Include="DigitalData.Modules.Interfaces">
<HintPath>..\..\DDMonorepo\Modules.Interfaces\bin\Debug\DigitalData.Modules.Interfaces.dll</HintPath>
</Reference>
<Reference Include="DigitalData.Modules.Language">
<HintPath>..\..\DDMonorepo\Modules.Language\bin\Release\DigitalData.Modules.Language.dll</HintPath>
</Reference>
<Reference Include="DigitalData.Modules.Logging">
<HintPath>..\..\DDMonorepo\Modules.Logging\bin\Release\DigitalData.Modules.Logging.dll</HintPath>
</Reference>
<Reference Include="Microsoft.CSharp" />
<Reference Include="NLog, Version=4.0.0.0, Culture=neutral, PublicKeyToken=5120e14c03d0593c, processorArchitecture=MSIL">
<HintPath>..\packages\NLog.4.7.10\lib\net45\NLog.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Configuration" />
<Reference Include="System.Data" />
<Reference Include="System.IO.Compression" />
<Reference Include="System.Runtime.Serialization" />
<Reference Include="System.ServiceModel" />
<Reference Include="System.Transactions" />
<Reference Include="System.Xml" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="System.Net.Http" />
</ItemGroup>
<ItemGroup>
<Import Include="Microsoft.VisualBasic" />
<Import Include="System" />
<Import Include="System.Collections" />
<Import Include="System.Collections.Generic" />
<Import Include="System.Data" />
<Import Include="System.Diagnostics" />
<Import Include="System.Linq" />
<Import Include="System.Xml.Linq" />
<Import Include="System.Threading.Tasks" />
</ItemGroup>
<ItemGroup>
<Compile Include="BaseClass.vb" />
<Compile Include="Config.vb" />
<Compile Include="Constants.vb" />
<Compile Include="DataRowEx.vb" />
<Compile Include="Documents\Document.vb" />
<Compile Include="Documents\DocumentRow.vb" />
<Compile Include="Documents\DocumentType.vb" />
<Compile Include="Documents\DocumentLoader.vb" />
<Compile Include="Exceptions.vb" />
<Compile Include="Helpers.vb" />
<Compile Include="IDictionaryEx.vb" />
<Compile Include="IEnumerableEx.vb" />
<Compile Include="Mapper.vb" />
<Compile Include="My Project\AssemblyInfo.vb" />
<Compile Include="My Project\Application.Designer.vb">
<AutoGen>True</AutoGen>
<DependentUpon>Application.myapp</DependentUpon>
<DesignTime>True</DesignTime>
</Compile>
<Compile Include="My Project\Resources.Designer.vb">
<AutoGen>True</AutoGen>
<DesignTime>True</DesignTime>
<DependentUpon>Resources.resx</DependentUpon>
</Compile>
<Compile Include="My Project\Settings.Designer.vb">
<AutoGen>True</AutoGen>
<DependentUpon>Settings.settings</DependentUpon>
<DesignTimeSharedInput>True</DesignTimeSharedInput>
</Compile>
<Compile Include="Report\ReportGenerator.vb" />
<Compile Include="Templates\GeneralConfig.vb" />
<Compile Include="Templates\MandatorConfig.vb" />
<Compile Include="Templates\MandatorConfigItem.vb" />
<Compile Include="Templates\MappingConfig.vb" />
<Compile Include="Templates\MappingConfigItem.vb" />
<Compile Include="Report\ReportHead.vb" />
<Compile Include="Report\ReportPosition.vb" />
<Compile Include="Report\ReportSource.vb" />
<Compile Include="Winline\Entities\Response.vb" />
<Compile Include="Templates\Template.vb" />
<Compile Include="Templates\TemplateLoader.vb" />
<Compile Include="Serializer.vb" />
<Compile Include="Templates\TemplateConfig.vb" />
<Compile Include="Winline\Entities\Account.vb" />
<Compile Include="Winline\WinlineData.vb" />
<Compile Include="Winline\Entities\Article.vb" />
<Compile Include="Winline\Entities\Contact.vb" />
<Compile Include="Winline\Entities\DocumentKind.vb" />
<Compile Include="Winline\Entities\Mandator.vb" />
<Compile Include="Templates\TemplateConfigItem.vb" />
<Compile Include="Winline\WebServiceData.vb" />
<Compile Include="XmlData.vb" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="My Project\Resources.resx">
<Generator>VbMyResourcesResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.Designer.vb</LastGenOutput>
<CustomToolNamespace>My.Resources</CustomToolNamespace>
<SubType>Designer</SubType>
</EmbeddedResource>
</ItemGroup>
<ItemGroup>
<None Include="My Project\Application.myapp">
<Generator>MyApplicationCodeGenerator</Generator>
<LastGenOutput>Application.Designer.vb</LastGenOutput>
</None>
<None Include="My Project\Settings.settings">
<Generator>SettingsSingleFileGenerator</Generator>
<CustomToolNamespace>My</CustomToolNamespace>
<LastGenOutput>Settings.Designer.vb</LastGenOutput>
</None>
<None Include="packages.config" />
</ItemGroup>
<ItemGroup />
<Import Project="$(MSBuildToolsPath)\Microsoft.VisualBasic.targets" />
</Project>

View File

@@ -0,0 +1,13 @@
'------------------------------------------------------------------------------
' <auto-generated>
' 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.
' </auto-generated>
'------------------------------------------------------------------------------
Option Strict On
Option Explicit On

View File

@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<MyApplicationData xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<MySubMain>false</MySubMain>
<SingleInstance>false</SingleInstance>
<ShutdownMode>0</ShutdownMode>
<EnableVisualStyles>true</EnableVisualStyles>
<AuthenticationMode>0</AuthenticationMode>
<ApplicationType>1</ApplicationType>
<SaveMySettingsOnExit>true</SaveMySettingsOnExit>
</MyApplicationData>

View File

@@ -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
<Assembly: AssemblyTitle("MultiTool.Common")>
<Assembly: AssemblyDescription("")>
<Assembly: AssemblyCompany("")>
<Assembly: AssemblyProduct("MultiTool.Common")>
<Assembly: AssemblyCopyright("Copyright © 2022")>
<Assembly: AssemblyTrademark("")>
<Assembly: ComVisible(False)>
'Die folgende GUID wird für die typelib-ID verwendet, wenn dieses Projekt für COM verfügbar gemacht wird.
<Assembly: Guid("c3902aa5-4b44-4ae2-8a57-b3c8e031d076")>
' 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:
' <Assembly: AssemblyVersion("1.0.*")>
<Assembly: AssemblyVersion("1.2.0.0")>
<Assembly: AssemblyFileVersion("1.0.0.0")>

View File

@@ -0,0 +1,63 @@
'------------------------------------------------------------------------------
' <auto-generated>
' 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.
' </auto-generated>
'------------------------------------------------------------------------------
Option Strict On
Option Explicit On
Imports System
Namespace My.Resources
'Diese Klasse wurde von der StronglyTypedResourceBuilder automatisch generiert
'-Klasse über ein Tool wie ResGen oder Visual Studio automatisch generiert.
'Um einen Member hinzuzufügen oder zu entfernen, bearbeiten Sie die .ResX-Datei und führen dann ResGen
'mit der /str-Option erneut aus, oder Sie erstellen Ihr VS-Projekt neu.
'''<summary>
''' Eine stark typisierte Ressourcenklasse zum Suchen von lokalisierten Zeichenfolgen usw.
'''</summary>
<Global.System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0"), _
Global.System.Diagnostics.DebuggerNonUserCodeAttribute(), _
Global.System.Runtime.CompilerServices.CompilerGeneratedAttribute(), _
Global.Microsoft.VisualBasic.HideModuleNameAttribute()> _
Friend Module Resources
Private resourceMan As Global.System.Resources.ResourceManager
Private resourceCulture As Global.System.Globalization.CultureInfo
'''<summary>
''' Gibt die zwischengespeicherte ResourceManager-Instanz zurück, die von dieser Klasse verwendet wird.
'''</summary>
<Global.System.ComponentModel.EditorBrowsableAttribute(Global.System.ComponentModel.EditorBrowsableState.Advanced)> _
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("MultiTool.Common.Resources", GetType(Resources).Assembly)
resourceMan = temp
End If
Return resourceMan
End Get
End Property
'''<summary>
''' Überschreibt die CurrentUICulture-Eigenschaft des aktuellen Threads für alle
''' Ressourcenzuordnungen, die diese stark typisierte Ressourcenklasse verwenden.
'''</summary>
<Global.System.ComponentModel.EditorBrowsableAttribute(Global.System.ComponentModel.EditorBrowsableState.Advanced)> _
Friend Property Culture() As Global.System.Globalization.CultureInfo
Get
Return resourceCulture
End Get
Set
resourceCulture = value
End Set
End Property
End Module
End Namespace

View File

@@ -0,0 +1,117 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

View File

@@ -0,0 +1,73 @@
'------------------------------------------------------------------------------
' <auto-generated>
' 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.
' </auto-generated>
'------------------------------------------------------------------------------
Option Strict On
Option Explicit On
Namespace My
<Global.System.Runtime.CompilerServices.CompilerGeneratedAttribute(), _
Global.System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "16.8.1.0"), _
Global.System.ComponentModel.EditorBrowsableAttribute(Global.System.ComponentModel.EditorBrowsableState.Advanced)> _
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
<Global.System.Diagnostics.DebuggerNonUserCodeAttribute(), Global.System.ComponentModel.EditorBrowsableAttribute(Global.System.ComponentModel.EditorBrowsableState.Advanced)> _
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
End Class
End Namespace
Namespace My
<Global.Microsoft.VisualBasic.HideModuleNameAttribute(), _
Global.System.Diagnostics.DebuggerNonUserCodeAttribute(), _
Global.System.Runtime.CompilerServices.CompilerGeneratedAttribute()> _
Friend Module MySettingsProperty
<Global.System.ComponentModel.Design.HelpKeywordAttribute("My.Settings")> _
Friend ReadOnly Property Settings() As Global.MultiTool.Common.My.MySettings
Get
Return Global.MultiTool.Common.My.MySettings.Default
End Get
End Property
End Module
End Namespace

View File

@@ -0,0 +1,7 @@
<?xml version='1.0' encoding='utf-8'?>
<SettingsFile xmlns="http://schemas.microsoft.com/VisualStudio/2004/01/settings" CurrentProfile="(Default)" UseMySettingsClassName="true">
<Profiles>
<Profile Name="(Default)" />
</Profiles>
<Settings />
</SettingsFile>

View File

@@ -0,0 +1,122 @@
Imports System.Text.RegularExpressions
Imports DigitalData.Modules.Logging
Imports MultiTool.Common.Documents
Imports MultiTool.Common.Templates
Imports MultiTool.Common.Winline.Entities
Public Class Patterns
Inherits BaseClass
Private ReadOnly GeneralConfig As GeneralConfig
Public Sub New(pLogConfig As LogConfig, pGeneralConfig As GeneralConfig)
MyBase.New(pLogConfig)
GeneralConfig = pGeneralConfig
End Sub
Public Function ReplaceForImport(pDocument As Documents.Document, pRow As DocumentRow, oString As String)
Dim oRegex = New Regex("{#(\w+)#([\w\s_-]+)}+")
Dim oMatches As MatchCollection = oRegex.Matches(oString)
For Each oMatch As Match In oMatches
Dim oPlaceholderString As String = oMatch.Groups.Item(0)?.Value
Dim oPlaceholderType As String = oMatch.Groups.Item(1)?.Value
Dim oPlaceholderValue As String = oMatch.Groups.Item(2)?.Value
Select Case oPlaceholderType.ToUpper
Case "FIELD"
Dim oFieldName = oPlaceholderValue
Dim oTargetField = pRow.Fields.
Where(Function(field) field.Key = oFieldName).
SingleOrDefault()
oString = oString.Replace(oPlaceholderString, oTargetField.Value.Final)
Case "CONST"
Dim oValue = ""
Select Case oPlaceholderValue.ToUpper
Case "MESOYEAR"
oValue = GeneralConfig.GetWinLineYear()
Case "MESOCOMP"
oValue = pDocument.Mandator.Id
Case "USERNAME"
oValue = Environment.UserName
Case "CURRENTDATE"
oValue = Now.ToString()
Case "FILENAME"
oValue = pDocument.FileName
Case "MANDATORDB"
oValue = pDocument.Mandator.Database
Case Else
oValue = ""
End Select
If oValue <> "" Then
oString = oString.Replace(oPlaceholderString, oValue)
End If
End Select
Next
Return oString
End Function
Public Function ReplaceForExport(pDocument As ExportDocument, pMandator As Mandator, oString As String)
Dim oRegex = New Regex("{#(\w+)#([\w\s_-]+)}+")
Dim oMatches As MatchCollection = oRegex.Matches(oString)
For Each oMatch As Match In oMatches
Dim oPlaceholderString As String = oMatch.Groups.Item(0)?.Value
Dim oPlaceholderType As String = oMatch.Groups.Item(1)?.Value
Dim oPlaceholderValue As String = oMatch.Groups.Item(2)?.Value
Select Case oPlaceholderType.ToUpper
Case "CONST"
Dim oValue = ""
Select Case oPlaceholderValue.ToUpper
Case "MESOYEAR"
oValue = GeneralConfig.GetWinLineYear()
Case "MESOCOMP"
oValue = pMandator.Id
Case "USERNAME"
oValue = Environment.UserName
Case "CURRENTDATE"
oValue = Now.ToString()
Case "FILENAME"
oValue = pDocument.FilenameExport
Case "ACCOUNTNUMBER"
oValue = pDocument.Account.Id
Case "RUNNINGNUMBER"
oValue = pDocument.RunningNumber
Case "MANDATORDB"
oValue = pMandator.Database
Case Else
oValue = ""
End Select
If oValue <> "" Then
oString = oString.Replace(oPlaceholderString, oValue)
End If
End Select
Next
Return oString
End Function
End Class

View File

@@ -0,0 +1,129 @@
Imports System.Text.RegularExpressions
Imports DevExpress.XtraReports
Imports DigitalData.Modules.Database
Imports DigitalData.Modules.Logging
Imports MultiTool.Common.Documents
Imports MultiTool.Common.Documents.DocumentRow
Imports MultiTool.Common.Report
Imports MultiTool.Common.Templates
Imports MultiTool.Common.Winline.Entities
Public Class ReportGenerator(Of TReport As IReport)
Inherits BaseClass
Private ReadOnly TemplateConfig As TemplateConfig
Private ReadOnly GeneralConfig As GeneralConfig
Private ReadOnly Patterns As Patterns
Private ReadOnly FileEx As DigitalData.Modules.Filesystem.File
Public Sub New(pLogConfig As LogConfig, pDatabase As MSSQLServer, pTemplateConfig As TemplateConfig, pGeneralConfig As GeneralConfig)
MyBase.New(pLogConfig)
Database = pDatabase
GeneralConfig = pGeneralConfig
TemplateConfig = pTemplateConfig
Patterns = New Patterns(pLogConfig, pGeneralConfig)
FileEx = New DigitalData.Modules.Filesystem.File(LogConfig)
End Sub
Public Function GetReportFilePath(pDocument As Document, pTemplate As Template)
Dim oFinalDirectory = FileEx.CreateDateDirectory(pTemplate.OutputReportDirectory)
Dim oFileName = FileEx.GetFilenameWithSuffix(IO.Path.GetFileNameWithoutExtension(pDocument.File.Name), FileEx.GetDateTimeString, "pdf")
Dim oFilePath As String = IO.Path.Combine(oFinalDirectory, oFileName)
Return oFilePath
End Function
Public Function GenerateReport(pDocument As Document, pTemplate As Template) As TReport
Dim oMapperConfig As New Mapper(LogConfig)
Dim oHeadMapper = oMapperConfig.GetMapper(Of ReportHead)(New Dictionary(Of String, String) From {
{"Fakt_Kontoname", "Text1"},
{"Fakt_Kontonummer[Final]", "Text2"},
{"Auftrags-Bestellnummer", "Text3"},
{"Datum_Auftrag-Bestellung", "Text4"},
{"Bestellt_von", "Text5"}
})
Dim oPositionMapper = oMapperConfig.GetMapper(Of ReportPosition)(New Dictionary(Of String, String) From {
{"Artikelnummer", "Text1"},
{"Lieferantenartikelnummer", "Text2"},
{"Bezeichnung", "Text3"},
{"Menge_bestellt", "Text4"},
{"Menge_geliefert", "Text5"},
{"Colli", "Text6"},
{"Einzelpreis[Original]", "Text7"},
{"Einzelpreis[Final]", "Text8"},
{"EinheitProPalette", "Text9"},
{"Lagerstand", "Text10"}
})
Dim oSQLConfig = TemplateConfig.Items.
Where(Function(item) item.Function.Name = Constants.FUNCTION_SQL).
ToList()
FillFieldValuesFromSQL(pDocument, oSQLConfig)
Dim oHeadRow = pDocument.Rows.
Where(Function(r) r.TableName.EndsWith("T025")).
Select(Function(r) r.Fields).
FirstOrDefault()
Dim oPositionRows = pDocument.Rows.
Where(Function(r) r.TableName.EndsWith("T026")).
ToList()
Dim oReportHead = oHeadMapper.Map(Of Dictionary(Of String, FieldValue), ReportHead)(oHeadRow)
oReportHead.Title = pTemplate.Name
oReportHead.Subtitle = "Schaum"
oReportHead.Filename = pDocument.FileName
Dim oReportPositions As New List(Of ReportPosition)
Dim oCounter = 1
For Each oRow As DocumentRow In oPositionRows
Dim oReportPosition As ReportPosition = oPositionMapper.Map(Of Dictionary(Of String, FieldValue), ReportPosition)(oRow.Fields)
oReportPosition.Id = oCounter
oReportPositions.Add(oReportPosition)
oCounter += 1
Next
Dim oReportSource As New ReportSource With {
.Head = oReportHead,
.Positions = oReportPositions
}
Dim oReport = Activator.CreateInstance(GetType(TReport))
Dim oDataSource = New DevExpress.DataAccess.ObjectBinding.ObjectDataSource With {
.DataSource = oReportSource
}
oDataSource.Fill()
oReport.DataSource = oDataSource
Return oReport
End Function
Private Sub FillFieldValuesFromSQL(pDocument As Document, oSQLConfig As List(Of TemplateConfigItem))
For Each oSQLConfigItem In oSQLConfig
' FieldList is a list of fields that will be changed
' Example: Setting SQL for Article StorageLocation will invoke the sql for each row
Dim oRowList = pDocument.Rows.
Where(Function(row) row.Fields.Any(Function(field) field.Key = oSQLConfigItem.Name)).
ToList()
For Each oRow As DocumentRow In oRowList
Dim oField = oRow.Fields.
Where(Function(field) field.Key = oSQLConfigItem.Name).
SingleOrDefault()
Dim oSQL = oSQLConfigItem.Function.Params
oSQL = Patterns.ReplaceForImport(pDocument, oRow, oSQL)
Dim oValue = Database.GetScalarValue(oSQL)
If oValue IsNot Nothing Then
oField.Value.Final = oValue
End If
Next
Next
End Sub
End Class

View File

@@ -0,0 +1,23 @@
Namespace Report
Public Class ReportHead
Public Property Title As String
Public Property Subtitle As String
Public Property Filename As String
Public Property DateCreated As Date
Public Property Id As String
Public Property Text1 As String
Public Property Text2 As String
Public Property Text3 As String
Public Property Text4 As String
Public Property Text5 As String
Public Property Text6 As String
Public Property Text7 As String
Public Property Text8 As String
Public Property Text9 As String
Public Property Text10 As String
End Class
End Namespace

View File

@@ -0,0 +1,27 @@
Namespace Report
Public Class ReportPosition
Public Property Id As String
Public Property Text1 As String
Public Property Text2 As String
Public Property Text3 As String
Public Property Text4 As String
Public Property Text5 As String
Public Property Text6 As String
Public Property Text7 As String
Public Property Text8 As String
Public Property Text9 As String
Public Property Text10 As String
Public Property Text11 As String
Public Property Text12 As String
Public Property Text13 As String
Public Property Text14 As String
Public Property Text15 As String
Public Property Text16 As String
Public Property Text17 As String
Public Property Text18 As String
Public Property Text19 As String
Public Property Text20 As String
End Class
End Namespace

View File

@@ -0,0 +1,18 @@
Imports System.ComponentModel
Imports DevExpress.DataAccess.ObjectBinding
Namespace Report
<HighlightedClass, DisplayName("ReportSource")>
Public Class ReportSource
<HighlightedMember>
Public Property Head As ReportHead
<HighlightedMember>
Public Property Positions As IEnumerable(Of ReportPosition)
<HighlightedMember>
Public Iterator Function GetPositionList() As IEnumerable(Of ReportPosition)
For Each oPosition In Positions
Yield oPosition
Next
End Function
End Class
End Namespace

View File

@@ -0,0 +1,31 @@
Imports System.Xml.Serialization
Imports DigitalData.Modules.Logging
Public Class Serializer
Inherits BaseClass
Public Sub New(pLogConfig As LogConfig)
MyBase.New(pLogConfig)
End Sub
Public Function GetSerializer(pSchemaType As Type) As XmlSerializer
Dim oSerializer As New XmlSerializer(pSchemaType)
AddHandler oSerializer.UnknownAttribute, Sub(sender As Object, e As XmlAttributeEventArgs)
Logger.Debug("[{1}] Unknown Attribute: {0}", e.Attr, pSchemaType.Name)
End Sub
AddHandler oSerializer.UnknownElement, Sub(sender As Object, e As XmlElementEventArgs)
Logger.Debug("[{1}] Unknown Element: {0}", e.Element, pSchemaType.Name)
End Sub
AddHandler oSerializer.UnknownNode, Sub(sender As Object, e As XmlNodeEventArgs)
Logger.Debug("[{1}] Unknown Node: {0}", e.Name, pSchemaType.Name)
End Sub
AddHandler oSerializer.UnreferencedObject, Sub(sender As Object, e As UnreferencedObjectEventArgs)
Logger.Debug("[{1}] Unreferenced Object: {0}", e.UnreferencedId, pSchemaType.Name)
End Sub
Return oSerializer
End Function
End Class

View File

@@ -0,0 +1,35 @@
Namespace Templates
Public Class GeneralConfig
Public Property TemplateDirectory As String = ""
Public Property Webservice As New WebServiceConfig()
Public Property DefaultYearOverride As Integer = 0
Public Class WebServiceConfig
Public Property BaseUrl As String = "http://127.0.0.1/EWL"
Public Property Username As String = "Username"
Public Property Password As String = "Password"
Public Property ImportBasePath As String = ""
Public Property ImportRelativePath As String = ""
End Class
<DebuggerStepThrough>
Public Function GetYear() As Integer
If DefaultYearOverride > 0 Then
Return DefaultYearOverride
End If
Return Now.Year
End Function
<DebuggerStepThrough>
Public Function GetWinLineYear()
Return GetWinLineYear(GetYear)
End Function
<DebuggerStepThrough>
Public Function GetWinLineYear(pYear As Integer)
Return (pYear - 1900) * 12
End Function
End Class
End Namespace

View File

@@ -0,0 +1,5 @@
Namespace Templates
Public Class MandatorConfig
Public Property Items As New List(Of MandatorConfigItem)
End Class
End Namespace

View File

@@ -0,0 +1,7 @@
Namespace Templates
Public Class MandatorConfigItem
Public Property Name As String
Public Property OrderKey As Integer
End Class
End Namespace

View File

@@ -0,0 +1,12 @@
Namespace Templates
Public Class MappingConfig
Public Class Entity
Public Const MANDATOR = "MANDATOR"
Public Const DOCUMENTTYPE = "DOCUMENTTYPE"
Public Const ARTICLE = "ARTICLE"
End Class
Public Property Items As New List(Of MappingConfigItem)
End Class
End Namespace

View File

@@ -0,0 +1,12 @@
Namespace Templates
Public Class MappingConfigItem
Public Property OrderKey As Integer
Public Property SourceName As String
Public Property SourceItem As String
Public Property SourceRegex As String
Public Property DestinationName As String
Public Property DestinationItem As String
Public Property DestinationValue As String
End Class
End Namespace

View File

@@ -0,0 +1,97 @@
Imports DigitalData.Modules.Language
Namespace Templates
Public Class Template
Public Property Guid As Integer
Public Property Name As String
Public Property FileName As String
Public Property Description As String
Public Property IsImport As Boolean
Public Property Parameter1 As String
Public Property Parameter2 As String
Public Property FinalSQL As String
''' <summary>
''' Tabledata from XSD
''' </summary>
Public Property Tables As New List(Of Table)
Public Property InputDirectory As String
Public Property OutputDirectory As String
Public Property ArchiveDirectory As String
Public ReadOnly Property OutputReportDirectory
Get
Return IO.Path.Combine(OutputDirectory, "Reports")
End Get
End Property
Public ReadOnly Property OutputWebserviceDirectory
Get
Return IO.Path.Combine(OutputDirectory, "WebService")
End Get
End Property
Public ReadOnly Property OutputXmlFileDirectory
Get
Return IO.Path.Combine(OutputDirectory, "XmlFiles")
End Get
End Property
Public Function GetParameter(pName As String) As String
Dim oParam1 As String = Utils.NotNull(Parameter1, String.Empty)
Dim oParam2 As String = Utils.NotNull(Parameter2, String.Empty)
Dim oParamValue1 = TryGetParameter(oParam1)
Dim oParamValue2 = TryGetParameter(oParam2)
If oParamValue1 IsNot Nothing AndAlso oParamValue1.Item1 = pName Then
Return oParamValue1.Item2
End If
If oParamValue2 IsNot Nothing AndAlso oParamValue2.Item1 = pName Then
Return oParamValue2.Item2
End If
Return Nothing
End Function
Private Function TryGetParameter(pParameterString As String) As Tuple(Of String, String)
If pParameterString <> String.Empty Then
Dim oSplit = pParameterString.Split("=").ToList()
If oSplit.Count = 2 Then
Return New Tuple(Of String, String)(oSplit.First, oSplit.Last)
Else
Return Nothing
End If
Else
Return Nothing
End If
End Function
''' <summary>
''' Table from XSD
''' </summary>
Class Table
Public Property Name As String
Public Property Columns As New List(Of Column)
End Class
Class Column
Public Property Name As String
Public Property DataType As Constants.ColumnType
''' <summary>
''' Required value from Schema. This value will be written in the ColumnConfig and is not relevant from that point on.
''' </summary>
Public Property IsRequired As Boolean
Public Property Config As TemplateConfigItem
Public Overrides Function ToString() As String
Return Name
End Function
End Class
End Class
End Namespace

View File

@@ -0,0 +1,17 @@
Imports MultiTool.Common.Winline
Namespace Templates
''' <summary>
''' Class for loading column/field config from database
''' </summary>
Public Class TemplateConfig
Public Property Items As List(Of TemplateConfigItem)
Public Function GetColumn(pName As String, pTable As String) As TemplateConfigItem
Return Items.
Where(Function(c) c.Name = pName And c.Table = pTable).
FirstOrDefault()
End Function
End Class
End Namespace

View File

@@ -0,0 +1,59 @@
Imports MultiTool.Common.Constants
Imports DigitalData.Modules.Language
Namespace Templates
Public Class TemplateConfigItem
Public Property Name As String
Public Property Table As String
Public Property Type As ColumnType
Public Property Template As String
Public Property OrderKey As Integer
Public Property IsHead As Boolean
Public Property IsReadOnly As Boolean
Public Property IsVisible As Boolean
Public Property IsRequired As Boolean
Public Property IsVirtual As Boolean
Public Property [Function] As ColumnFunction
Public ReadOnly Property FunctionName As String
Get
Return Utils.NotNull([Function]?.Name, String.Empty)
End Get
End Property
Public ReadOnly Property FunctionParams As String
Get
Return Utils.NotNull([Function]?.Params, String.Empty)
End Get
End Property
Public Class ColumnFunction
Public Id As XmlFunction
Public Name As String
Public Params As String
End Class
Public Shared Function ConvertType(pType As String) As ColumnType
Select Case pType
Case DB_TYPE_DATE
Return ColumnType.Date
Case DB_TYPE_DECIMAL
Return ColumnType.Date
Case DB_TYPE_BOOLEAN
Return ColumnType.Boolean
Case DB_TYPE_INTEGER
Return ColumnType.Integer
Case Else
Return ColumnType.String
End Select
End Function
End Class
End Namespace

View File

@@ -0,0 +1,352 @@
Imports System.IO
Imports DigitalData.Modules.Database
Imports DigitalData.Modules.Logging
Imports DigitalData.Modules.Language
Namespace Templates
Public Class TemplateLoader
Inherits BaseClass
Private ReadOnly ns As XNamespace = "http://www.w3.org/2001/XMLSchema"
Public Property TemplateList As List(Of Template)
Public Property TemplateConfiguration As New TemplateConfig
Public Property MappingConfiguration As New MappingConfig
Public Property MandatorConfiguration As New MandatorConfig
Public Property GeneralConfiguration As New GeneralConfig
Private Const SQL_VWMT_ITEMS = "SELECT * FROM [DD_ECM].[dbo].[VWMT_ITEMS]"
Private Const SQL_VWMT_MAPPING = "SELECT * FROM [DD_ECM].[dbo].[VWMT_MAPPING]"
Private Const SQL_TBMT_MANDATORS = "SELECT * FROM [DD_ECM].[dbo].[TBMT_MANDATORS] ORDER BY ORDER_KEY"
Private Const SQL_TBMT_CONFIG = "SELECT * FROM [DD_ECM].[dbo].[TBMT_CONFIG]"
Private Const SQL_TBMT_TEMPLATES = "SELECT * FROM [DD_ECM].[dbo].[TBMT_TEMPLATES] WHERE ACTIVE = 1"
Public Sub New(pLogConfig As LogConfig, pMSSQL As MSSQLServer)
MyBase.New(pLogConfig, pMSSQL)
End Sub
Public Async Function LoadTemplates() As Task(Of Boolean)
Try
Dim oTable As DataTable = Await Database.GetDatatableAsync(SQL_TBMT_TEMPLATES)
Dim oTemplates As New List(Of Template)
For Each oRow As DataRow In oTable.Rows
Dim oTemplate As New Template With {
.Guid = oRow.Item("GUID"),
.Name = oRow.ItemEx("NAME", String.Empty),
.Description = oRow.ItemEx("DESCRIPTION", String.Empty),
.FileName = oRow.ItemEx("FILE_NAME", String.Empty),
.IsImport = oRow.ItemEx("IS_IMPORT", True),
.FinalSQL = oRow.ItemEx("FINAL_SQL", String.Empty),
.Parameter1 = oRow.ItemEx("PARAMETER_1", String.Empty),
.Parameter2 = oRow.ItemEx("PARAMETER_2", String.Empty)
}
oTemplates.Add(oTemplate)
Next
TemplateList = oTemplates
Return True
Catch ex As Exception
Logger.Error(ex)
Return False
End Try
End Function
Public Async Function LoadGeneralConfiguration() As Task(Of Boolean)
Try
Dim oTable As DataTable = Await Database.GetDatatableAsync(SQL_TBMT_CONFIG)
Dim oGeneralConfig As New GeneralConfig
For Each oRow As DataRow In oTable.Rows
Dim oValue As String = oRow.ItemEx("VALUE", String.Empty)
Select Case oRow.Item("KEY")
Case "YEAR_OVERRIDE"
oGeneralConfig.DefaultYearOverride = oRow.ItemEx("VALUE", 0)
Case "WEBSERVICE_BASEURL"
oGeneralConfig.Webservice.BaseUrl = oValue
Case "WEBSERVICE_USERNAME"
oGeneralConfig.Webservice.Username = oValue
Case "WEBSERIVCE_PASSWORD"
oGeneralConfig.Webservice.Password = oValue
Case "WEBSERVICE_IMPORT_BASE_PATH"
oGeneralConfig.Webservice.ImportBasePath = oValue
Case "WEBSERVICE_IMPORT_RELATIVE_PATH"
oGeneralConfig.Webservice.ImportRelativePath = oValue
Case "TEMPLATE_DIRECTORY"
oGeneralConfig.TemplateDirectory = oValue
End Select
Next
GeneralConfiguration = oGeneralConfig
Return True
Catch ex As Exception
Logger.Error(ex)
Return False
End Try
End Function
Public Async Function LoadMappingConfiguration() As Task(Of Boolean)
Try
Dim oTable As DataTable = Await Database.GetDatatableAsync(SQL_VWMT_MAPPING)
Dim oMappingConfig As New MappingConfig
For Each oRow As DataRow In oTable.Rows
Dim oTemplate As New MappingConfigItem With {
.OrderKey = oRow.ItemEx("ORDER_KEY", String.Empty),
.SourceName = oRow.ItemEx("SOURCE_NAME", String.Empty),
.SourceItem = oRow.ItemEx("SOURCE_ITEM", String.Empty),
.SourceRegex = oRow.ItemEx("SOURCE_REGEX", String.Empty),
.DestinationName = oRow.ItemEx("DESTINATION_NAME", String.Empty),
.DestinationItem = oRow.ItemEx("DESTINATION_ITEM", String.Empty),
.DestinationValue = oRow.ItemEx("DESTINATION_VALUE", String.Empty)
}
oMappingConfig.Items.Add(oTemplate)
Next
MappingConfiguration = oMappingConfig
Return True
Catch ex As Exception
Logger.Error(ex)
Return False
End Try
End Function
Public Async Function LoadMandatorConfiguration() As Task(Of Boolean)
Try
Dim oTable As DataTable = Await Database.GetDatatableAsync(SQL_TBMT_MANDATORS)
Dim oMandatorConfig As New MandatorConfig
For Each oRow As DataRow In oTable.Rows
Dim oMandator As New MandatorConfigItem With {
.OrderKey = oRow.ItemEx("ORDER_KEY", String.Empty),
.Name = oRow.ItemEx("NAME", String.Empty)
}
oMandatorConfig.Items.Add(oMandator)
Next
MandatorConfiguration = oMandatorConfig
Return True
Catch ex As Exception
Logger.Error(ex)
Return False
End Try
End Function
Public Async Function LoadTemplateConfiguration() As Task(Of Boolean)
Try
Dim oTable As DataTable = Await Database.GetDatatableAsync(SQL_VWMT_ITEMS)
Dim oItems As New List(Of TemplateConfigItem)
For Each oRow As DataRow In oTable.Rows
Dim oColumn As New TemplateConfigItem() With {
.Template = oRow.ItemEx("TEMPLATE_NAME", String.Empty),
.Table = oRow.ItemEx("XML_TABLE", String.Empty),
.Name = oRow.ItemEx("XML_ITEM", String.Empty),
.Type = TemplateConfigItem.ConvertType(ItemEx(oRow, "DATA_TYPE", String.Empty)),
.OrderKey = oRow.ItemEx("ORDER_KEY", 0),
.IsReadOnly = oRow.ItemEx("IS_READ_ONLY", False),
.IsVisible = oRow.ItemEx("IS_VISIBLE", True),
.IsRequired = oRow.ItemEx("IS_REQUIRED", False),
.IsVirtual = oRow.ItemEx("IS_VIRTUAL", False),
.IsHead = oRow.ItemEx("IS_HEAD", True),
.[Function] = New TemplateConfigItem.ColumnFunction With {
.Id = oRow.ItemEx("FUNCTION_ID", 0),
.Name = oRow.ItemEx("FUNCTION_NAME", String.Empty),
.Params = oRow.ItemEx("FUNCTION_PARAMETERS", String.Empty)
}
}
oItems.Add(oColumn)
Next
TemplateConfiguration = New TemplateConfig With {
.Items = oItems
}
Return True
Catch ex As Exception
Logger.Error(ex)
Return False
End Try
End Function
Public Function UpdateTemplateFromFile(pTemplate As Template, pInputDirectory As String) As Template
Dim oFullPath = Path.Combine(pInputDirectory, pTemplate.FileName)
If Not IO.File.Exists(oFullPath) Then
Throw New FileNotFoundException(oFullPath)
End If
Dim oElements = GetTemplateElements(oFullPath)
For Each oElement In oElements
Dim oColumns = GetElementColumns(oElement)
Dim oTemplateColumns As New List(Of Template.Column)
For Each oColumn As XElement In oColumns
Dim oName = XmlData.GetElementAttribute(oColumn, "name")
Dim oMinOccurs = XmlData.GetElementAttribute(oColumn, "minOccurs")
Dim oMaxOccurs = XmlData.GetElementAttribute(oColumn, "maxOccurs")
Dim oType = GetElementType(oColumn)
Dim oRequired = False
If oMinOccurs = 1 And oMaxOccurs = 1 Then
oRequired = True
End If
Dim oTemplateColumn As New Template.Column With {
.Name = oName,
.DataType = oType,
.IsRequired = oRequired
}
oTemplateColumns.Add(oTemplateColumn)
Next
pTemplate.Tables.Add(New Template.Table With {
.Name = XmlData.GetElementAttribute(oElement, "name"),
.Columns = oTemplateColumns
})
Next
Return pTemplate
End Function
Public Function UpdateTemplateTablesFromDatabase(pTemplate As Template, pTemplateConfig As TemplateConfig) As Template
If pTemplateConfig Is Nothing Then
Return pTemplate
End If
Dim oTemplate = CreateVirtualColumns(pTemplate, pTemplateConfig)
For Each oTable In oTemplate.Tables
For Each oColumn As Template.Column In oTable.Columns
Dim oConfig As TemplateConfigItem = pTemplateConfig.GetColumn(oColumn.Name, oTable.Name)
If oConfig Is Nothing Then
oConfig = New TemplateConfigItem With {
.IsRequired = oColumn.IsRequired,
.Name = oColumn.Name
}
End If
oColumn.Config = oConfig
Next
Next
Return oTemplate
End Function
Private Function CreateVirtualColumns(pTemplate As Template, pTemplateConfig As TemplateConfig) As Template
For Each oConfigItem In pTemplateConfig.Items
' Find the table that relates to this config item
Dim oTable = pTemplate.Tables.Where(Function(table) table.Name = oConfigItem.Table).FirstOrDefault()
If oTable Is Nothing Then
Logger.Warn("Table [{0}] for item [{1}] does exist in this Template!", oConfigItem.Table, oConfigItem.Name)
Continue For
End If
Dim oColumnExists = oTable.Columns.Any(Function(column) column.Name = oConfigItem.Name)
If oColumnExists = False And oConfigItem.IsVirtual = True Then
oTable.Columns.Add(New Template.Column() With {
.Name = oConfigItem.Name,
.Config = oConfigItem,
.DataType = Constants.ColumnType.String,
.IsRequired = False
})
End If
Next
Return pTemplate
End Function
Public Function UpdateTemplateFromDatabase(pTemplate As Template) As Template
Try
Dim oTable As DataTable = Database.GetDatatable($"{SQL_TBMT_CONFIG} WHERE TEMPLATE_ID = {pTemplate.Guid}")
Dim oGeneralConfig As New GeneralConfig
For Each oRow As DataRow In oTable.Rows
Dim oValue As String = oRow.ItemEx("VALUE", String.Empty)
Select Case oRow.Item("KEY")
Case "INPUT_DIRECTORY"
pTemplate.InputDirectory = oValue
Case "OUTPUT_DIRECTORY"
pTemplate.OutputDirectory = oValue
Case "ARCHIVE_DIRECTORY"
pTemplate.ArchiveDirectory = oValue
End Select
Next
Return pTemplate
Catch ex As Exception
Logger.Error(ex)
Return pTemplate
End Try
End Function
Public Function GetElementType(pElement As XElement) As Constants.ColumnType
Dim oTypeString = XmlData.GetElementAttribute(pElement, "type")
If oTypeString Is Nothing Then
Dim oRestrictionElement As XElement = pElement.
Descendants(ns + "restriction").
FirstOrDefault()
oTypeString = XmlData.GetElementAttribute(oRestrictionElement, "base")
End If
Select Case oTypeString
Case Constants.TEMPLATE_TYPE_DATE
Return Constants.ColumnType.Date
Case Constants.TEMPLATE_TYPE_INTEGER
Return Constants.ColumnType.Integer
Case Constants.TEMPLATE_TYPE_DECIMAL
Return Constants.ColumnType.Decimal
Case Constants.TEMPLATE_TYPE_BOOLEAN
Return Constants.ColumnType.Boolean
Case Else
Return Constants.ColumnType.String
End Select
End Function
Public Function GetTemplateElements(pTemplateFilePath As String) As List(Of XElement)
Dim oText As String = IO.File.ReadAllText(pTemplateFilePath)
Dim oDoc = XDocument.Parse(oText)
Return XmlData.GetElementsFromElement(oDoc, "choice", ns)
End Function
Public Function GetElementColumns(pElement As XElement) As List(Of XElement)
Return XmlData.GetElementsFromElement(pElement, "sequence", ns)
End Function
End Class
End Namespace

View File

@@ -0,0 +1,25 @@
Namespace Winline.Entities
Public Class Account
Public Property Id As String
Public Property Name As String
Public Property StreetName As String
Public Property CityName As String
Public Property ZipCode As String
Public Property GLN As String
Public Property Mandator As Mandator
Public Overrides Function GetHashCode() As Integer
Return Id.GetHashCode()
End Function
Public Overrides Function Equals(obj As Object) As Boolean
Return DirectCast(obj, Account).Id = Id
End Function
Public Overrides Function ToString() As String
Return $"{Name} ({Id})"
End Function
End Class
End Namespace

View File

@@ -0,0 +1,21 @@
Namespace Winline.Entities
Public Class Article
Public Property Id As String
Public Property Name As String
Public Property EAN As String
Public Property Mandator As Mandator
Public Overrides Function GetHashCode() As Integer
Return Id.GetHashCode()
End Function
Public Overrides Function Equals(obj As Object) As Boolean
Return DirectCast(obj, Article).Id = Id
End Function
Public Overrides Function ToString() As String
Return $"{Name} ({Id})"
End Function
End Class
End Namespace

View File

@@ -0,0 +1,12 @@
Namespace Winline.Entities
Public Class Contact
Public Property Id As Integer
Public Property Number As String
Public Property Name As String
Public Overrides Function ToString() As String
Return Name
End Function
End Class
End Namespace

View File

@@ -0,0 +1,19 @@
Namespace Winline.Entities
Public Class DocumentKind
Public Property Id As Integer
Public Property Name As String
Public Property Mandator As Mandator
Public Overrides Function GetHashCode() As Integer
Return Id.GetHashCode()
End Function
Public Overrides Function Equals(obj As Object) As Boolean
Return DirectCast(obj, DocumentKind).Id = Id
End Function
Public Overrides Function ToString() As String
Return $"{Name} ({Id})"
End Function
End Class
End Namespace

View File

@@ -0,0 +1,28 @@
Namespace Winline.Entities
Public Class ExportDocument
Public Property Schema As Templates.Template
Public Property Account As Account
Public ReadOnly Property AccountName As String
Get
Return Account?.ToString()
End Get
End Property
Public Property Kind As DocumentKind
Public Property RunningNumber As String
Public Property Number As String
Public Property [Date] As Date
Public Property DateColumn As String
Public Property NetAmount As Double
Public Property GrossAmount As Double
Public Property IsSelected As Boolean = False
Public Property IsExported As Boolean = False
Public Property FilenameExport As String
Public Property ExportedWhen As Date
Public Property ExportedWho As String
End Class
End Namespace

View File

@@ -0,0 +1,23 @@
Namespace Winline.Entities
Public Class Mandator
Public Property Id As String
Public Property Name As String
Public Property Database As String
Public Property Server As String
Public Property Regex As String
Public Property Order As Integer
Public Property IsWhitelisted As Boolean
Public Overrides Function GetHashCode() As Integer
Return Id.GetHashCode()
End Function
Public Overrides Function Equals(obj As Object) As Boolean
Return DirectCast(obj, Mandator).Id = Id
End Function
Public Overrides Function ToString() As String
Return $"{Name} ({Id})"
End Function
End Class
End Namespace

View File

@@ -0,0 +1,128 @@
'------------------------------------------------------------------------------
' <auto-generated>
' 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.
' </auto-generated>
'------------------------------------------------------------------------------
Option Strict Off
Option Explicit On
'
'This source code was auto-generated by xsd, Version=4.8.3928.0.
'
Namespace Templates.Entities
'''<remarks/>
<System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.8.3928.0"),
System.SerializableAttribute(),
System.Diagnostics.DebuggerStepThroughAttribute(),
System.ComponentModel.DesignerCategoryAttribute("code"),
System.Xml.Serialization.XmlTypeAttribute(AnonymousType:=True),
System.Xml.Serialization.XmlRootAttribute([Namespace]:="", IsNullable:=False)>
Partial Public Class MESOWebServiceResult
Private overallSuccessField As Boolean
Private resultDetailsField As MESOWebServiceResultResultDetails()
'''<remarks/>
<System.Xml.Serialization.XmlElementAttribute(Form:=System.Xml.Schema.XmlSchemaForm.Unqualified)>
Public Property OverallSuccess() As Boolean
Get
Return Me.overallSuccessField
End Get
Set
Me.overallSuccessField = Value
End Set
End Property
'''<remarks/>
<System.Xml.Serialization.XmlElementAttribute("ResultDetails", Form:=System.Xml.Schema.XmlSchemaForm.Unqualified)>
Public Property ResultDetails() As MESOWebServiceResultResultDetails()
Get
Return Me.resultDetailsField
End Get
Set
Me.resultDetailsField = Value
End Set
End Property
End Class
'''<remarks/>
<System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.8.3928.0"),
System.SerializableAttribute(),
System.Diagnostics.DebuggerStepThroughAttribute(),
System.ComponentModel.DesignerCategoryAttribute("code"),
System.Xml.Serialization.XmlTypeAttribute(AnonymousType:=True)>
Partial Public Class MESOWebServiceResultResultDetails
Private successField As Boolean
Private errorCodeField As String
Private errorTextField As String
Private keyValueField As String
Private voucherNumberField As String
'''<remarks/>
<System.Xml.Serialization.XmlElementAttribute(Form:=System.Xml.Schema.XmlSchemaForm.Unqualified)>
Public Property Success() As Boolean
Get
Return Me.successField
End Get
Set
Me.successField = Value
End Set
End Property
'''<remarks/>
<System.Xml.Serialization.XmlElementAttribute(Form:=System.Xml.Schema.XmlSchemaForm.Unqualified)>
Public Property ErrorCode() As String
Get
Return Me.errorCodeField
End Get
Set
Me.errorCodeField = Value
End Set
End Property
'''<remarks/>
<System.Xml.Serialization.XmlElementAttribute(Form:=System.Xml.Schema.XmlSchemaForm.Unqualified)>
Public Property ErrorText() As String
Get
Return Me.errorTextField
End Get
Set
Me.errorTextField = Value
End Set
End Property
'''<remarks/>
<System.Xml.Serialization.XmlElementAttribute(Form:=System.Xml.Schema.XmlSchemaForm.Unqualified)>
Public Property KeyValue() As String
Get
Return Me.keyValueField
End Get
Set
Me.keyValueField = Value
End Set
End Property
'''<remarks/>
<System.Xml.Serialization.XmlElementAttribute(Form:=System.Xml.Schema.XmlSchemaForm.Unqualified)>
Public Property VoucherNumber() As String
Get
Return Me.voucherNumberField
End Get
Set
Me.voucherNumberField = Value
End Set
End Property
End Class
End Namespace

View File

@@ -0,0 +1,402 @@
Imports System.Net.Http
Imports System.Text
Imports System.Xml
Imports DigitalData.Modules.Database
Imports DigitalData.Modules.Filesystem
Imports DigitalData.Modules.Logging
Imports MultiTool.Common.Documents
Imports MultiTool.Common.Exceptions
Imports MultiTool.Common.Templates
Imports MultiTool.Common.Templates.GeneralConfig
Imports MultiTool.Common.Winline.Entities
Namespace Winline
Public Class WebServiceData
Inherits BaseClass
Private ReadOnly Config As WebServiceConfig
Private ReadOnly Serializer As Serializer
Private ReadOnly Winline As WinlineData
Private ReadOnly FileEx As File
Private ReadOnly Patterns As Patterns
Public Event WebServiceProgress As EventHandler(Of String)
Public Sub New(pLogConfig As LogConfig, pDatabase As MSSQLServer, pWinline As WinlineData, pWebserviceConfig As WebServiceConfig, pGeneralConfig As GeneralConfig)
MyBase.New(pLogConfig, pDatabase)
Serializer = New Serializer(pLogConfig)
Config = pWebserviceConfig
Patterns = New Patterns(pLogConfig, pGeneralConfig)
FileEx = New File(LogConfig)
Winline = pWinline
End Sub
Public Sub RaiseWebServiceProgress(pMessage As String)
RaiseEvent WebServiceProgress(Me, pMessage)
End Sub
#Region "Import"
''' <summary>
''' Transfers a document to winline via Webservices
''' </summary>
''' <param name="pDocument"></param>
''' <param name="pTemplate"></param>
''' <param name="pMandator"></param>
''' <param name="pIsTest"></param>
''' <exception cref="HttpRequestException"></exception>
''' <exception cref="WebServiceException"></exception>
''' <exception cref="TaskCanceledException"></exception>
''' <returns>True if request was successful.</returns>
Public Async Function TransferDocumentToWinline(pDocument As Documents.Document, pTemplate As Template, pMandator As Mandator, Optional pIsTest As Boolean = False) As Task(Of Boolean)
Dim oBytes As Byte() = GetBytesFromDocument(pDocument)
Dim oWS = Config
RaiseEvent WebServiceProgress(Me, "Einstellungen laden")
' --- Build all teh filenamez and pathz
Dim oBaseFileName As String = FileEx.GetDateTimeString()
Dim oFileName = $"{pTemplate.Name}-{oBaseFileName}-Request.xml"
' --- Get and create path for request/response files
Dim oOutputDirectory = FileEx.CreateDateDirectory(pTemplate.OutputWebserviceDirectory)
Dim oOutputFilePath = IO.Path.Combine(oOutputDirectory, oFileName)
' Generate absolute path to copy xml file to
Dim oAbsolutePath = IO.Path.Combine(oWS.ImportBasePath, oWS.ImportRelativePath)
oAbsolutePath = FileEx.CreateDateDirectory(oAbsolutePath)
Dim oImportAbsoluteFilePath = IO.Path.Combine(oAbsolutePath, oFileName)
' Generate relative path to supply to winline
Dim oRelativePath = IO.Path.Combine(oWS.ImportRelativePath)
oRelativePath = FileEx.GetDateDirectory(oRelativePath)
Dim oImportRelativeFilePath = IO.Path.Combine(oRelativePath, oFileName)
RaiseEvent WebServiceProgress(Me, "Dateien schreiben")
' --- Serialize Data into XML string
IO.File.WriteAllBytes(oOutputFilePath, oBytes)
' --- Copy file to Winline Import Directory
Try
IO.File.Copy(oOutputFilePath, oImportAbsoluteFilePath, True)
Catch ex As Exception
Logger.Error(ex)
Throw ex
End Try
' --- Prepare URL and HTTP Client
Dim oTemplateType = pDocument.TemplateType
Dim oTemplateName = pDocument.TemplateName
' ActionCode: Should this be a test or not?
' 0 = Test call
' 1 = Real call
Dim oActionCode = 1
If pIsTest = True Then
oActionCode = 0
End If
' Byref: Should data be supplied as file or as string?
' 0 = As String
' 1 = As File (relative to Winline Server directory)
Dim oByref = 1
Dim oURL As String = $"{oWS.BaseUrl}/ewlservice/import?User={oWS.Username}&Password={oWS.Password}&Company={pMandator.Id}&Type={oTemplateType}&Vorlage={oTemplateName}&ActionCode={oActionCode}&Byref={oByref}&Data={oImportRelativeFilePath}"
Dim oClient As New HttpClient With {
.Timeout = TimeSpan.FromSeconds(Constants.HTTP_REQUEST_TIMEOUT_IN_SECONDS)
}
Logger.Info("Creating HTTP Request to [{0}]", oWS.BaseUrl)
RaiseEvent WebServiceProgress(Me, "Anfrage absenden")
' --- Bring the action!
Try
Dim oResponse As HttpResponseMessage = Await oClient.GetAsync(oURL)
Await HandleImportResponse(oResponse, pTemplate, oBaseFileName)
Return True
Catch ex As Exception
Logger.Error(ex)
Throw ex
Finally
oClient.Dispose()
End Try
End Function
Private Async Function HandleImportResponse(pResponse As HttpResponseMessage, pTemplate As Template, pBaseFileName As String) As Task
pResponse.EnsureSuccessStatusCode()
Dim oResponseBody As String = Await pResponse.Content.ReadAsStringAsync()
Dim oContentType = pResponse.Content.Headers.ContentType.MediaType
Dim oSerializer = Serializer.GetSerializer(GetType(Templates.Entities.MESOWebServiceResult))
Dim oOutputDirectory = FileEx.CreateDateDirectory(pTemplate.OutputWebserviceDirectory)
RaiseEvent WebServiceProgress(Me, "Antwort verarbeiten")
Select Case oContentType
Case "text/xml"
WriteResponseFile(oOutputDirectory, oResponseBody, $"{pTemplate.Name}-{pBaseFileName}-Response.xml")
Dim oBytes As Byte() = Encoding.UTF8.GetBytes(oResponseBody)
Using oStream As New IO.MemoryStream(oBytes)
Dim oResponseObject As Templates.Entities.MESOWebServiceResult = oSerializer.Deserialize(oStream)
Dim oErrorStrings As New List(Of String)
If oResponseObject.ResultDetails IsNot Nothing Then
For Each oDetails As Templates.Entities.MESOWebServiceResultResultDetails In oResponseObject.ResultDetails
If oDetails.Success = True Then
Logger.Info("KeyValue: [{0}]", oDetails.KeyValue)
Logger.Info("VoucherNumber: [{0}]", oDetails.VoucherNumber)
Else
Logger.Warn("ErrorCode: [{0}]", oDetails.ErrorCode)
Logger.Warn("ErrorText: [{0}]", oDetails.ErrorText)
oErrorStrings.Add($"[{oDetails.ErrorCode}] {oDetails.ErrorText}")
End If
Next
End If
If oResponseObject.OverallSuccess = False Then
Dim oMessage = $"Request to Webservice was unsuccessful:{vbNewLine}{vbNewLine}{String.Join(vbNewLine, oErrorStrings.ToArray)}"
Throw New WebServiceException(oMessage)
End If
End Using
Case "text/html"
WriteResponseFile(oOutputDirectory, oResponseBody, $"{pTemplate.Name}-{pBaseFileName}-Response.xml")
Throw New WebServiceException(oResponseBody)
Case Else
Throw New WebServiceException(oResponseBody)
End Select
End Function
Private Function GetBytesFromDocument(pDocument As Documents.Document) As Byte()
Using oStream As New IO.MemoryStream()
Dim w = XmlWriter.Create(oStream)
w.WriteStartDocument()
w.WriteStartElement("MESOWebService")
w.WriteAttributeString("Template", pDocument.TemplateName)
w.WriteAttributeString("TemplateType", pDocument.TemplateType)
w.WriteAttributeString("option", pDocument.Option)
w.WriteAttributeString("printVoucher", pDocument.PrintVoucher)
pDocument.Rows.Sort()
For Each oRow In pDocument.Rows
w.WriteStartElement(oRow.TableName)
For Each oField As KeyValuePair(Of String, DocumentRow.FieldValue) In oRow.Fields
If oField.Value.Final = String.Empty Then
Continue For
End If
If oField.Value.IsVirtual Then
Continue For
End If
w.WriteStartElement(oField.Key)
w.WriteValue(oField.Value.Final)
w.WriteEndElement() ' Field
Next
w.WriteEndElement() ' Row
Next
w.WriteEndElement() ' MESOWebService
w.WriteEndDocument() ' Document
w.Close()
Return oStream.ToArray()
End Using
End Function
#End Region
#Region "Export"
Async Function ExportDocumentFromWinline(pDocument As Entities.ExportDocument, pTemplate As Template, pMandator As Mandator, Optional pIsTest As Boolean = False) As Task(Of Boolean)
Dim oWS = Config
' --- Build all teh filenamez and pathz
Dim oBaseFileName As String = FileEx.GetDateTimeString()
Dim oFileName = $"{pTemplate.Name}-{oBaseFileName}.xml"
'Dim oFileName = FileEx.GetFilenameWithPrefix(oBaseFileName, pTemplate.Name, "xml")
' Save the filename to the document
pDocument.FilenameExport = oFileName
RaiseEvent WebServiceProgress(Me, "Dateien schreiben")
' --- Prepare URL and HTTP Client
Dim oTemplateType = 30
Dim oTemplateName = pDocument.Schema.Name
Dim oKey = $"{pDocument.Account.Id}-{pDocument.RunningNumber}"
' ActionCode: Should this be a test or not?
' 0 = Test call
' 1 = Real call
Dim oActionCode = 1
If pIsTest = True Then
oActionCode = 0
End If
Dim oURL As String = $"{oWS.BaseUrl}/ewlservice/export?User={oWS.Username}&Password={oWS.Password}&Company={pMandator.Id}&Type={oTemplateType}&Vorlage={oTemplateName}&ActionCode={oActionCode}&Key={oKey}"
Dim oClient As New HttpClient()
Logger.Info("Creating HTTP Request to [{0}]", oWS.BaseUrl)
RaiseEvent WebServiceProgress(Me, "Anfrage absenden")
' --- Bring the action!
Try
Dim oResponse As HttpResponseMessage = Await oClient.GetAsync(oURL)
Await HandleExportResponse(oResponse, pDocument, pTemplate, pMandator, oBaseFileName)
Return True
Catch ex As Exception
Logger.Error(ex)
Throw ex
Finally
oClient.Dispose()
End Try
End Function
Private Async Function HandleExportResponse(pResponse As HttpResponseMessage, pDocument As Entities.ExportDocument, pTemplate As Template, pMandator As Mandator, pBaseFileName As String) As Task
pResponse.EnsureSuccessStatusCode()
Dim oResponseBody As String = Await pResponse.Content.ReadAsStringAsync()
Dim oContentType = pResponse.Content.Headers.ContentType.MediaType
Dim oSerializer = Serializer.GetSerializer(GetType(Templates.Entities.MESOWebServiceResult))
RaiseEvent WebServiceProgress(Me, "Antwort verarbeiten")
oResponseBody = ApplyItemFunctionsForExport(pDocument, pTemplate, pMandator, oResponseBody)
Select Case oContentType
Case "text/xml"
' Webservice
WriteResponseFile(pTemplate.OutputWebserviceDirectory, oResponseBody, $"{pTemplate.Name}-{pBaseFileName}-Response.xml")
' XML
WriteResponseFile(pTemplate.OutputXmlFileDirectory, oResponseBody, $"{pTemplate.Name}-{pBaseFileName}.xml")
' Archive
WriteResponseFile(FileEx.CreateDateDirectory(pTemplate.ArchiveDirectory), oResponseBody, $"{pTemplate.Name}-{pBaseFileName}.xml")
Case "text/html"
WriteResponseFile(pTemplate.OutputWebserviceDirectory, oResponseBody, $"{pTemplate.Name}-{pBaseFileName}-Response.txt")
Throw New ApplicationException(oResponseBody)
Case Else
Throw New ApplicationException(oResponseBody)
End Select
End Function
Private Function ApplyItemFunctionsForExport(pDocument As Entities.ExportDocument, pTemplate As Template, pMandator As Mandator, oResponseBody As String) As String
Dim oDoc As New XmlDocument()
oDoc.LoadXml(oResponseBody)
For Each oTable In pTemplate.Tables
For Each oItem As Template.Column In oTable.Columns
Dim oTableName As String = oTable.Name
Dim oItemName As String = oItem.Name
If oItem.Config.Function Is Nothing Then
Continue For
End If
Dim oFunction = oItem.Config.Function.Name
Dim oPath = $"//MESOWebService/{oTableName}/{oItemName}"
Dim oNodes As XmlNodeList = oDoc.SelectNodes(oPath)
For Each oNode As XmlNode In oNodes
If oItem.Config.Function.Name = "GLN" Then
Dim oGLN = Winline.TryGetGLN(oNode.InnerText, pMandator)
If oGLN Is Nothing Then
Throw New Exceptions.MissingAttributeException("GLN")
End If
oNode.InnerText = oGLN
ElseIf oItem.Config.Function.Name = "EAN" Then
Dim oEAN = Winline.TryGetEAN(oNode.InnerText, pMandator)
If oEAN Is Nothing Then
Throw New Exceptions.MissingAttributeException("EAN")
End If
oNode.InnerText = oEAN
ElseIf oItem.Config.Function.Name = "SQL" Then
Dim oSQL = Patterns.ReplaceForExport(pDocument, pMandator, oItem.Config.Function.Params)
Dim oValue = Database.GetScalarValue(oSQL)
If oValue Is Nothing Then
Throw New Exceptions.MissingAttributeException("SQL")
End If
oNode.InnerText = oValue
End If
Next
Next
Next
Dim oArray As Byte()
Using oStream As New IO.MemoryStream
oDoc.Save(oStream)
oArray = oStream.ToArray()
End Using
Dim oXml = Text.Encoding.UTF8.GetString(oArray)
oResponseBody = oXml
Return oResponseBody
End Function
#End Region
Private Function WriteResponseFileWithSuffix(pPath As String, pBaseFileName As String, pResponseBody As String, pExtension As String, pSuffix As String) As Boolean
Try
Dim oRequestFileName As String = FileEx.GetFilenameWithSuffix(pBaseFileName, pSuffix, pExtension)
Dim oFilePath As String = IO.Path.Combine(pPath, oRequestFileName)
IO.File.WriteAllText(oFilePath, pResponseBody)
Return True
Catch ex As Exception
Logger.Error(ex)
Return False
End Try
End Function
Private Function WriteResponseFileWithPrefix(pPath As String, pBaseFileName As String, pResponseBody As String, pExtension As String, pPrefix As String) As Boolean
Try
Dim oRequestFileName As String = FileEx.GetFilenameWithPrefix(pBaseFileName, pPrefix, pExtension)
Dim oFilePath As String = IO.Path.Combine(pPath, oRequestFileName)
IO.File.WriteAllText(oFilePath, pResponseBody)
Return True
Catch ex As Exception
Logger.Error(ex)
Return False
End Try
End Function
Private Function WriteResponseFile(pPath As String, pResponseBody As String, pFileName As String) As Boolean
Try
Dim oFilePath As String = IO.Path.Combine(pPath, pFileName)
IO.File.WriteAllText(oFilePath, pResponseBody)
Return True
Catch ex As Exception
Logger.Error(ex)
Return False
End Try
End Function
End Class
End Namespace

View File

@@ -0,0 +1,881 @@
Imports DigitalData.Modules.Logging
Imports DigitalData.Modules.Database
Imports MultiTool.Common.Winline.Entities
Imports System.Text.RegularExpressions
Imports MultiTool.Common.Templates
Imports MultiTool.Common.Constants
Imports DigitalData.Modules.Language
Namespace Winline
Public Class WinlineData
Inherits BaseClass
Private ReadOnly Property Config As GeneralConfig
Private ReadOnly Property MandatorConfig As MandatorConfig
Private ReadOnly Property MappingConfig As MappingConfig
Private ReadOnly Property Patterns As Patterns
Public Property Articles As New List(Of Article)
Public Property Accounts As New List(Of Account)
Public Property Mandators As New List(Of Mandator)
Public Property DocumentKinds As New List(Of DocumentKind)
Public Property Years As List(Of Integer)
Public Sub New(pLogConfig As LogConfig, pDatabase As MSSQLServer, pConfig As GeneralConfig, pMappingConfig As MappingConfig, pMandatorConfig As MandatorConfig)
MyBase.New(pLogConfig, pDatabase)
Patterns = New Patterns(pLogConfig, pConfig)
Config = pConfig
MandatorConfig = pMandatorConfig
MappingConfig = pMappingConfig
End Sub
Public Enum DocumentType
Undefined
OutgoingOffer
OutgoingOrder
OutgoingDeliveryNote
OutgoingInvoice
IncomingOffer
IncomingOrder
IncomingDeliveryNote
IncomingInvoice
End Enum
Public Class GetDocumentArgs
Public Property Account As Account
Public Property Kinds As List(Of DocumentKind)
Public Property DateFrom As Date
Public Property DateTo As Date
Public Property DocNumberFrom As String
Public Property DocNumberTo As String
Public Property ShowExported As Boolean
Public Property Year As Integer
End Class
Public Async Function LoadArticles(pMandator As Mandator) As Task
Logger.Info("Loading Articles for Mandator [{0}]", pMandator)
Dim oYear = Config.GetWinLineYear()
Try
Dim oSQL = $"
SELECT DISTINCT
[c002], -- Artikelnummer
[c003], -- Bezeichnung
[c075] -- EAN
FROM [{pMandator.Server}].[{pMandator.Database}].[dbo].[v021]
WHERE
mesocomp = '{pMandator.Id}'
AND mesoyear = {oYear}"
Dim oTable = Await Database.GetDatatableAsync(oSQL)
Dim oArticles As New List(Of Article)
For Each oRow As DataRow In oTable.Rows
Dim oArticleId As String = ItemEx(oRow, V21_ARTICLENUMBER, String.Empty)
Dim oArticleDescription As String = ItemEx(oRow, V21_ARTICLEDESCRIPTION, String.Empty)
Dim oEAN As String = ItemEx(oRow, V21_EAN, String.Empty)
oArticles.Add(New Article With {
.Id = oArticleId,
.Name = oArticleDescription,
.EAN = oEAN,
.Mandator = pMandator
})
Next
Articles.AddRange(oArticles)
Logger.Info("[{0}] Articles loaded for Mandator [{1}]", oArticles.Count, pMandator)
Catch ex As Exception
Logger.Warn("Could not load Articles for Mandator [{0}]", pMandator)
Logger.Error(ex)
End Try
End Function
Public Async Function LoadAccounts(pMandator As Mandator) As Task
Logger.Info("Loading Accounts for Mandator [{0}]", pMandator)
Dim oYear = Config.GetWinLineYear()
Try
Dim oSQL = $"
SELECT DISTINCT
[c002], -- Kundennummer
[c003], -- Kundenname
[c050], -- Straße
[c052], -- Ort
[c051], -- PLZ
[c260] -- GLN
FROM [{pMandator.Server}].[{pMandator.Database}].[dbo].[v050]
WHERE
c139 IS NULL
AND mesocomp = '{pMandator.Id}'
AND mesoyear = {oYear}"
Dim oTable = Await Database.GetDatatableAsync(oSQL)
Dim oAccounts As New List(Of Account)
For Each oRow As DataRow In oTable.Rows
Dim oAccountNumber As String = ItemEx(oRow, V50_ACCOUNTNUMBER, String.Empty)
Dim oAccountName As String = ItemEx(oRow, V50_ACCOUNTNAME, String.Empty)
Dim oStreetName As String = ItemEx(oRow, V50_STREETNAME, String.Empty)
Dim oZipCode As String = ItemEx(oRow, V50_ZIPCODE, String.Empty)
Dim oCityName As String = ItemEx(oRow, V50_CITYNAME, String.Empty)
Dim oGLN As String = ItemEx(oRow, V50_GLN, String.Empty)
oAccounts.Add(New Account With {
.Id = oAccountNumber,
.Name = oAccountName,
.StreetName = oStreetName,
.ZipCode = oZipCode,
.CityName = oCityName,
.GLN = oGLN,
.Mandator = pMandator
})
Next
Accounts.AddRange(oAccounts)
If oAccounts.Count = 0 Then
Logger.Warn("No Accounts loaded for Mandator [{0}]", pMandator)
End If
Logger.Info("[{0}] Accounts loaded for Mandator [{1}]", oAccounts.Count, pMandator)
Catch ex As Exception
Logger.Warn("Could not load Accounts for Mandator [{0}]", pMandator)
Logger.Error(ex)
End Try
End Function
Public Async Function LoadMandators() As Task
Try
Dim oSQL = "SELECT [c000], [c003], [c004] FROM [cwlsystem].[dbo].[T001SRV] (NOLOCK)"
Dim oTable = Await Database.GetDatatableAsync(oSQL)
Mandators.Clear()
For Each oRow As DataRow In oTable.Rows
Dim oDbInfo = SplitConnectionInfo(oRow)
Dim oMandator = New Mandator With {
.Id = ItemEx(oRow, T01_MANDATORID, String.Empty),
.Name = ItemEx(oRow, T01_MANDATORNAME, String.Empty),
.Database = oDbInfo.Item1,
.Server = oDbInfo.Item2
}
Dim oMandatorConfig As MandatorConfigItem = MandatorConfig.Items.
Where(Function(item) item.Name = oMandator.Id).
SingleOrDefault()
If oMandatorConfig IsNot Nothing Then
oMandator.IsWhitelisted = True
oMandator.Order = oMandatorConfig.OrderKey
End If
Mandators.Add(oMandator)
Next
Logger.Info("[{0}] Mandators loaded", Mandators.Count)
Catch ex As Exception
Logger.Warn("Could not load Mandators")
Logger.Error(ex)
End Try
End Function
Public Sub LoadEconomicYears()
Dim oCurrentYear = Now.Year
Dim oRange As IEnumerable(Of Integer) = Enumerable.Range(oCurrentYear - 10, 12).ToList()
Years = oRange
End Sub
Public Async Function LoadDocumentKinds(pMandator As Mandator) As Task
Dim oYear As Integer = Config.GetWinLineYear()
Try
' TODO: This is Schaum specific, maybe move to config later
Dim oSQL = $"
SELECT
[c030],
[c001],
[mesocomp]
FROM [{pMandator.Database}].[dbo].[t357] (NOLOCK)
WHERE (
[c001] LIKE 'Werk%(VK)' OR
[c001] LIKE 'Werk%(WK)'
)
AND [mesocomp] = '{pMandator.Id}' AND [mesoyear] = {oYear}"
Dim oTable As DataTable = Await Database.GetDatatableAsync(oSQL)
Dim oKinds As New List(Of DocumentKind)
For Each oRow As DataRow In oTable.Rows
oKinds.Add(New DocumentKind With {
.Id = ItemEx(oRow, T357_KINDID, String.Empty),
.Name = ItemEx(oRow, T357_KINDNAME, String.Empty),
.Mandator = pMandator
})
Next
DocumentKinds.AddRange(oKinds)
Logger.Info("[{0}] DocumentKinds loaded for [{1}]", Mandators.Count, pMandator)
Catch ex As Exception
Logger.Warn("Could not load DocumentKinds")
Logger.Error(ex)
End Try
End Function
Public Function TryGetAccount(pGLN As String, pMandator As Mandator) As Account
Return TryGetAccount(pGLN, pMandator, "c260", String.Empty)
End Function
Public Function TryGetAccount(pGLN As String, pMandator As Mandator, pSearchField As String) As Account
Return TryGetAccount(pGLN, pMandator, pSearchField, String.Empty)
End Function
Public Function TryGetAccount(pIdentifier As String, pMandator As Mandator, pSearchField As String, pAlternativeField As String) As Account
Try
If pIdentifier Is Nothing OrElse pIdentifier = String.Empty Then
Return Nothing
End If
Dim oYear As Integer = Config.GetWinLineYear()
Dim oSQL = $"
SELECT
[c002], -- Kundennummer
[c003], -- Kundenname
[c050], -- Straße
[c052], -- Ort
[c051], -- PLZ
* -- Everything else
FROM [{pMandator.Database}].[dbo].[v050]
WHERE [c004] IN (2, 3) -- KontoTyp Debitor/Kreditor
AND [{pSearchField}] = '{pIdentifier}'
AND [mesocomp] = '{pMandator.Id}' and [mesoyear] = {oYear}"
Dim oTable As DataTable = Database.GetDatatable(oSQL)
' GLN not found in this Mandator, continue to next one
If oTable.Rows.Count = 0 Then
Logger.Debug("GLN [{0}] was not found in Mandator: [{1}]", pIdentifier, pMandator.Id)
Return Nothing
End If
' Duplicate GLN, exit and do nothing about this number
If oTable.Rows.Count > 1 Then
Logger.Warn("GLN [{0}] was found more than once in Mandator: [{1}]", pIdentifier, pMandator.Id)
Return Nothing
End If
Dim oRow As DataRow = oTable.Rows.Item(0)
Dim oAccountNumber As String = ItemEx(oRow, V50_ACCOUNTNUMBER, String.Empty)
Dim oAccountName As String = ItemEx(oRow, V50_ACCOUNTNAME, String.Empty)
Dim oStreetName As String = ItemEx(oRow, V50_STREETNAME, String.Empty)
Dim oZipCode As String = ItemEx(oRow, V50_ZIPCODE, String.Empty)
Dim oCityName As String = ItemEx(oRow, V50_CITYNAME, String.Empty)
If pAlternativeField <> String.Empty Then
Dim oAlternativeValue = ItemEx(oRow, pAlternativeField, String.Empty)
If oAlternativeValue <> String.Empty Then
Return TryGetAccount(oAlternativeValue, pMandator, "c002")
End If
End If
Return New Account With {
.Id = oAccountNumber,
.Name = oAccountName,
.StreetName = oStreetName,
.CityName = oCityName,
.ZipCode = oZipCode,
.Mandator = pMandator
}
Catch ex As Exception
Logger.Warn("Error while trying to get account for GLN [{0}]", pIdentifier)
Logger.Error(ex)
Return Nothing
End Try
End Function
Public Function TryGetGLN(pAccountId As String, pMandator As Mandator) As String
Try
If pAccountId Is Nothing OrElse pAccountId = String.Empty Then
Return Nothing
End If
Dim oYear As Integer = Config.GetWinLineYear()
Dim oSQL = $"
SELECT
[c260] -- GLN
FROM [{pMandator.Database}].[dbo].[v050]
WHERE [c004] IN (2, 3) -- KontoTyp Debitor/Kreditor
AND [c002] = '{pAccountId}'
AND [mesocomp] = '{pMandator.Id}' and [mesoyear] = {oYear}"
Dim oGLN As String = Database.GetScalarValue(oSQL)
' GLN not found in this Mandator, continue to next one
If oGLN Is Nothing Then
Logger.Debug("Account [{0}] was not found in Mandator: [{1}]", pAccountId, pMandator.Id)
Return Nothing
End If
Return oGLN
Catch ex As Exception
Logger.Warn("Error while trying to get GLN for Account [{0}]", pAccountId)
Logger.Error(ex)
Return Nothing
End Try
End Function
Public Async Function TryGetArticlePrice(pArticle As String, pAccountNumber As String, pQuantity As String, pDocumentDate As Date, pMandator As Mandator, pTemplate As Template) As Task(Of Double)
Return Await TryGetArticlePrice(pArticle, pAccountNumber, pQuantity, pDocumentDate, pMandator, pTemplate, 0)
End Function
Public Async Function TryGetArticlePrice(pArticle As String, pAccountNumber As String, pQuantity As String, pDocumentDate As Date, pMandator As Mandator, pTemplate As Template, pWaitingDays As Integer) As Task(Of Double)
Try
Dim oUserName = Environment.UserName
Dim oYear As Integer = Config.GetWinLineYear()
Dim oDebug = Convert.ToInt32(LogConfig.Debug)
' TODO: pGroupPropertyID in config
' TODO: pTempTableSuffix in config (nice to have)
Dim oDateFrom = pDocumentDate.AddDays(pWaitingDays * -1)
Dim oDateTo = pDocumentDate
Dim oSQL As String = $"
EXEC [{pMandator.Database}].[dbo].[PRCUST_GET_ACCOUNT_PRICE_CONDITION_VALUES]
@pAccountNr = '{pAccountNumber}',
@pGroupNr = '*',
@pProductNr = '{pArticle}',
@pProductQuantity = '<={pQuantity}',
@pProductPriceDateFrom = '{oDateFrom:dd.MM.yyyy}',
@pProductPriceDateTo = '{oDateTo:dd.MM.yyyy}',
@pmesocomp = '{pMandator.Id}',
@pmesoyear = {oYear},
@pGroupPropertyID = 1008,
@pTempTableSuffix = 'MT_USER_{oUserName}',
@pBatchID = NULL,
@pPrintDebug = 0,
@pLog2DB = {oDebug},
@pComment = 'Multitool/{pTemplate.Name}',
@pResultType = 'CalcPricing'
"
Dim oTable As DataTable = Await Database.GetDatatableAsync(oSQL)
If oTable.Rows.Count = 0 Then
Logger.Debug("Price for article [{0}] and Account [{1}] was not found in Mandator: [{2}]", pArticle, pAccountNumber, pMandator.Id)
Return Nothing
End If
Dim oRow As DataRow = oTable.Rows.Item(0)
Dim oPrice As Double = oRow.Item("PRICE")
Return oPrice
Catch ex As Exception
Logger.Warn("Error while trying to get Price for Article [{0}] and Account [{1}]", pArticle, pAccountNumber)
Logger.Error(ex)
Return Nothing
End Try
End Function
''' <summary>
''' This function is completely SCHAUM related.
''' </summary>
Public Async Function TryGetWaitingDays(pDocumentKind As Integer, pMandator As Mandator) As Task(Of Integer)
Try
Dim oSql = $"
SELECT [Karenztage].[u012] FROM [{pMandator.Database}].[dbo].[t670] As [Werksdefinition]
INNER JOIN [{pMandator.Database}].[dbo].[t670] AS [Werkszuordnung] ON [Werksdefinition].[u007] = [Werkszuordnung].[u007]
INNER JOIN [{pMandator.Database}].[dbo].[t670] AS [Karenztage] ON [Werksdefinition].[u000] = [Karenztage].[u032]
WHERE [Werksdefinition].[u011] In ({pDocumentKind},{pDocumentKind}*10)
AND [Werkszuordnung].[u006] = '%ConditionAccountNr%'
AND [Karenztage].[u002] = 'Karenztage'
"
Dim oWaitingDays As Integer = Await Database.GetScalarValueAsync(oSql)
If IsNothing(oWaitingDays) Then
oWaitingDays = 0
End If
Return oWaitingDays
Catch ex As Exception
Logger.Error(ex)
Return 0
End Try
End Function
Public Function TryGetArticleNumber(pEAN As String, pMandator As Mandator) As String
Try
Dim oYear As Integer = Config.GetWinLineYear()
Dim oSQL As String = $"
SELECT
[c011], -- Artikelnummer
[c003], -- Artikelbezeichnung
[c075], -- EAN-Nummer
[c123] -- Ersatzartikelnummer
FROM [{pMandator.Database}].[dbo].[v021]
WHERE [c075] = '{pEAN}'
AND [mesocomp] = '{pMandator.Id}' AND [mesoyear] = {oYear}"
Dim oTable As DataTable = Database.GetDatatable(oSQL)
' EAN not found in this Mandator, continue to next one
If oTable.Rows.Count = 0 Then
Logger.Debug("EAN [{0}] was not found in Mandator: [{1}]", pEAN, pMandator.Id)
Return Nothing
End If
' Duplicate EAN, exit and do nothing about this number
If oTable.Rows.Count > 1 Then
Logger.Warn("EAN [{0}] was found more than once", pEAN)
Return Nothing
End If
Dim oRow As DataRow = oTable.Rows.Item(0)
Dim oArticleNumber As String = ItemEx(oRow, V21_MAINARTICLENUMBER, String.Empty)
Return oArticleNumber
Catch ex As Exception
Logger.Error(ex)
Return Nothing
End Try
End Function
Public Function TryGetEAN(pArticleNumber As String, pMandator As Mandator) As String
Try
Dim oYear As Integer = Config.GetWinLineYear()
Dim oSQL As String = $"
SELECT
[c075] -- EAN-Nummer
FROM [{pMandator.Database}].[dbo].[v021]
WHERE [c011] = '{pArticleNumber}'
AND [mesocomp] = '{pMandator.Id}' AND [mesoyear] = {oYear}"
Dim oEAN As String = Database.GetScalarValue(oSQL)
' EAN not found in this Mandator, continue to next one
If oEAN Is Nothing Then
Logger.Debug("ArticleNumber [{0}] was not found in Mandator: [{1}]", pArticleNumber, pMandator.Id)
Return Nothing
End If
Return oEAN
Catch ex As Exception
Logger.Error(ex)
Return Nothing
End Try
End Function
Public Function GetContacts(pAccountNumber As String, pMandator As Mandator) As List(Of Contact)
Try
Dim oContacts As New List(Of Contact)
Dim oYear As Integer = Config.GetWinLineYear()
Dim oSQL As String = $"
SELECT
[c000], -- Key
[c001], -- Name
[c063] -- Kontaktnummer
FROM [{pMandator.Database}].[dbo].[t045]
WHERE [c063] LIKE '{pAccountNumber}-%'
AND [mesocomp] = '{pMandator.Id}' AND [mesoyear] = {oYear}"
Dim oTable As DataTable = Database.GetDatatable(oSQL)
' Contact not found in this Mandator, continue to next one
If oTable.Rows.Count = 0 Then
Logger.Debug("Contact for Account [{0}] was not found in Mandator: [{1}]", pAccountNumber, pMandator.Id)
Return Nothing
End If
For Each oRow In oTable.Rows
oContacts.Add(New Contact With {
.Id = ItemEx(Of String)(oRow, T45_KEY, Nothing),
.Name = ItemEx(Of String)(oRow, T45_NAME, Nothing),
.Number = ItemEx(Of String)(oRow, T45_CONTACTNUMBER, Nothing)
})
Next
Return oContacts
Catch ex As Exception
Logger.Error(ex)
Return Nothing
End Try
End Function
Public Function GetReplacementArticleNumber(pArticleNumber As String, pMandator As Mandator)
Try
Dim oYear As Integer = Config.GetWinLineYear()
Dim oSQL As String = $"
SELECT
[c011], -- Artikelnummer
[c003], -- Artikelbezeichnung
[c075], -- EAN-Nummer
[c123] -- Ersatzartikelnummer
FROM [{pMandator.Database}].[dbo].[v021]
WHERE [c011] = '{pArticleNumber}'
AND [mesocomp] = '{pMandator.Id}' AND [mesoyear] = {oYear}"
Dim oTable As DataTable = Database.GetDatatable(oSQL)
' ArticleNumber not found in this Mandator, continue to next one
If oTable.Rows.Count = 0 Then
Logger.Debug("ArticleNumber [{0}] was not found in Mandator: [{1}]", pArticleNumber, pMandator.Id)
Return Nothing
End If
' Duplicate EAN, exit and do nothing about this number
If oTable.Rows.Count > 1 Then
Logger.Warn("ArticleNumber [{0}] was found more than once", pArticleNumber)
Return Nothing
End If
Dim oRow As DataRow = oTable.Rows.Item(0)
Dim oReplacementArticleNumber = ItemEx(Of String)(oRow, V21_REPLACEMENTARTICLENUMBER, Nothing)
If oReplacementArticleNumber Is Nothing Then
Return pArticleNumber
End If
Return GetReplacementArticleNumber(oReplacementArticleNumber, pMandator)
Catch ex As Exception
Logger.Error(ex)
Return Nothing
End Try
End Function
Public Function FindMatchingMandatorFromOrder(pData As Documents.Document) As Mandator
Dim oPositions = pData.Rows.
Where(Function(r) r.TableName.ToUpper.EndsWith("T026")).
ToList()
Dim oEANNumbers = oPositions.
Select(Function(p)
If p.Fields.ContainsKey("Artikelnummer") Then
Return p.Fields.Item("Artikelnummer").Original
Else
Return Nothing
End If
End Function).
Where(Function(ean) ean IsNot Nothing).
Distinct().
ToList()
Dim oYear = Config.GetWinLineYear()
Dim oMandatorId As String = String.Empty
Dim oWhitelistedMandators = Mandators.
Where(Function(m) m.IsWhitelisted = True).
OrderBy(Function(m) m.Order).
ToList()
For Each oEANNumber In oEANNumbers
For Each oMandator In oWhitelistedMandators
Dim oSQL As String = $"
SELECT
[c011], -- Artikelnummer
[c003], -- Artikelbezeichnung
[c075], -- EAN-Nummer
[c123] -- Ersatzartikelnummer
FROM [{oMandator.Database}].[dbo].[v021]
WHERE [c075] = '{oEANNumber}'
AND [mesocomp] = '{oMandator.Id}' AND [mesoyear] = {oYear}"
Dim oTable As DataTable = Database.GetDatatable(oSQL)
' EAN not found in this Mandator, continue to next one
If oTable.Rows.Count = 0 Then
Logger.Debug("EAN [{0}] was not found in Mandator: [{1}]", oEANNumber, oMandator.Id)
Continue For
End If
' Duplicate EAN, exit and do nothing about this manda
If oTable.Rows.Count > 1 Then
Logger.Warn("EAN [{0}] was found more than once. Skipping Mandator [{1}]", oEANNumber, oMandator.Id)
Exit For
End If
Dim oRow As DataRow = oTable.Rows.Item(0)
Dim oArticleNumber As String = ItemEx(oRow, V21_MAINARTICLENUMBER, String.Empty)
' EAN was found, now we need to check it against the Regex of the current Mandantor, if one exists
Dim oMappingConfigItems = MappingConfig.Items.
Where(Function(item) item.DestinationName = "MANDATOR" And item.DestinationValue = oMandator.Id And item.SourceName = "ARTICLE").
ToList()
' If not match was found, continune to next mandator.
' For a catch all mandator, a regex like ".+" is needed.
For Each oItem In oMappingConfigItems
Try
Dim oRegex As New Regex(oItem.SourceRegex)
Dim oMatch = oRegex.Match(oArticleNumber)
' If ArticleNumber matches the regex, we assign it and exit
If oMatch.Success Then
Return oMandator
Else
' If it does not match, continue to the next mandator
End If
Catch ex As Exception
Logger.Error(ex)
Logger.Warn("Regex [{0}] could not be parsed. Skipping.", oMandator.Regex)
End Try
Next ' CONFIG ITEM
Next ' MANDATOR
Next ' EAN
Return Nothing
End Function
Public Function GetDocuments(pMandator As Mandator, pTemplate As Template, pDocumentType As DocumentType, pOptions As GetDocumentArgs) As List(Of ExportDocument)
Try
Dim oYear As Integer = Config.GetWinLineYear()
If pOptions.Year > 0 Then
oYear = Config.GetWinLineYear(pOptions.Year)
End If
Dim oTypeConstraint
Select Case pDocumentType
Case DocumentType.OutgoingOffer
oTypeConstraint = $"T.c137 = 2 AND c139 = 1 AND "
Case DocumentType.OutgoingOrder
oTypeConstraint = $"T.c137 = 2 AND c139 = 2 AND "
Case DocumentType.OutgoingDeliveryNote
oTypeConstraint = $"T.c137 = 2 AND (c139 = 3 OR c139 = -3) AND "
Case DocumentType.OutgoingInvoice
oTypeConstraint = $"T.c137 = 2 AND c139 = 4 AND "
Case DocumentType.IncomingOffer
oTypeConstraint = $"T.c137 = 3 AND c139 = 1 AND "
Case DocumentType.IncomingOrder
oTypeConstraint = $"T.c137 = 3 AND c139 = 2 AND "
Case DocumentType.IncomingDeliveryNote
oTypeConstraint = $"T.c137 = 3 AND c139 = 3 AND "
Case DocumentType.IncomingInvoice
oTypeConstraint = $"T.c137 = 3 AND c139 = 4 AND "
Case Else
oTypeConstraint = ""
End Select
Dim oAccountConstraint = ""
If pOptions.Account IsNot Nothing Then
oAccountConstraint = $"T.c021 = '{pOptions.Account.Id}' AND "
End If
Dim oKindConstraint = ""
If pOptions.Kinds IsNot Nothing AndAlso pOptions.Kinds.Count > 0 Then
Dim oKindIdList = pOptions.Kinds.Select(Function(kind) kind.Id)
Dim oKindIdString = String.Join(",", oKindIdList)
oKindConstraint = $"T.c035 IN ({oKindIdString}) AND "
End If
Dim oDateFromConstraint = ""
If pOptions.DateFrom <> Date.MinValue Then
oDateFromConstraint = $"T2.DATE >= CAST('{pOptions.DateFrom:yyyy-MM-dd}' as date) AND "
End If
Dim oDateToConstraint = ""
If pOptions.DateTo <> Date.MinValue Then
oDateToConstraint = $"T2.DATE <= CAST('{pOptions.DateTo:yyyy-MM-dd}' as date) AND "
End If
Dim oDocNumberConstraint = ""
If pOptions.DocNumberFrom <> String.Empty Then
oDocNumberConstraint &= $"T.c044 >= '{pOptions.DocNumberFrom}' AND "
End If
If pOptions.DocNumberTo <> String.Empty Then
oDocNumberConstraint &= $"T.c044 <= '{pOptions.DocNumberTo}' AND "
End If
' Build the constraint so that the default view will show all documents that do not have an exported
' flag set to the current document type.
' Ex. Search for orders will not show exported flag = 2 by default
Dim oDocType As Integer = Math.Abs(Convert.ToInt32(pDocumentType))
Dim oExportedConstraint = $"(T.U010 IS NULL OR T.U010 <> {oDocType}) AND"
If pOptions.ShowExported Then
oExportedConstraint = ""
End If
Dim oSql = $"
SELECT
T2.DATE,
T.c139 DOCUMENT_TYPE,
T.c035 DOCUMENT_KIND,
T.c021 ACCOUNT_NUMBER,
T.c022 RUNNING_NUMBER,
T.c043 OFFER_NUMBER,
T.c027 OFFER_DATE,
T.c044 ORDER_NUMBER,
T.c028 ORDER_DATE,
T.c045 DELIVERY_NUMBER,
T.c029 DELIVERY_DATE,
T.c055 INVOICE_NUMBER,
T.c032 INVOICE_DATE,
T.c100 GROSS_AMOUNT,
T.c114 NET_AMOUNT,
T.U010 ALREADY_EXPORTED,
T.U011 EXPORTED_WHO,
T.U012 EXPORTED_WHEN,
T.U013 EXPORTED_FILE
FROM [{pMandator.Database}].[dbo].[T025] T
INNER JOIN (SELECT * FROM (
SELECT c021, c022, mesoyear, mesocomp, c027 [DATE] FROM [{pMandator.Database}].[dbo].[T025]
WHERE c139 = 1 OR c139 = -1
UNION
SELECT c021, c022, mesoyear, mesocomp, c028 [DATE] FROM [{pMandator.Database}].[dbo].[T025]
WHERE c139 = 2 OR c139 = -2
UNION
SELECT c021, c022, mesoyear, mesocomp, c029 [DATE] FROM [{pMandator.Database}].[dbo].[T025]
WHERE c139 = 3 OR c139 = -3
UNION
SELECT c021, c022, mesoyear, mesocomp, c032 [DATE] FROM [{pMandator.Database}].[dbo].[T025]
WHERE c139 = 4 OR c139 = -4
) QUERY) T2 ON T.c021 = T2.c021 AND T.c022 = T2.c022 AND T.mesoyear = T2.mesoyear AND T.mesocomp = T2.mesocomp
WHERE
{oTypeConstraint}
{oAccountConstraint}
{oKindConstraint}
{oExportedConstraint}
{oDocNumberConstraint}
{oDateFromConstraint}
{oDateToConstraint}
T.[mesocomp] = '{pMandator.Id}' AND T.[mesoyear] = {oYear}"
Dim oTable As DataTable = Database.GetDatatable(oSql)
Dim oDocuments As New List(Of ExportDocument)
For Each oRow As DataRow In oTable.Rows
Try
Dim oDocument = GetDocumentFromDataRow(oRow)
oDocument.Schema = pTemplate
oDocuments.Add(oDocument)
Catch ex As Exception
Logger.Error(ex)
End Try
Next
Return oDocuments
Catch ex As Exception
Logger.Warn("Error while loading documents for mandator [{0}] and document type [{1}]", pMandator, pDocumentType)
Logger.Error(ex)
Return Nothing
End Try
End Function
Public Async Function ExecuteFinalSQL(pDocument As ExportDocument, pTemplate As Template, pMandator As Mandator) As Task(Of Boolean)
Try
Dim oSql As String = Patterns.ReplaceForExport(pDocument, pMandator, pTemplate.FinalSQL)
Return Await Database.ExecuteNonQueryAsync(oSql)
Catch ex As Exception
Logger.Error(ex)
Return False
End Try
End Function
Private Function GetDocumentFromDataRow(pDataRow As DataRow) As ExportDocument
Dim oAccountNumber = pDataRow.Item("ACCOUNT_NUMBER")
Dim oRunningNumber As String = pDataRow.Item("RUNNING_NUMBER")
Dim oDocumentType As Integer = pDataRow.Item("DOCUMENT_TYPE")
Dim oDocumentKind As Integer = pDataRow.Item("DOCUMENT_KIND")
Dim oGrossAmount As Double = pDataRow.Item("GROSS_AMOUNT")
Dim oNetAmount As Double = pDataRow.Item("NET_AMOUNT")
Dim oExported As Boolean = pDataRow.ItemEx("ALREADY_EXPORTED", False)
Dim oExportedWho As String = pDataRow.ItemEx("EXPORTED_WHO", "")
Dim oExportedWhen As Date = pDataRow.ItemEx(Of Date)("EXPORTED_WHEN", Nothing)
Dim oExportFile As String = pDataRow.ItemEx("EXPORTED_FILE", "")
Dim oDocumentNumber As String = Nothing
Dim oDocumentDate As Date = Nothing
Dim oDocumentDateColumn As String = Nothing
Dim oAccount = Accounts.
Where(Function(acc) acc.Id = oAccountNumber).
FirstOrDefault()
Dim oKind = DocumentKinds.
Where(Function(kind) kind.Id = oDocumentKind).
FirstOrDefault()
Select Case oDocumentType
Case 1
oDocumentNumber = pDataRow.Item("OFFER_NUMBER")
oDocumentDate = pDataRow.Item("OFFER_DATE")
oDocumentDateColumn = "c027"
Case 2
oDocumentNumber = pDataRow.Item("ORDER_NUMBER")
oDocumentDate = pDataRow.Item("ORDER_DATE")
oDocumentDateColumn = "c028"
Case 3
oDocumentNumber = pDataRow.Item("DELIVERY_NUMBER")
oDocumentDate = pDataRow.Item("DELIVERY_DATE")
oDocumentDateColumn = "c029"
Case 4
oDocumentNumber = pDataRow.Item("INVOICE_NUMBER")
oDocumentDate = pDataRow.Item("INVOICE_DATE")
oDocumentDateColumn = "c032"
End Select
Dim oDocument As New ExportDocument With {
.Account = oAccount,
.RunningNumber = oRunningNumber,
.Number = oDocumentNumber,
.[Date] = oDocumentDate,
.DateColumn = oDocumentDateColumn,
.Kind = oKind,
.GrossAmount = oGrossAmount,
.NetAmount = oNetAmount,
.IsExported = oExported,
.ExportedWhen = oExportedWhen,
.ExportedWho = oExportedWho,
.FilenameExport = oExportFile
}
Return oDocument
End Function
''' <summary>
''' Turns a database info like "SQLCWLDATEN on SERVER\INSTANCE" into a Tuple of two strings
''' </summary>
''' <param name="pRow"></param>
''' <returns></returns>
Private Function SplitConnectionInfo(pRow As DataRow) As Tuple(Of String, String)
Dim oDbInfo = pRow.Item(T01_DATABASEINFO).ToString()
Dim oSplittedInfo = SplitAtString(oDbInfo.ToUpper, "ON")
Dim oServer = oSplittedInfo.Item(1).Trim()
Dim oDatabase = oSplittedInfo.Item(0).Trim()
If oDatabase.StartsWith("SQL") Then
oDatabase = oDatabase.Remove(0, 3)
End If
Return New Tuple(Of String, String)(oDatabase, oServer)
End Function
Private Function SplitAtString(pStringToSplit As String, pDelimiter As String) As List(Of String)
Dim oDelimiter As String() = New String(0) {pDelimiter}
Return pStringToSplit.
Split(oDelimiter, StringSplitOptions.None).
ToList()
End Function
End Class
End Namespace

View File

@@ -0,0 +1,43 @@
Imports DigitalData.Modules.Logging
Public Class XmlData
<DebuggerStepThrough>
Public Shared Function GetElementAttribute(pElement As XElement, pName As String) As String
Try
Dim oAttribute As XAttribute = pElement.Attribute(pName)
Return oAttribute?.Value
Catch ex As Exception
Return Nothing
End Try
End Function
Public Shared Function GetElementsFromElement(pElement As XContainer, pElementName As String) As List(Of XElement)
Return pElement.Descendants(pElementName).
Elements().
ToList()
End Function
Public Shared Function GetElementsFromElement(pElement As XContainer, pElementName As String, pNamespace As XNamespace) As List(Of XElement)
Return pElement.Descendants(pNamespace + pElementName).
Elements().
ToList()
End Function
Public Shared Function GetElement(pContainer As XContainer, pElementName As String, pNamespace As XNamespace) As XElement
Return pContainer.Descendants(pNamespace + pElementName).
FirstOrDefault()
End Function
Public Shared Function GetElement(pContainer As XContainer, pElementName As String) As XElement
Return pContainer.Descendants(pElementName).
FirstOrDefault()
End Function
Public Shared Function GetElementValue(pElement As XElement) As String
Return pElement.Value
End Function
End Class

View File

@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="AutoMapper" version="10.1.1" targetFramework="net461" />
<package id="NLog" version="4.7.10" targetFramework="net461" />
</packages>