Improve Error handling across the board

This commit is contained in:
Jonathan Jenne
2022-04-26 12:02:00 +02:00
parent 13af72dee5
commit 3e41502766
19 changed files with 404 additions and 141 deletions

View File

@@ -65,22 +65,13 @@ Namespace Documents
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)
FilesLoaded = Files.Count
Logger.Info("Loading file [{0}]", oFile.Name)
Dim oDocument = Await LoadFile(oFile, pTemplate, pMandator)
Files.Add(oDocument)
FilesLoaded = Files.Count
Dim oInfo As New FileLoadInfo(FilesTotal, FilesLoaded)
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
Dim oInfo As New FileLoadInfo(FilesTotal, FilesLoaded)
RaiseEvent FileLoadComplete(Me, oInfo)
Next
Return True
@@ -93,20 +84,52 @@ Namespace Documents
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)
Logger.Debug("Creating new Document object for file [{0}]", pFileInfo.Name)
Dim oDocument As Document = New Document With {
.File = pFileInfo,
.Schema = pTemplate
}
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()
oDocument = LoadDocumentData(oDocument, pTemplate, TemplateConfig)
Catch ex As Exception
Logger.Error(ex)
Throw ex
Logger.Error(ex)
End Try
Try
oDocument = Await MatchDataFromWinLine(oDocument, Winline.Mandators, pMandator, pTemplate)
Catch ex As Exception
Throw ex
Logger.Error(ex)
End Try
Try
oDocument = MarkRequiredFields(oDocument)
Catch ex As Exception
Throw ex
Logger.Error(ex)
End Try
Return oDocument
End Function
Public Function MarkRequiredFields(pDocument As Document) As Document
For Each oRow In pDocument.Rows
For Each oField In oRow.Fields
If oField.Value.Final = String.Empty And oField.Value.IsRequired Then
oField.Value.AddFieldError(FieldErrorType.MissingValue, $"Attribut '{oField.Key}' ist ein Pflichtfeld, wurde aber nicht gefüllt.")
End If
Next
Next
Return pDocument
End Function
Public Sub ReplaceDocument(pDocument As Document)
@@ -154,27 +177,27 @@ Namespace Documents
Dim oRootElement As XElement = XmlData.GetElement(oDoc, "MESOWebService")
If oRootElement Is Nothing Then
Throw New MalformedXmlException("Datei enthält kein MESOWebService-Element")
pDocument.AddDocumentError(DocumentErrorType.MissingXmlAttribute, "Datei enthält kein MESOWebService-Attribut")
End If
Dim oTemplateName = XmlData.GetElementAttribute(oRootElement, "Template")
If oTemplateName Is Nothing Then
Throw New MalformedXmlException("Datei enthält kein Template-Attribut")
pDocument.AddDocumentError(DocumentErrorType.MissingXmlAttribute, "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")
pDocument.AddDocumentError(DocumentErrorType.MissingXmlAttribute, "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")
pDocument.AddDocumentError(DocumentErrorType.MissingXmlAttribute, "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")
pDocument.AddDocumentError(DocumentErrorType.MissingXmlAttribute, "Datei enthält kein printVoucher-Attribut")
End If
' The first level of Elements are the document Rows
@@ -227,16 +250,18 @@ Namespace Documents
Else
Logger.Debug("Creating new field from Configuration: [{0}]", oColumn.Name)
Dim oColumnError = FieldError.None
If oColumn.Config?.IsRequired Then
oColumnError = FieldError.MissingValue
End If
oFields.Add(oColumn.Name, New DocumentRow.FieldValue With {
.[Error] = oColumnError,
Dim oValue = New DocumentRow.FieldValue With {
.SortKey = oColumnSortKey,
.IsVirtual = oColumn.Config.IsVirtual
})
}
'oValue.Error = FieldErrorType.None
If oColumn.Config?.IsRequired Then
'oValue.Error = FieldErrorType.MissingValue
oValue.AddFieldError(FieldErrorType.MissingValue, $"Attribut {oSubElement.Name} wird benötigt, ist aber nicht gefüllt.")
End If
oFields.Add(oColumn.Name, oValue)
End If
oColumnSortKey += 1
@@ -282,6 +307,9 @@ Namespace Documents
If oMandator Is Nothing Then
Logger.Warn("Mandator not found for File [{0}]", pDocument.File.Name)
' Without mandator, we just exit, life is meaningless.
pDocument.AddDocumentError(DocumentErrorType.MandatorNotFound, "Mandant nicht gefunden. Verarbeitung wurde abgebrochen.")
Else
' Set mandator befor applying any functions that depend on a valid mandator
pDocument.Mandator = oMandator
@@ -290,7 +318,7 @@ Namespace Documents
.RunningFunction = "Winline-Funktionen"
})
pDocument = ApplyDefinedItemFunctionsForImport(pDocument, oMandator, pTemplate)
pDocument = Await ApplyDefinedItemFunctionsForImportAsync(pDocument, oMandator, pTemplate)
pDocument = ApplyDynamicItemFunctionsForImport(pDocument, oMandator)
RaiseEvent FileLoadProgress(Me, New FileLoadProgressInfo(FilesTotal, FilesLoaded) With {
@@ -355,7 +383,7 @@ Namespace Documents
Return pDocument
End Function
Private Function ApplyDefinedItemFunctionsForImport(pDocument As Document, pMandator As Mandator, pTemplate As Template) As Document
Private Async Function ApplyDefinedItemFunctionsForImportAsync(pDocument As Document, pMandator As Mandator, pTemplate As Template) As Task(Of Document)
For Each oRow As DocumentRow In pDocument.Rows
Dim oTable = pTemplate.Tables.Where(Function(table) table.Name = oRow.TableName).SingleOrDefault()
@@ -373,14 +401,17 @@ Namespace Documents
Dim oFunctionParams = oColumn.Config.FunctionParams
Dim oParamsDict = ParseFunctionParamsAsDict(oFunctionParams)
If oFunctionName = Constants.FUNCTION_GLN Then
If oFunctionName = FUNCTION_GLN Then
SetAccountByGLN(oRow, pMandator, oField.Key, Nothing, oParamsDict)
End If
If oFunctionName = Constants.FUNCTION_EAN Then
If oFunctionName = FUNCTION_EAN Then
SetArticleByEAN(oRow, pMandator, oField.Key)
End If
If oFunctionName = FUNCTION_RUNNINGNUMBER Then
Await SetVersionedRunningNumber(pDocument, oRow, pMandator, oField.Key, oParamsDict)
End If
Next
Next
@@ -481,9 +512,7 @@ Namespace Documents
pDocument.Rows.
SelectMany(Function(row) row.Fields).
Where(Function(field) field.Key = oMapping.DestinationItem).
SetValue(Sub(field)
field.Value.Final = oMapping.DestinationValue
End Sub)
SetValue(Sub(field) field.Value.Final = oMapping.DestinationValue)
Else
' don't do anything
@@ -494,12 +523,12 @@ Namespace Documents
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
Private Async Function SetPrice(pRow As DocumentRow, pPriceField As String, pParamMap 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
Const PARAMETER_ARTICLE = "Article"
Dim oArticleNumberField As String = oFieldMap.GetOrDefault(PARAMETER_ARTICLE, Nothing)
Dim oArticleNumberField As String = pParamMap.GetOrDefault(PARAMETER_ARTICLE, Nothing)
If oArticleNumberField Is Nothing Then
Logger.Warn("Parameter '{0}' not found for Function PRICE", PARAMETER_ARTICLE)
End If
@@ -510,7 +539,7 @@ Namespace Documents
Dim oArticleNumber As String = pRow.Fields.Item(oArticleNumberField).Final
Const PARAMETER_QUANTITY = "Quantity"
Dim oQuantityField As String = oFieldMap.GetOrDefault(PARAMETER_QUANTITY, Nothing)
Dim oQuantityField As String = pParamMap.GetOrDefault(PARAMETER_QUANTITY, Nothing)
If oQuantityField Is Nothing Then
Logger.Warn("Parameter '{0}' not found for Function PRICE", PARAMETER_QUANTITY)
End If
@@ -521,13 +550,13 @@ Namespace Documents
End If
' These fields a fetched from the head row, ie. the first row
Dim oAccountNumberField As String = oFieldMap.GetOrDefault("Account", Nothing)
Dim oAccountNumberField As String = pParamMap.GetOrDefault("Account", Nothing)
Dim oAccountNumber = pDocument.GetFieldValue(oAccountNumberField)
Dim oDocumentDateField As String = oFieldMap.GetOrDefault("DocumentDate", Nothing)
Dim oDocumentDateField As String = pParamMap.GetOrDefault("DocumentDate", Nothing)
Dim oDocumentDate = pDocument.GetFieldValue(oDocumentDateField)
Dim oDocumentKindField As String = oFieldMap.GetOrDefault("DocumentKind", Nothing)
Dim oDocumentKindField As String = pParamMap.GetOrDefault("DocumentKind", Nothing)
Dim oDocumentKind As Integer = 0
If Integer.TryParse(pDocument.GetFieldValue(oDocumentKindField), oDocumentKind) = False Then
Logger.Warn("Value for parameter DocumentKind could not be parsed. Setting to 0.")
@@ -538,10 +567,10 @@ Namespace Documents
' 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)
Dim oWaitingDays As Integer = Await Winline.TryGetWaitingDaysAsync(oDocumentKind, pMandator)
' END TODO
Dim oArticlePrice As Double = Await Winline.TryGetArticlePrice(oArticleNumber, oAccountNumber, oQuantity, oDocumentDate, pMandator, pTemplate, oWaitingDays)
Dim oArticlePrice As Double = Await Winline.TryGetArticlePriceAsync(oArticleNumber, oAccountNumber, oQuantity, oDocumentDate, pMandator, pTemplate, oWaitingDays)
If oArticlePrice > 0 Then
oPriceItem.External = oArticlePrice
@@ -559,7 +588,8 @@ Namespace Documents
oNumberItem.External = oArticleNumber
oNumberItem.Final = oArticleNumber
Else
oNumberItem.Error = FieldError.ArticleNotFound
'oNumberItem.Error = FieldErrorType.ArticleNotFound
oNumberItem.AddFieldError(FieldErrorType.ArticleNotFound, $"EAN in Attribut '{pArticleField}' konnte nicht aufgelöst werden.")
End If
End Sub
@@ -597,7 +627,8 @@ Namespace Documents
' If no account was found and the field is required,
' mark it as error. Otherwise, do nothing.
If oNumberItem.IsRequired Then
oNumberItem.Error = FieldError.AccountNotFound
'oNumberItem.Error = FieldErrorType.AccountNotFound
oNumberItem.AddFieldError(FieldErrorType.AccountNotFound, $"GLN in Attribut '{pNumberField}' konnte nicht aufgelöst werden.")
End If
End If
Catch ex As Exception
@@ -606,9 +637,31 @@ Namespace Documents
End Try
End Sub
Private Function WrapFileInfo(pFileInfo As FileInfo) As Document
Logger.Debug("Creating new Document object for file [{0}]", pFileInfo.Name)
Return New Document With {.File = pFileInfo}
Public Async Function SetVersionedRunningNumber(pDocument As Document, pRow As DocumentRow, pMandator As Mandator, pRunningNumberField As String, pParams As Dictionary(Of String, String)) As Task
Try
Const PARAMETER_ACCOUNT = "Account"
Dim oAccountField As String = pParams.GetOrDefault(PARAMETER_ACCOUNT, Nothing)
If oAccountField Is Nothing Then
Logger.Warn("Parameter '{0}' not found for Function RUNNINGNUMBER", PARAMETER_ACCOUNT)
End If
Dim oRunningNumberItem As DocumentRow.FieldValue = pRow.Fields.GetOrDefault(pRunningNumberField)
Dim oRunningNumber = oRunningNumberItem.Final
Dim oAccountNumberItem As DocumentRow.FieldValue = pRow.Fields.GetOrDefault(oAccountField)
Dim oAccountNumber = oAccountNumberItem.Final
Dim oVersionedNumber = Await Winline.GetVersionedRunningNumberAsync(pDocument, pMandator, oAccountNumber, oRunningNumber)
If oVersionedNumber <> oRunningNumber Then
oRunningNumberItem.External = oVersionedNumber
oRunningNumberItem.Final = oVersionedNumber
End If
Catch ex As Exception
Logger.Error(ex)
Throw ex
End Try
End Function
Private Function ParseFunctionParamsAsDict(pParams As String) As Dictionary(Of String, String)