ZUGFeRD: Validate errors in xml and throw ValidationException
This commit is contained in:
@@ -15,6 +15,7 @@ Public Class ZUGFeRDInterface
|
||||
Private ReadOnly _logConfig As LogConfig
|
||||
Private ReadOnly _logger As Logger
|
||||
Private ReadOnly _Options As ZugferdOptions
|
||||
Private ReadOnly _Validator As Validator
|
||||
|
||||
' These constants define the specification markers for the different
|
||||
' zugferd document schema versions. These markers need to be used to
|
||||
@@ -39,7 +40,6 @@ Public Class ZUGFeRDInterface
|
||||
UnsupportedFormat
|
||||
FileTooBig
|
||||
UnknownError
|
||||
ValidationFailed
|
||||
End Enum
|
||||
|
||||
Public ReadOnly Property FileGroup As FileGroups
|
||||
@@ -54,7 +54,6 @@ Public Class ZUGFeRDInterface
|
||||
|
||||
Public Class ZugferdResult
|
||||
Public Property DataFileName As String
|
||||
Public Property XPathObject As XPathDocument
|
||||
Public Property XElementObject As XElement
|
||||
Public Property SchemaObject As Object
|
||||
Public Property Specification As String
|
||||
@@ -76,6 +75,7 @@ Public Class ZUGFeRDInterface
|
||||
Public Sub New(pLogConfig As LogConfig, pGDPictureKey As String, Optional pOptions As ZugferdOptions = Nothing)
|
||||
_logConfig = pLogConfig
|
||||
_logger = _logConfig.GetLogger()
|
||||
_Validator = New Validator(_logConfig)
|
||||
|
||||
If pOptions Is Nothing Then
|
||||
_Options = New ZugferdOptions()
|
||||
@@ -138,9 +138,11 @@ Public Class ZUGFeRDInterface
|
||||
Dim oResult = ValidateZUGFeRDFileWithGDPicture(Path)
|
||||
oResult = ValidateZUGFeRDDocument(oResult)
|
||||
|
||||
'If IsNothing(oResult.SchemaObject) Then
|
||||
Throw New ZUGFeRDExecption(ErrorType.NoZugferd, "Datei ist keine ZUGFeRD Datei.")
|
||||
'End If
|
||||
If oResult.ValidationErrors.Any() Then
|
||||
Throw New ValidationException() With {
|
||||
.ValidationErrors = oResult.ValidationErrors
|
||||
}
|
||||
End If
|
||||
|
||||
Return SerializeZUGFeRDDocument(oResult)
|
||||
End Function
|
||||
@@ -154,9 +156,16 @@ Public Class ZUGFeRDInterface
|
||||
Dim oResult = ValidateZUGFeRDFileWithGDPicture(Stream)
|
||||
oResult = ValidateZUGFeRDDocument(oResult)
|
||||
|
||||
'If IsNothing(oResult.SchemaObject) Then
|
||||
' Throw New ZUGFeRDExecption(ErrorType.NoZugferd, "Datei ist keine ZUGFeRD Datei.")
|
||||
'End If
|
||||
If oResult.ValidationErrors.Any() Then
|
||||
_logger.Info("Validation found [{0}] errors", oResult.ValidationErrors.Count)
|
||||
oResult.ValidationErrors.ForEach(
|
||||
Sub(e) _logger.Info("Field [{0}] with value [{1}] has error: [{2}]", e.ElementName, e.ElementValue, e.ErrorMessage)
|
||||
)
|
||||
|
||||
Throw New ValidationException() With {
|
||||
.ValidationErrors = oResult.ValidationErrors
|
||||
}
|
||||
End If
|
||||
|
||||
Return SerializeZUGFeRDDocument(oResult)
|
||||
End Function
|
||||
@@ -248,22 +257,13 @@ Public Class ZUGFeRDInterface
|
||||
End If
|
||||
|
||||
Try
|
||||
Dim oXPathObject As XPathDocument = Nothing
|
||||
Using oStream As New MemoryStream(oAllowedResult.FileContents)
|
||||
oXPathObject = New XPathDocument(oStream)
|
||||
Return New ZugferdResult With {
|
||||
.DataFileName = oAllowedResult.FileName,
|
||||
.XElementObject = XElement.Load(oStream)
|
||||
}
|
||||
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
|
||||
' 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.
|
||||
@@ -281,93 +281,11 @@ Public Class ZUGFeRDInterface
|
||||
End Class
|
||||
|
||||
Public Function ValidateZUGFeRDDocument(pResult As ZugferdResult) As ZugferdResult
|
||||
Dim oNavigator As XPathNavigator = pResult.XPathObject.CreateNavigator()
|
||||
Dim oNamespaceManager As New XmlNamespaceManager(oNavigator.NameTable)
|
||||
|
||||
oNamespaceManager.AddNamespace("ram", "urn:un:unece:uncefact:data:standard:ReusableAggregateBusinessInformationEntity:12")
|
||||
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
|
||||
Try
|
||||
Dim oCurrencyCodeNodes = pResult.XElementObject.Descendants().
|
||||
Where(Function(n) n.Name.ToString.EndsWith("CurrencyCode"))
|
||||
|
||||
For Each oNode As XElement In oCurrencyCodeNodes
|
||||
Dim oValid = ValidateCurrencyCode(oNode.Value)
|
||||
If oValid = False Then
|
||||
pResult.ValidationErrors.Add(New ZugferdValidationError() With {
|
||||
.ElementName = oNode.Name.LocalName,
|
||||
.ElementValue = oNode.Value,
|
||||
.ErrorMessage = "Invalid CurrencyCode. Only 3-Character codes are allowed."
|
||||
})
|
||||
End If
|
||||
Next
|
||||
Catch ex As Exception
|
||||
_logger.Error(ex)
|
||||
End Try
|
||||
|
||||
' currencyID
|
||||
Try
|
||||
Dim oCurrencyIDNodes = pResult.XElementObject.Descendants().
|
||||
Where(Function(n) n.Attributes.Any(Function(a) a.Name.LocalName = "currencyID"))
|
||||
|
||||
For Each oNode As XElement In oCurrencyIDNodes
|
||||
Dim oCurrencyID As String = oNode.Attribute("currencyID")?.Value
|
||||
|
||||
' CurrencyID is optional per spec
|
||||
If String.IsNullOrWhiteSpace(oCurrencyID) Then
|
||||
Continue For
|
||||
End If
|
||||
|
||||
Dim oValid = ValidateCurrencyCode(oCurrencyID)
|
||||
If oValid = False Then
|
||||
pResult.ValidationErrors.Add(New ZugferdValidationError() With {
|
||||
.ElementName = oNode.Name.LocalName,
|
||||
.ElementValue = oCurrencyID,
|
||||
.ErrorMessage = "Invalid currencyID. Only 3-Character codes or empty values are allowed."
|
||||
})
|
||||
End If
|
||||
Next
|
||||
|
||||
Catch ex As Exception
|
||||
_logger.Error(ex)
|
||||
End Try
|
||||
|
||||
Return pResult
|
||||
End Function
|
||||
|
||||
Private Function ValidateCurrencyCode(pValue As String) As Boolean
|
||||
Dim oValueRegex As New Text.RegularExpressions.Regex("[A-Z]{3}")
|
||||
|
||||
If oValueRegex.IsMatch(pValue) = False Then
|
||||
Return False
|
||||
End If
|
||||
|
||||
Return True
|
||||
Return _Validator.ValidateZUGFeRDDocument(pResult)
|
||||
End Function
|
||||
|
||||
Public Function SerializeZUGFeRDDocument(pResult As ZugferdResult) As ZugferdResult
|
||||
Try
|
||||
Dim oNavigator As XPathNavigator = pResult.XPathObject.CreateNavigator()
|
||||
Dim oReader As XmlReader
|
||||
|
||||
Dim oObject As Object = Nothing
|
||||
@@ -405,8 +323,7 @@ Public Class ZUGFeRDInterface
|
||||
_logger.Debug("Trying Type [{0}]", oTypeName)
|
||||
|
||||
Try
|
||||
oReader = oNavigator.ReadSubtree()
|
||||
|
||||
oReader = pResult.XElementObject.CreateReader()
|
||||
oObject = oSerializer.Deserialize(oReader)
|
||||
oSpecification = oType.Specification
|
||||
|
||||
|
||||
Reference in New Issue
Block a user