379 lines
15 KiB
VB.net
379 lines
15 KiB
VB.net
Imports System.Reflection
|
|
Imports System.Text.RegularExpressions
|
|
Imports DigitalData.Modules.Logging
|
|
|
|
Public Class PropertyValues
|
|
Private _logger As Logger
|
|
Private _logConfig As LogConfig
|
|
|
|
Private _indexPattern = "\((\d+)\)"
|
|
Private _indexRegex As New Regex(_indexPattern)
|
|
|
|
Public Sub New(LogConfig As LogConfig)
|
|
_logConfig = LogConfig
|
|
_logger = LogConfig.GetLogger()
|
|
End Sub
|
|
|
|
Public Class CheckPropertyValuesResult
|
|
Public MissingProperties As New List(Of MissingProperty)
|
|
Public ValidProperties As New List(Of ValidProperty)
|
|
End Class
|
|
|
|
Public Class ValidProperty
|
|
Public MessageId As String
|
|
Public TableName As String
|
|
Public TableColumn As String
|
|
|
|
Public IsRequired As Boolean
|
|
Public GroupCounter As Integer = -1
|
|
|
|
Public Description As String
|
|
Public Value As String
|
|
Public XMLPath As String
|
|
|
|
Public ItemType As Integer = 0
|
|
End Class
|
|
|
|
Public Class MissingProperty
|
|
Public Description As String
|
|
Public XMLPath As String
|
|
|
|
Public Overrides Function ToString() As String
|
|
Return XMLPath
|
|
End Function
|
|
End Class
|
|
|
|
Public Function CheckPropertyValues(pDocument As Object, PropertyMap As Dictionary(Of String, XmlItemProperty), MessageId As String) As CheckPropertyValuesResult
|
|
Dim oGlobalGroupCounter = 0
|
|
Dim oMissingProperties As New List(Of String)
|
|
Dim oResult As New CheckPropertyValuesResult()
|
|
|
|
' PropertyMap items with `IsGrouped = False` are handled normally
|
|
Dim oDefaultProperties As Dictionary(Of String, XmlItemProperty) = PropertyMap.
|
|
Where(Function(Item) Item.Value.IsGrouped = False).
|
|
ToDictionary(Function(Item) Item.Key,
|
|
Function(Item) Item.Value)
|
|
|
|
_logger.Debug("Found {0} default properties.", oDefaultProperties.Count)
|
|
|
|
' PropertyMap items with `IsGrouped = True` are grouped by group scope
|
|
Dim oGroupedProperties = PropertyMap.
|
|
Where(Function(Item) Item.Value.IsGrouped = True).
|
|
ToLookup(Function(Item) Item.Value.GroupScope, ' Lookup key is group scope
|
|
Function(Item) Item)
|
|
|
|
_logger.Debug($"Found [{PropertyMap.Count - oDefaultProperties.Count}] properties grouped in [{oGroupedProperties.Count}] group(s)")
|
|
' Iterate through groups to get group scope and group items
|
|
For Each oGroup In oGroupedProperties
|
|
Dim oGroupScope As String = oGroup.Key
|
|
|
|
Dim oPropertyList As New Dictionary(Of XmlItemProperty, List(Of Object))
|
|
Dim oRowCount = 0
|
|
|
|
_logger.Debug($"Fetching Property values for group [{oGroupScope}].")
|
|
|
|
' get properties as a nested object, see `oPropertyList`
|
|
For Each oProperty As KeyValuePair(Of String, XmlItemProperty) In oGroup
|
|
Dim oPropertyValues As List(Of Object)
|
|
_logger.Debug($"Fetching value for itemSpecification [{oProperty.Value.TableColumn}].")
|
|
Try
|
|
oPropertyValues = GetPropValue(pDocument, oProperty.Key)
|
|
Catch ex As Exception
|
|
_logger.Warn($"{MessageId} - Unknown error occurred while fetching property/TColumn [{0}] in group [{1}]:", oProperty.Value.TableColumn, oGroupScope)
|
|
_logger.Error(ex)
|
|
oPropertyValues = New List(Of Object)
|
|
End Try
|
|
|
|
' Flatten result value
|
|
oPropertyValues = GetFinalPropValue(oPropertyValues)
|
|
|
|
' Add to list
|
|
oPropertyList.Add(oProperty.Value, oPropertyValues)
|
|
|
|
' check the first batch of values to determine the row count
|
|
If oRowCount = 0 Or oGroupScope = "POSITIONS" Then '08.04.2025 MS Added as Workaround for Positions!
|
|
oRowCount = oPropertyValues.Count
|
|
End If
|
|
Next
|
|
|
|
' Structure of oPropertyList
|
|
' [ # Propertyname # Row 1 # Row 2
|
|
' PositionsMenge: [BilledQuantity1, BilledQuantity2, ...],
|
|
' PositionsSteuersatz: [ApplicablePercent1, ApplicablePercent2, ...],
|
|
' ...
|
|
' ]
|
|
For oRowIndex = 0 To oRowCount - 1
|
|
_logger.Debug("Processing row {0}", oRowIndex)
|
|
|
|
For Each oColumn As KeyValuePair(Of XmlItemProperty, List(Of Object)) In oPropertyList
|
|
Dim oTableName As String = oColumn.Key.TableName
|
|
Dim oTableColumn As String = oColumn.Key.TableColumn
|
|
Dim oIsRequired As Boolean = oColumn.Key.IsRequired
|
|
Dim oPropertyDescription As String = oColumn.Key.Description
|
|
Dim oPropertyPath As String = oColumn.Key.XMLPath
|
|
Dim oItemType As Integer = oColumn.Key.ItemType
|
|
|
|
Dim oRowCounter = oRowIndex + oGlobalGroupCounter + 1
|
|
|
|
' Returns nothing if oColumn.Value contains an empty list
|
|
Dim oPropertyValue = oColumn.Value.ElementAtOrDefault(oRowIndex)
|
|
|
|
_logger.Debug("Processing itemSpecification *TableColumn* [{0}].", oTableColumn)
|
|
If oTableColumn = "INVOICE_SELLER_EMAIL" Then
|
|
Console.WriteLine("INVOICE_SELLER_EMAIL")
|
|
ElseIf oTableColumn = "INVOICE_POSITION_ARTICLE" Then
|
|
Console.WriteLine("INVOICE_POSITION_ARTICLE")
|
|
End If
|
|
If IsNothing(oPropertyValue) OrElse String.IsNullOrEmpty(oPropertyValue) Then
|
|
If oColumn.Key.IsRequired Then
|
|
_logger.Warn($"{MessageId} # oPropertyValue for specification [{oTableColumn}] is empty or not found but is required. Continuing with Empty String.")
|
|
Dim oMissingProperty = New MissingProperty() With {
|
|
.Description = oPropertyDescription,
|
|
.XMLPath = oPropertyPath
|
|
}
|
|
oResult.MissingProperties.Add(oMissingProperty)
|
|
Else
|
|
_logger.Debug($"{MessageId} # oPropertyValue for specification [{oTableColumn}] is empty or not found. Continuing with Empty String.")
|
|
End If
|
|
|
|
oPropertyValue = String.Empty
|
|
End If
|
|
|
|
_logger.Debug("ItemSpecification [{0}] has value '{1}'", oTableColumn, oPropertyValue)
|
|
|
|
oResult.ValidProperties.Add(New ValidProperty() With {
|
|
.MessageId = MessageId,
|
|
.Description = oPropertyDescription,
|
|
.Value = oPropertyValue,
|
|
.GroupCounter = oRowCounter,
|
|
.TableName = oTableName,
|
|
.TableColumn = oTableColumn,
|
|
.IsRequired = oIsRequired,
|
|
.XMLPath = oPropertyPath,
|
|
.ItemType = oItemType
|
|
})
|
|
Next
|
|
Next
|
|
|
|
oGlobalGroupCounter += oRowCount
|
|
Next
|
|
|
|
' Iterate through default properties
|
|
For Each oItem As KeyValuePair(Of String, XmlItemProperty) In oDefaultProperties
|
|
Dim oPropertyValueList As List(Of Object)
|
|
Dim oTableColumn As String = oItem.Value.TableColumn
|
|
Dim oPropertyDescription As String = oItem.Value.Description
|
|
Dim oPropertyPath As String = oItem.Value.XMLPath
|
|
Dim oPropertyValue As Object = Nothing
|
|
Dim oTableName = oItem.Value.TableName
|
|
Dim oIsRequired = oItem.Value.IsRequired
|
|
Dim oDescription = oItem.Value.Description
|
|
Dim oItemType = oItem.Value.ItemType
|
|
|
|
Try
|
|
oPropertyValueList = GetPropValue(pDocument, oItem.Key)
|
|
Catch ex As Exception
|
|
_logger.Warn("{2} # Unknown error occurred while fetching specification [{0}] in group [{1}]:", oPropertyDescription, oItem.Value.GroupScope, MessageId)
|
|
_logger.Warn("ERROR-MESSAGE [{0}]", ex.Message)
|
|
_logger.Error(ex)
|
|
oPropertyValueList = New List(Of Object)
|
|
End Try
|
|
|
|
Try
|
|
If IsNothing(oPropertyValueList) Then
|
|
oPropertyValue = Nothing
|
|
ElseIf TypeOf oPropertyValueList Is List(Of Object) Then
|
|
Select Case oPropertyValueList.Count
|
|
Case 0
|
|
oPropertyValue = Nothing
|
|
Case Else
|
|
Dim oList As List(Of Object) = DirectCast(oPropertyValueList, List(Of Object))
|
|
oPropertyValue = oList.Item(0)
|
|
|
|
' This should hopefully show config errors
|
|
If TypeOf oPropertyValue Is List(Of Object) Then
|
|
_logger.Warn("Item with specification [{0}] may be configured incorrectly", oPropertyDescription)
|
|
oPropertyValue = Nothing
|
|
End If
|
|
End Select
|
|
End If
|
|
Catch ex As Exception
|
|
_logger.Warn("Unknown error occurred while processing specification [{0}]:", oPropertyDescription)
|
|
_logger.Error(ex)
|
|
oPropertyValue = Nothing
|
|
End Try
|
|
|
|
If IsNothing(oPropertyValue) OrElse String.IsNullOrEmpty(oPropertyValue) Then
|
|
If oItem.Value.IsRequired Then
|
|
_logger.Warn("{0} # Specification [{1}] is empty, but marked as required! Skipping.", MessageId, oPropertyDescription)
|
|
Dim oMissingProperty = New MissingProperty With
|
|
{
|
|
.Description = oPropertyDescription,
|
|
.XMLPath = oPropertyPath
|
|
}
|
|
oResult.MissingProperties.Add(oMissingProperty)
|
|
Continue For
|
|
Else
|
|
_logger.Debug("{0} # oPropertyValue for specification [{1}] is empty or not found. Skipping.", MessageId, oPropertyDescription)
|
|
|
|
Continue For
|
|
End If
|
|
End If
|
|
|
|
' Statt dem Zahlenwert des Enums, wollen wir die Währunsgbezeichnung
|
|
If oTableColumn = "INVOICE_CURRENCY" Then
|
|
oPropertyValue = oPropertyValue.ToString()
|
|
End If
|
|
|
|
oResult.ValidProperties.Add(New ValidProperty() With {
|
|
.MessageId = MessageId,
|
|
.Description = oDescription,
|
|
.Value = oPropertyValue,
|
|
.TableName = oTableName,
|
|
.TableColumn = oTableColumn,
|
|
.IsRequired = oIsRequired,
|
|
.XMLPath = oPropertyPath,
|
|
.ItemType = oItemType
|
|
})
|
|
Next
|
|
|
|
Return oResult
|
|
End Function
|
|
|
|
Public Function GetPropValue(Obj As Object, PropertyName As String) As List(Of Object)
|
|
Dim oNameParts As String() = PropertyName.Split("."c)
|
|
|
|
If IsNothing(Obj) Then
|
|
_logger.Debug("`Obj` is Nothing. Exiting.")
|
|
Return New List(Of Object)
|
|
End If
|
|
|
|
If oNameParts.Length = 1 Then
|
|
Dim oPropInfo As PropertyInfo = Obj.GetType().GetProperty(PropertyName)
|
|
|
|
If IsNothing(oPropInfo) Then
|
|
_logger.Debug("Property [{0}] does not exist(1).", PropertyName)
|
|
Return New List(Of Object)
|
|
Else
|
|
Dim oPropValue = oPropInfo.GetValue(Obj, Nothing)
|
|
Return New List(Of Object) From {oPropValue}
|
|
End If
|
|
End If
|
|
|
|
For Each oPart As String In oNameParts
|
|
Dim oType As Type = Obj.GetType()
|
|
Dim oPartName = oPart
|
|
Dim oIndex As Integer = Nothing
|
|
Dim oHasIndex As Boolean = HasIndex(oPartName)
|
|
|
|
If oHasIndex Then
|
|
oPartName = StripIndex(oPart)
|
|
oIndex = GetIndex(oPart)
|
|
End If
|
|
|
|
Dim oInfo As PropertyInfo = oType.GetProperty(oPartName)
|
|
|
|
If IsNothing(oInfo) OrElse IsNothing(oInfo.GetValue(Obj, Nothing)) Then
|
|
_logger.Debug("Property [{0}] does not exist(2).", oPartName)
|
|
Return New List(Of Object)
|
|
End If
|
|
|
|
Obj = oInfo.GetValue(Obj, Nothing)
|
|
|
|
' TODO: This code should check for array properties by itself
|
|
' and should not rely on the user to
|
|
'If oInfo.PropertyType.IsArray Then
|
|
' Obj = Obj(0)
|
|
'End If
|
|
|
|
If oHasIndex Then
|
|
Obj = Obj(0)
|
|
End If
|
|
|
|
If IsArray(Obj) And Not oHasIndex Then
|
|
Dim oCurrentPart As String = oPart
|
|
Dim oSplitString As String() = New String() {oCurrentPart & "."}
|
|
Dim oPathFragments = PropertyName.Split(oSplitString, StringSplitOptions.None)
|
|
Dim oResults As New List(Of Object)
|
|
|
|
' if path has no more subitems, return an empty list
|
|
If oPathFragments.Length = 1 Then
|
|
Return oResults
|
|
End If
|
|
|
|
For Each oArrayItem In Obj
|
|
Dim oResult As List(Of Object) = GetPropValue(oArrayItem, oPathFragments(1))
|
|
|
|
If Not IsNothing(oResult) Then
|
|
oResults.Add(oResult)
|
|
End If
|
|
Next
|
|
|
|
Return oResults
|
|
End If
|
|
|
|
Next
|
|
|
|
Return New List(Of Object) From {Obj}
|
|
End Function
|
|
|
|
Public Function GetFinalPropValue(List As List(Of Object)) As List(Of Object)
|
|
Dim oResult As New List(Of Object)
|
|
|
|
For Each Item In List
|
|
Dim oItemValue = DoGetFinalPropValue(Item)
|
|
|
|
If Not IsNothing(oItemValue) Then
|
|
oResult.Add(oItemValue)
|
|
End If
|
|
Next
|
|
|
|
Return oResult
|
|
End Function
|
|
|
|
Private Function DoGetFinalPropValue(Value As Object) As String
|
|
If TypeOf Value Is List(Of Object) Then
|
|
Dim oList = DirectCast(Value, List(Of Object))
|
|
Dim oCount = oList.Count
|
|
|
|
Select Case oCount
|
|
Case 0
|
|
Return Nothing
|
|
Case Else
|
|
Return DoGetFinalPropValue(oList.First())
|
|
End Select
|
|
|
|
Return DoGetFinalPropValue(Value)
|
|
Else
|
|
' Nothing kann auch der Default-Wert der Variablen bedeuten. Also auch 0.00
|
|
If IsNothing(Value) Then
|
|
Return String.Empty
|
|
Else
|
|
Return Value.ToString
|
|
End If
|
|
|
|
End If
|
|
End Function
|
|
|
|
Private Function GetIndex(Prop As String) As Integer
|
|
If Regex.IsMatch(Prop, _indexPattern) Then
|
|
Dim oMatch = _indexRegex.Match(Prop)
|
|
Dim oGroup = oMatch.Groups.Item(1)
|
|
Dim oValue = oGroup.Value
|
|
|
|
Return Integer.Parse(oValue)
|
|
End If
|
|
|
|
Return Nothing
|
|
End Function
|
|
|
|
Private Function StripIndex(Prop As String) As String
|
|
Return Regex.Replace(Prop, _indexPattern, "")
|
|
End Function
|
|
|
|
Private Function HasIndex(Prop As String) As Boolean
|
|
Return Regex.IsMatch(Prop, _indexPattern)
|
|
End Function
|
|
|
|
End Class
|