diff --git a/Interfaces/ZUGFeRDInterface.vb b/Interfaces/ZUGFeRDInterface.vb index 9d748345..8588efbb 100644 --- a/Interfaces/ZUGFeRDInterface.vb +++ b/Interfaces/ZUGFeRDInterface.vb @@ -39,6 +39,7 @@ Public Class ZUGFeRDInterface UnsupportedFormat FileTooBig UnknownError + ValidationFailed End Enum Public ReadOnly Property FileGroup As FileGroups @@ -54,6 +55,7 @@ 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 Public Property ValidationErrors As New List(Of ZugferdValidationError) @@ -246,13 +248,22 @@ Public Class ZUGFeRDInterface End If Try + Dim oXPathObject As XPathDocument = Nothing Using oStream As New MemoryStream(oAllowedResult.FileContents) - Return New ZugferdResult With { - .DataFileName = oAllowedResult.FileName, - .XPathObject = New XPathDocument(oStream) - } + oXPathObject = New XPathDocument(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. @@ -276,48 +287,67 @@ Public Class ZUGFeRDInterface 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 oCurrencyCodeIterator As XPathNodeIterator = oNavigator. - Select("//ram:InvoiceCurrencyCode | //ram:TaxCurrencyCode | //ram:TaxCurrencyCode | //ram:SourceCurrencyCode", oNamespaceManager) + Dim oCurrencyCodeNodes = pResult.XElementObject.Descendants(). + Where(Function(n) n.Name.ToString.EndsWith("CurrencyCode")) - While oCurrencyCodeIterator.MoveNext() - Dim oNode As XPathNavigator = oCurrencyCodeIterator.Current + 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, + .ElementName = oNode.Name.LocalName, .ElementValue = oNode.Value, .ErrorMessage = "Invalid CurrencyCode. Only 3-Character codes are allowed." }) End If - End While + Next Catch ex As Exception _logger.Error(ex) End Try ' currencyID 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() - Dim oNode As XPathNavigator = oCurrencyIDIterator.Current - Dim oCurrencyID As String = oNode.GetAttribute("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 While + Continue For End If Dim oValid = ValidateCurrencyCode(oCurrencyID) If oValid = False Then pResult.ValidationErrors.Add(New ZugferdValidationError() With { - .ElementName = oNode.Name, + .ElementName = oNode.Name.LocalName, .ElementValue = oCurrencyID, .ErrorMessage = "Invalid currencyID. Only 3-Character codes or empty values are allowed." }) End If - End While + Next + Catch ex As Exception _logger.Error(ex) End Try