Interfaces: Rewrite ValidateZugferdDocument, add validation for invalid decimals

This commit is contained in:
Jonathan Jenne 2023-06-21 13:09:11 +02:00
parent a19123dd03
commit a05156a1a6

View File

@ -39,6 +39,7 @@ Public Class ZUGFeRDInterface
UnsupportedFormat UnsupportedFormat
FileTooBig FileTooBig
UnknownError UnknownError
ValidationFailed
End Enum End Enum
Public ReadOnly Property FileGroup As FileGroups Public ReadOnly Property FileGroup As FileGroups
@ -54,6 +55,7 @@ Public Class ZUGFeRDInterface
Public Class ZugferdResult Public Class ZugferdResult
Public Property DataFileName As String Public Property DataFileName As String
Public Property XPathObject As XPathDocument Public Property XPathObject As XPathDocument
Public Property XElementObject As XElement
Public Property SchemaObject As Object Public Property SchemaObject As Object
Public Property Specification As String Public Property Specification As String
Public Property ValidationErrors As New List(Of ZugferdValidationError) Public Property ValidationErrors As New List(Of ZugferdValidationError)
@ -246,13 +248,22 @@ Public Class ZUGFeRDInterface
End If End If
Try Try
Dim oXPathObject As XPathDocument = Nothing
Using oStream As New MemoryStream(oAllowedResult.FileContents) Using oStream As New MemoryStream(oAllowedResult.FileContents)
Return New ZugferdResult With { oXPathObject = New XPathDocument(oStream)
.DataFileName = oAllowedResult.FileName,
.XPathObject = New XPathDocument(oStream)
}
End Using End Using
Dim oXElementObject As XElement = Nothing
Using oStream As New MemoryStream(oAllowedResult.FileContents)
oXElementObject = XElement.Load(oStream)
End Using
Return New ZugferdResult With {
.DataFileName = oAllowedResult.FileName,
.XElementObject = oXElementObject,
.XPathObject = oXPathObject
}
Catch ex As ZUGFeRDExecption Catch ex As ZUGFeRDExecption
' Don't log ZUGFeRD Exceptions here, they should be handled by the calling code. ' Don't log ZUGFeRD Exceptions here, they should be handled by the calling code.
' It also produces misleading error messages when checking if an attachment is a zugferd file. ' It also produces misleading error messages when checking if an attachment is a zugferd file.
@ -276,48 +287,67 @@ Public Class ZUGFeRDInterface
oNamespaceManager.AddNamespace("ram", "urn:un:unece:uncefact:data:standard:ReusableAggregateBusinessInformationEntity:12") oNamespaceManager.AddNamespace("ram", "urn:un:unece:uncefact:data:standard:ReusableAggregateBusinessInformationEntity:12")
oNamespaceManager.AddNamespace("rsm", "urn:ferd:CrossIndustryDocument:invoice:1p0") oNamespaceManager.AddNamespace("rsm", "urn:ferd:CrossIndustryDocument:invoice:1p0")
Try
Dim oDecimalNodes = pResult.XElementObject.Descendants().
Where(Function(n) n.Name.ToString.EndsWith("Amount") Or n.Name.ToString.EndsWith("Percent"))
For Each oNode As XElement In oDecimalNodes
Dim oParsedValue As Decimal = 0.0
If Decimal.TryParse(oNode.Value, oParsedValue) = False Then
pResult.ValidationErrors.Add(New ZugferdValidationError() With {
.ElementName = oNode.Name.LocalName,
.ElementValue = oNode.Value,
.ErrorMessage = "Value could not be parsed as Decimal"
})
End If
Next
Catch ex As Exception
_logger.Error(ex)
End Try
' CurrencyCode Nodes ' CurrencyCode Nodes
Try Try
Dim oCurrencyCodeIterator As XPathNodeIterator = oNavigator. Dim oCurrencyCodeNodes = pResult.XElementObject.Descendants().
Select("//ram:InvoiceCurrencyCode | //ram:TaxCurrencyCode | //ram:TaxCurrencyCode | //ram:SourceCurrencyCode", oNamespaceManager) Where(Function(n) n.Name.ToString.EndsWith("CurrencyCode"))
While oCurrencyCodeIterator.MoveNext() For Each oNode As XElement In oCurrencyCodeNodes
Dim oNode As XPathNavigator = oCurrencyCodeIterator.Current
Dim oValid = ValidateCurrencyCode(oNode.Value) Dim oValid = ValidateCurrencyCode(oNode.Value)
If oValid = False Then If oValid = False Then
pResult.ValidationErrors.Add(New ZugferdValidationError() With { pResult.ValidationErrors.Add(New ZugferdValidationError() With {
.ElementName = oNode.Name, .ElementName = oNode.Name.LocalName,
.ElementValue = oNode.Value, .ElementValue = oNode.Value,
.ErrorMessage = "Invalid CurrencyCode. Only 3-Character codes are allowed." .ErrorMessage = "Invalid CurrencyCode. Only 3-Character codes are allowed."
}) })
End If End If
End While Next
Catch ex As Exception Catch ex As Exception
_logger.Error(ex) _logger.Error(ex)
End Try End Try
' currencyID ' currencyID
Try Try
Dim oCurrencyIDIterator As XPathNodeIterator = oNavigator.Select("//*[@currencyID]") Dim oCurrencyIDNodes = pResult.XElementObject.Descendants().
Where(Function(n) n.Attributes.Any(Function(a) a.Name.LocalName = "currencyID"))
While oCurrencyIDIterator.MoveNext() For Each oNode As XElement In oCurrencyIDNodes
Dim oNode As XPathNavigator = oCurrencyIDIterator.Current Dim oCurrencyID As String = oNode.Attribute("currencyID")?.Value
Dim oCurrencyID As String = oNode.GetAttribute("currencyID", "")
' CurrencyID is optional per spec ' CurrencyID is optional per spec
If String.IsNullOrWhiteSpace(oCurrencyID) Then If String.IsNullOrWhiteSpace(oCurrencyID) Then
Continue While Continue For
End If End If
Dim oValid = ValidateCurrencyCode(oCurrencyID) Dim oValid = ValidateCurrencyCode(oCurrencyID)
If oValid = False Then If oValid = False Then
pResult.ValidationErrors.Add(New ZugferdValidationError() With { pResult.ValidationErrors.Add(New ZugferdValidationError() With {
.ElementName = oNode.Name, .ElementName = oNode.Name.LocalName,
.ElementValue = oCurrencyID, .ElementValue = oCurrencyID,
.ErrorMessage = "Invalid currencyID. Only 3-Character codes or empty values are allowed." .ErrorMessage = "Invalid currencyID. Only 3-Character codes or empty values are allowed."
}) })
End If End If
End While Next
Catch ex As Exception Catch ex As Exception
_logger.Error(ex) _logger.Error(ex)
End Try End Try