Rename Shared to Common
This commit is contained in:
17
MultiTool.Common/BaseClass.vb
Normal file
17
MultiTool.Common/BaseClass.vb
Normal 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
|
||||
8
MultiTool.Common/Config.vb
Normal file
8
MultiTool.Common/Config.vb
Normal 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
|
||||
63
MultiTool.Common/Constants.vb
Normal file
63
MultiTool.Common/Constants.vb
Normal 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
|
||||
75
MultiTool.Common/Documents/Document.vb
Normal file
75
MultiTool.Common/Documents/Document.vb
Normal 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
|
||||
40
MultiTool.Common/Documents/DocumentCleaner.vb
Normal file
40
MultiTool.Common/Documents/DocumentCleaner.vb
Normal 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
|
||||
539
MultiTool.Common/Documents/DocumentLoader.vb
Normal file
539
MultiTool.Common/Documents/DocumentLoader.vb
Normal 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
|
||||
93
MultiTool.Common/Documents/DocumentRow.vb
Normal file
93
MultiTool.Common/Documents/DocumentRow.vb
Normal 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
|
||||
8
MultiTool.Common/Documents/DocumentType.vb
Normal file
8
MultiTool.Common/Documents/DocumentType.vb
Normal 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
|
||||
76
MultiTool.Common/Exceptions.vb
Normal file
76
MultiTool.Common/Exceptions.vb
Normal 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
|
||||
22
MultiTool.Common/IDictionaryEx.vb
Normal file
22
MultiTool.Common/IDictionaryEx.vb
Normal 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
|
||||
12
MultiTool.Common/IEnumerableEx.vb
Normal file
12
MultiTool.Common/IEnumerableEx.vb
Normal 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
|
||||
146
MultiTool.Common/ImporterShared.vbproj.bak
Normal file
146
MultiTool.Common/ImporterShared.vbproj.bak
Normal 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
127
MultiTool.Common/Mapper.vb
Normal 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
|
||||
180
MultiTool.Common/MultiTool.Common.vbproj
Normal file
180
MultiTool.Common/MultiTool.Common.vbproj
Normal 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>
|
||||
175
MultiTool.Common/MultiTool.Shared.vbproj.bak
Normal file
175
MultiTool.Common/MultiTool.Shared.vbproj.bak
Normal 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>
|
||||
13
MultiTool.Common/My Project/Application.Designer.vb
generated
Normal file
13
MultiTool.Common/My Project/Application.Designer.vb
generated
Normal 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
|
||||
|
||||
10
MultiTool.Common/My Project/Application.myapp
Normal file
10
MultiTool.Common/My Project/Application.myapp
Normal 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>
|
||||
35
MultiTool.Common/My Project/AssemblyInfo.vb
Normal file
35
MultiTool.Common/My Project/AssemblyInfo.vb
Normal 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")>
|
||||
63
MultiTool.Common/My Project/Resources.Designer.vb
generated
Normal file
63
MultiTool.Common/My Project/Resources.Designer.vb
generated
Normal 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
|
||||
117
MultiTool.Common/My Project/Resources.resx
Normal file
117
MultiTool.Common/My Project/Resources.resx
Normal 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>
|
||||
73
MultiTool.Common/My Project/Settings.Designer.vb
generated
Normal file
73
MultiTool.Common/My Project/Settings.Designer.vb
generated
Normal 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
|
||||
7
MultiTool.Common/My Project/Settings.settings
Normal file
7
MultiTool.Common/My Project/Settings.settings
Normal 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>
|
||||
122
MultiTool.Common/Patterns.vb
Normal file
122
MultiTool.Common/Patterns.vb
Normal 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
|
||||
129
MultiTool.Common/Report/ReportGenerator.vb
Normal file
129
MultiTool.Common/Report/ReportGenerator.vb
Normal 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
|
||||
23
MultiTool.Common/Report/ReportHead.vb
Normal file
23
MultiTool.Common/Report/ReportHead.vb
Normal 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
|
||||
|
||||
27
MultiTool.Common/Report/ReportPosition.vb
Normal file
27
MultiTool.Common/Report/ReportPosition.vb
Normal 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
|
||||
18
MultiTool.Common/Report/ReportSource.vb
Normal file
18
MultiTool.Common/Report/ReportSource.vb
Normal 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
|
||||
31
MultiTool.Common/Serializer.vb
Normal file
31
MultiTool.Common/Serializer.vb
Normal 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
|
||||
35
MultiTool.Common/Templates/GeneralConfig.vb
Normal file
35
MultiTool.Common/Templates/GeneralConfig.vb
Normal 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
|
||||
5
MultiTool.Common/Templates/MandatorConfig.vb
Normal file
5
MultiTool.Common/Templates/MandatorConfig.vb
Normal file
@@ -0,0 +1,5 @@
|
||||
Namespace Templates
|
||||
Public Class MandatorConfig
|
||||
Public Property Items As New List(Of MandatorConfigItem)
|
||||
End Class
|
||||
End Namespace
|
||||
7
MultiTool.Common/Templates/MandatorConfigItem.vb
Normal file
7
MultiTool.Common/Templates/MandatorConfigItem.vb
Normal file
@@ -0,0 +1,7 @@
|
||||
Namespace Templates
|
||||
Public Class MandatorConfigItem
|
||||
Public Property Name As String
|
||||
Public Property OrderKey As Integer
|
||||
End Class
|
||||
|
||||
End Namespace
|
||||
12
MultiTool.Common/Templates/MappingConfig.vb
Normal file
12
MultiTool.Common/Templates/MappingConfig.vb
Normal 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
|
||||
12
MultiTool.Common/Templates/MappingConfigItem.vb
Normal file
12
MultiTool.Common/Templates/MappingConfigItem.vb
Normal 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
|
||||
97
MultiTool.Common/Templates/Template.vb
Normal file
97
MultiTool.Common/Templates/Template.vb
Normal 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
|
||||
|
||||
17
MultiTool.Common/Templates/TemplateConfig.vb
Normal file
17
MultiTool.Common/Templates/TemplateConfig.vb
Normal 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
|
||||
59
MultiTool.Common/Templates/TemplateConfigItem.vb
Normal file
59
MultiTool.Common/Templates/TemplateConfigItem.vb
Normal 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
|
||||
352
MultiTool.Common/Templates/TemplateLoader.vb
Normal file
352
MultiTool.Common/Templates/TemplateLoader.vb
Normal 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
|
||||
25
MultiTool.Common/Winline/Entities/Account.vb
Normal file
25
MultiTool.Common/Winline/Entities/Account.vb
Normal 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
|
||||
21
MultiTool.Common/Winline/Entities/Article.vb
Normal file
21
MultiTool.Common/Winline/Entities/Article.vb
Normal 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
|
||||
12
MultiTool.Common/Winline/Entities/Contact.vb
Normal file
12
MultiTool.Common/Winline/Entities/Contact.vb
Normal 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
|
||||
19
MultiTool.Common/Winline/Entities/DocumentKind.vb
Normal file
19
MultiTool.Common/Winline/Entities/DocumentKind.vb
Normal 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
|
||||
28
MultiTool.Common/Winline/Entities/ExportDocument.vb
Normal file
28
MultiTool.Common/Winline/Entities/ExportDocument.vb
Normal 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
|
||||
23
MultiTool.Common/Winline/Entities/Mandator.vb
Normal file
23
MultiTool.Common/Winline/Entities/Mandator.vb
Normal 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
|
||||
128
MultiTool.Common/Winline/Entities/Response.vb
Normal file
128
MultiTool.Common/Winline/Entities/Response.vb
Normal 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
|
||||
402
MultiTool.Common/Winline/WebServiceData.vb
Normal file
402
MultiTool.Common/Winline/WebServiceData.vb
Normal 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
|
||||
881
MultiTool.Common/Winline/WinlineData.vb
Normal file
881
MultiTool.Common/Winline/WinlineData.vb
Normal 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
|
||||
43
MultiTool.Common/XmlData.vb
Normal file
43
MultiTool.Common/XmlData.vb
Normal 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
|
||||
5
MultiTool.Common/packages.config
Normal file
5
MultiTool.Common/packages.config
Normal 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>
|
||||
Reference in New Issue
Block a user