3 Commits

Author SHA1 Message Date
Jonathan Jenne
86ca1011df Jobs: Version 1.10.0.0 2022-11-24 14:28:39 +01:00
Jonathan Jenne
b1aba0a80d Jobs: Add exception for unsupported zugferd documents 2022-11-24 14:26:42 +01:00
Jonathan Jenne
a8862709d8 Jobs: Update to use Job Runner Table 2022-11-24 14:24:59 +01:00
10 changed files with 97 additions and 73 deletions

View File

@@ -89,10 +89,10 @@ Public Class ZUGFeRDInterface
''' </summary> ''' </summary>
''' <param name="Path"></param> ''' <param name="Path"></param>
''' <exception cref="ZUGFeRDExecption"></exception> ''' <exception cref="ZUGFeRDExecption"></exception>
Public Function ExtractZUGFeRDFileWithGDPicture(Path As String) As Object Public Function ExtractZUGFeRDFileWithGDPicture(Path As String) As Tuple(Of String, Object)
Dim oXmlDocument = ValidateZUGFeRDFileWithGDPicture(Path) Dim oXmlDocument = ValidateZUGFeRDFileWithGDPicture(Path)
If IsNothing(oXmlDocument) Then If IsNothing(oXmlDocument.Item2) Then
Throw New ZUGFeRDExecption(ErrorType.NoZugferd, "Datei ist keine ZUGFeRD Datei.") Throw New ZUGFeRDExecption(ErrorType.NoZugferd, "Datei ist keine ZUGFeRD Datei.")
End If End If
@@ -104,10 +104,10 @@ Public Class ZUGFeRDInterface
''' </summary> ''' </summary>
''' <param name="Stream"></param> ''' <param name="Stream"></param>
''' <exception cref="ZUGFeRDExecption"></exception> ''' <exception cref="ZUGFeRDExecption"></exception>
Public Function ExtractZUGFeRDFileWithGDPicture(Stream As Stream) As Object Public Function ExtractZUGFeRDFileWithGDPicture(Stream As Stream) As Tuple(Of String, Object)
Dim oXmlDocument = ValidateZUGFeRDFileWithGDPicture(Stream) Dim oXmlDocument = ValidateZUGFeRDFileWithGDPicture(Stream)
If IsNothing(oXmlDocument) Then If IsNothing(oXmlDocument.Item2) Then
Throw New ZUGFeRDExecption(ErrorType.NoZugferd, "Datei ist keine ZUGFeRD Datei.") Throw New ZUGFeRDExecption(ErrorType.NoZugferd, "Datei ist keine ZUGFeRD Datei.")
End If End If
@@ -120,7 +120,7 @@ Public Class ZUGFeRDInterface
''' <param name="pStream"></param> ''' <param name="pStream"></param>
''' <exception cref="ZUGFeRDExecption"></exception> ''' <exception cref="ZUGFeRDExecption"></exception>
''' <returns>The embedded xml data as an XPath document</returns> ''' <returns>The embedded xml data as an XPath document</returns>
Public Function ValidateZUGFeRDFileWithGDPicture(pStream As Stream) As XPathDocument Public Function ValidateZUGFeRDFileWithGDPicture(pStream As Stream) As Tuple(Of String, XPathDocument)
Dim oEmbedExtractor = New PDFEmbeds(_logConfig) Dim oEmbedExtractor = New PDFEmbeds(_logConfig)
Try Try
@@ -148,7 +148,7 @@ Public Class ZUGFeRDInterface
''' <param name="pPath"></param> ''' <param name="pPath"></param>
''' <exception cref="ZUGFeRDExecption"></exception> ''' <exception cref="ZUGFeRDExecption"></exception>
''' <returns>The embedded xml data as an XPath document</returns> ''' <returns>The embedded xml data as an XPath document</returns>
Public Function ValidateZUGFeRDFileWithGDPicture(pPath As String) As XPathDocument Public Function ValidateZUGFeRDFileWithGDPicture(pPath As String) As Tuple(Of String, XPathDocument)
Dim oEmbedExtractor = New PDFEmbeds(_logConfig) Dim oEmbedExtractor = New PDFEmbeds(_logConfig)
Try Try
@@ -170,9 +170,7 @@ Public Class ZUGFeRDInterface
End Try End Try
End Function End Function
Private Function HandleEmbeddedFiles(pResults As List(Of PDFEmbeds.EmbeddedFile)) As XPathDocument Private Function HandleEmbeddedFiles(pResults As List(Of PDFEmbeds.EmbeddedFile)) As Tuple(Of String, XPathDocument)
Dim oXmlDocument As XPathDocument
If pResults Is Nothing Then If pResults Is Nothing Then
Throw New ZUGFeRDExecption(ErrorType.NoZugferd, "Datei ist keine ZUGFeRD Datei, weil die Attachments nicht gelesen werden konnten.") Throw New ZUGFeRDExecption(ErrorType.NoZugferd, "Datei ist keine ZUGFeRD Datei, weil die Attachments nicht gelesen werden konnten.")
End If End If
@@ -183,7 +181,7 @@ Public Class ZUGFeRDInterface
' Find the first file which filename matches the valid filenames for embedded invoice files ' Find the first file which filename matches the valid filenames for embedded invoice files
Dim oValidResult As PDFEmbeds.EmbeddedFile = pResults. Dim oValidResult As PDFEmbeds.EmbeddedFile = pResults.
Where(Function(result) ValidFilenames.Contains(result.FileName.ToUpper)). Where(Function(f) ValidFilenames.Contains(f.FileName.ToUpper)).
FirstOrDefault() FirstOrDefault()
If oValidResult Is Nothing Then If oValidResult Is Nothing Then
@@ -193,19 +191,18 @@ Public Class ZUGFeRDInterface
' Search the embedded files for the ones which are allowed as per the configuration. ' Search the embedded files for the ones which are allowed as per the configuration.
' The config might say, allow ZUGFeRD but not Factur-X. ' The config might say, allow ZUGFeRD but not Factur-X.
Dim oAllowedResult As PDFEmbeds.EmbeddedFile = pResults. Dim oAllowedResult As PDFEmbeds.EmbeddedFile = pResults.
Where(Function(result) AllowedFilenames.Contains(result.FileName.ToUpper)). Where(Function(f) AllowedFilenames.Contains(f.FileName.ToUpper)).
FirstOrDefault() FirstOrDefault()
If oAllowedResult Is Nothing Then If oAllowedResult Is Nothing Then
Throw New ZUGFeRDExecption(ErrorType.UnsupportedFormat, "Datei ist eine ZUGFeRD Datei, aber das Format wird nicht unterstützt.") Throw New ZUGFeRDExecption(ErrorType.UnsupportedFormat, "Datei ist eine ZUGFeRD Datei, aber das Format wird nicht unterstützt.", oAllowedResult.FileName)
End If End If
Try Try
Using oStream As New MemoryStream(oAllowedResult.FileContents) Using oStream As New MemoryStream(oAllowedResult.FileContents)
oXmlDocument = New XPathDocument(oStream) Return New Tuple(Of String, XPathDocument)(oAllowedResult.FileName, New XPathDocument(oStream))
End Using End Using
Return oXmlDocument
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.
@@ -217,9 +214,9 @@ Public Class ZUGFeRDInterface
End Try End Try
End Function End Function
Public Function SerializeZUGFeRDDocument(pDocument As XPathDocument) As Object Public Function SerializeZUGFeRDDocument(pDocument As Tuple(Of String, XPathDocument)) As Tuple(Of String, Object)
Try Try
Dim oNavigator As XPathNavigator = pDocument.CreateNavigator() Dim oNavigator As XPathNavigator = pDocument.Item2.CreateNavigator()
Dim oReader As XmlReader Dim oReader As XmlReader
Dim oResult = Nothing Dim oResult = Nothing

View File

@@ -4,10 +4,23 @@
Public ReadOnly Property ErrorType() As ZUGFeRDInterface.ErrorType Public ReadOnly Property ErrorType() As ZUGFeRDInterface.ErrorType
''' <summary>
''' Contains the name of the extracted xml file if already extracted.
''' </summary>
''' <returns>A filename like zugferd-invoice.xml</returns>
Public ReadOnly Property XmlFile As String = String.Empty
Public Sub New(ErrorType As ZUGFeRDInterface.ErrorType, Message As String) Public Sub New(ErrorType As ZUGFeRDInterface.ErrorType, Message As String)
MyBase.New(Message) MyBase.New(Message)
_ErrorType = ErrorType _ErrorType = ErrorType
End Sub End Sub
Public Sub New(ErrorType As ZUGFeRDInterface.ErrorType, Message As String, pXmlFileName As String)
MyBase.New(Message)
_ErrorType = ErrorType
_XmlFile = pXmlFileName
End Sub
End Class End Class
End Class End Class

View File

@@ -43,8 +43,11 @@ Public Class Exceptions
Public Class UnsupportedFerdException Public Class UnsupportedFerdException
Inherits ApplicationException Inherits ApplicationException
Public Sub New() Public ReadOnly Property XmlFile As String
Public Sub New(pXmlFile As String)
MyBase.New("ZUGFeRD document found but is not supported!") MyBase.New("ZUGFeRD document found but is not supported!")
_XmlFile = pXmlFile
End Sub End Sub
End Class End Class

View File

@@ -2,9 +2,9 @@
Imports System.IO Imports System.IO
Imports DigitalData.Modules.Interfaces Imports DigitalData.Modules.Interfaces
Imports DigitalData.Modules.Jobs
Imports DigitalData.Modules.Config Imports DigitalData.Modules.Config
Imports DigitalData.Modules.Logging Imports DigitalData.Modules.Logging
Imports DigitalData.Modules.Language
Imports Newtonsoft.Json.Linq Imports Newtonsoft.Json.Linq
Imports System.Collections.Generic Imports System.Collections.Generic
Imports System.Linq Imports System.Linq
@@ -43,7 +43,7 @@ Public Class GraphQLJob
_Logger.Debug("Loading Queries") _Logger.Debug("Loading Queries")
' Load query data from TBCUST_JOBRUNNER_QUERY ' Load query data from TBCUST_JOBRUNNER_QUERY
Dim oQueryTable As DataTable = _MSSQL.GetDatatable("SELECT * FROM TBCUST_JOBRUNNER_QUERY ORDER BY OPERATION_NAME, CLEAR_BEFORE_FILL ASC") Dim oQueryTable As DataTable = _MSSQL.GetDatatable("SELECT * FROM TBCUST_JOBRUNNER_QUERY ORDER BY SEQUENCE")
Dim oQueryList As New List(Of GraphQL.Query) Dim oQueryList As New List(Of GraphQL.Query)
' Save query data to business objects ' Save query data to business objects
@@ -51,14 +51,35 @@ Public Class GraphQLJob
Dim oQuery As New GraphQL.Query With { Dim oQuery As New GraphQL.Query With {
.Id = oRow.Item("GUID"), .Id = oRow.Item("GUID"),
.Name = oRow.Item("TITLE"), .Name = oRow.Item("TITLE"),
.ClearBeforeFill = oRow.Item("CLEAR_BEFORE_FILL"), .ClearBeforeFill = oRow.ItemEx("CLEAR_BEFORE_FILL", False),
.ConnectionId = oRow.Item("CON_ID"), ' TODO: Connection String? .ConnectionId = oRow.ItemEx("CON_ID", 1), ' TODO: Connection String?
.DestinationTable = oRow.Item("DESTINATION_TABLE"), .DestinationTable = oRow.ItemEx("DESTINATION_TABLE", String.Empty),
.OperationName = oRow.Item("OPERATION_NAME"), .OperationName = oRow.ItemEx("OPERATION_NAME", String.Empty),
.MappingBasePath = oRow.Item("MAPPING_BASE_PATH"), .MappingBasePath = oRow.ItemEx("MAPPING_BASE_PATH", String.Empty),
.QueryString = oRow.Item("QUERY_STRING"), .QueryString = oRow.ItemEx("QUERY_STRING", String.Empty),
.QueryConstraint = oRow.Item("QUERY_CONSTRAINT") .QueryConstraint = oRow.ItemEx("QUERY_CONSTRAINT", String.Empty)
} }
If oQuery.DestinationTable = String.Empty Then
_Logger.Warn("Value [DestinationTable] could not be read. Configuration incomplete.")
End If
If oQuery.OperationName = String.Empty Then
_Logger.Warn("Value [OperationName] could not be read. Configuration incomplete.")
End If
If oQuery.MappingBasePath = String.Empty Then
_Logger.Warn("Value [MappingBasePath] could not be read. Configuration incomplete.")
End If
If oQuery.QueryString = String.Empty Then
_Logger.Warn("Value [QueryString] could not be read. Configuration incomplete.")
End If
If oQuery.QueryConstraint = String.Empty Then
_Logger.Warn("Value [QueryConstraint] could not be read. Configuration incomplete.")
End If
oQueryList.Add(oQuery) oQueryList.Add(oQuery)
Next Next
@@ -71,6 +92,10 @@ Public Class GraphQLJob
Dim oConnectionId As Integer = oQuery.ConnectionId Dim oConnectionId As Integer = oQuery.ConnectionId
Dim oConnectionString = _MSSQL.Get_ConnectionStringforID(oConnectionId) Dim oConnectionString = _MSSQL.Get_ConnectionStringforID(oConnectionId)
If oConnectionString = String.Empty Then
_Logger.Warn("Could not get Connection String for ConnectionId [{0}]", oConnectionId)
End If
Dim oDatabase As New MSSQLServer(_LogConfig, oConnectionString) Dim oDatabase As New MSSQLServer(_LogConfig, oConnectionString)
' Reset all records to status = 0 ' Reset all records to status = 0

View File

@@ -1,8 +1,17 @@
Imports System.Collections.Generic Imports System.Collections.Generic
Public Class JobConfig Public Class JobConfig
Public Enabled As Boolean Public Property Name As JobType
Public StartImmediately As Boolean Public Property Enabled As Boolean = False
Public CronExpression As String Public Property StartWithoutDelay As Boolean = False
Public Arguments As Dictionary(Of String, String) Public Property CronSchedule As String = ""
Public Property ArgsString As String = ""
Public Property Args As New Dictionary(Of String, String)
Public Enum JobType
ADSync
GraphQL
Test
End Enum
End Class End Class

View File

@@ -13,46 +13,17 @@ Public Class JobConfigParser
''' </summary> ''' </summary>
''' <param name="ConfigString"></param> ''' <param name="ConfigString"></param>
''' <returns>A populated JobConfig object</returns> ''' <returns>A populated JobConfig object</returns>
Public Shared Function ParseConfig(ConfigString As String) As JobConfig Public Shared Function ParseConfig(pJobConfig As JobConfig) As JobConfig
If JobOptionsRegex.IsMatch(ConfigString) Then
Dim oMatches = JobOptionsRegex.Matches(ConfigString)
Dim oOptions As New JobConfig
Dim oSplitOptions As String() = ConfigString.Split(ARGS_LIST_DELIMITER) ' 24.11.2022: This only parses the optional Job arguments,
' everything is comparmentalized in the Service config
pJobConfig.Args = ParseOptionalArguments(pJobConfig.ArgsString)
Return pJobConfig
If oSplitOptions.Length = 3 Then
oOptions = ParseEnabled(oSplitOptions(0), oOptions)
oOptions.CronExpression = oSplitOptions(1)
oOptions.Arguments = ParseOptionalArguments(oSplitOptions(2))
ElseIf oSplitOptions.Length = 2 Then
oOptions = ParseEnabled(oSplitOptions(0), oOptions)
oOptions.CronExpression = oSplitOptions(1)
oOptions.Arguments = New Dictionary(Of String, String)
Else
Throw New ArgumentException("Config Malformed")
End If
Return oOptions
Else
Throw New ArgumentException("Config Malformed")
End If
End Function End Function
Public Shared Function ParseEnabled(EnabledValue As String, Options As JobConfig) As JobConfig
Select Case EnabledValue
Case "True"
Options.Enabled = True
Options.StartImmediately = False
Case "Debug"
Options.Enabled = True
Options.StartImmediately = True
Case Else
Options.Enabled = False
Options.StartImmediately = False
End Select
Return Options
End Function
Private Shared Function ParseOptionalArguments(ArgsString As String) As Dictionary(Of String, String) Private Shared Function ParseOptionalArguments(ArgsString As String) As Dictionary(Of String, String)
Dim oArgsDictionary As New Dictionary(Of String, String) Dim oArgsDictionary As New Dictionary(Of String, String)

View File

@@ -116,6 +116,10 @@
</Compile> </Compile>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Reference Include="DigitalData.Modules.Language, Version=1.6.2.0, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\Interfaces\bin\Debug\DigitalData.Modules.Language.dll</HintPath>
</Reference>
<Reference Include="FirebirdSql.Data.FirebirdClient, Version=7.5.0.0, Culture=neutral, PublicKeyToken=3750abcc3150b00c, processorArchitecture=MSIL"> <Reference Include="FirebirdSql.Data.FirebirdClient, Version=7.5.0.0, Culture=neutral, PublicKeyToken=3750abcc3150b00c, processorArchitecture=MSIL">
<HintPath>..\packages\FirebirdSql.Data.FirebirdClient.7.5.0\lib\net452\FirebirdSql.Data.FirebirdClient.dll</HintPath> <HintPath>..\packages\FirebirdSql.Data.FirebirdClient.7.5.0\lib\net452\FirebirdSql.Data.FirebirdClient.dll</HintPath>
</Reference> </Reference>

View File

@@ -13,7 +13,7 @@ Imports System.Runtime.InteropServices
<Assembly: AssemblyCompany("Digital Data")> <Assembly: AssemblyCompany("Digital Data")>
<Assembly: AssemblyProduct("Modules.Jobs")> <Assembly: AssemblyProduct("Modules.Jobs")>
<Assembly: AssemblyCopyright("Copyright © 2022")> <Assembly: AssemblyCopyright("Copyright © 2022")>
<Assembly: AssemblyTrademark("1.9.0.0")> <Assembly: AssemblyTrademark("1.10.0.0")>
<Assembly: ComVisible(False)> <Assembly: ComVisible(False)>
@@ -30,5 +30,5 @@ Imports System.Runtime.InteropServices
' Sie können alle Werte angeben oder die standardmäßigen Build- und Revisionsnummern ' Sie können alle Werte angeben oder die standardmäßigen Build- und Revisionsnummern
' übernehmen, indem Sie "*" eingeben: ' übernehmen, indem Sie "*" eingeben:
<Assembly: AssemblyVersion("1.9.0.0")> <Assembly: AssemblyVersion("1.10.0.0")>
<Assembly: AssemblyFileVersion("1.9.0.0")> <Assembly: AssemblyFileVersion("1.10.0.0")>

View File

@@ -39,6 +39,6 @@
" "
Public Const EMAIL_UNSUPPORTED_DOCUMENT = " Public Const EMAIL_UNSUPPORTED_DOCUMENT = "
<p>Ihre Email enthielt ein ZUGFeRD Dokument, welches aber zur Zeit noch nicht unsterstützt wird.</p> <p>Ihre Email enthielt ein ZUGFeRD Dokument ({0}), welches zur Zeit noch nicht unsterstützt wird.</p>
" "
End Class End Class

View File

@@ -204,8 +204,10 @@ Public Class ImportZUGFeRDFiles
Try Try
For Each oFile In oFileGroupFiles For Each oFile In oFileGroupFiles
' 09.12.2021: oDocument is now an Object, because have different classes corresponding to the ' 09.12.2021: oDocument is now an Object, because have different classes corresponding to the
' different versions of ZUGFeRD and the type is unknown at compile-time. ' different versions of ZUGFeRD and the type is unknown at compile-time.
Dim oDocument As Object ' 17.11.2022: oDocument is now a Tuple of (String, Object), to be able to return the filename
' of the extracted xml file.
Dim oDocument As Tuple(Of String, Object)
' Start a global group counter for each file ' Start a global group counter for each file
Dim oGlobalGroupCounter = 0 Dim oGlobalGroupCounter = 0
@@ -245,8 +247,8 @@ Public Class ImportZUGFeRDFiles
Continue For Continue For
Case ZUGFeRDInterface.ErrorType.UnsupportedFormat Case ZUGFeRDInterface.ErrorType.UnsupportedFormat
_logger.Info("File [{0}] is an unsupported ZUFeRD document format!") _logger.Info("File [{0}/{1}] is an unsupported ZUFeRD document format!", oFile.Name, ex.XmlFile)
Throw New UnsupportedFerdException() Throw New UnsupportedFerdException(ex.XmlFile)
Case ZUGFeRDInterface.ErrorType.NoValidZugferd Case ZUGFeRDInterface.ErrorType.NoValidZugferd
_logger.Warn("File [{0}] is an Incorrectly formatted ZUGFeRD document!", oFile.Name) _logger.Warn("File [{0}] is an Incorrectly formatted ZUGFeRD document!", oFile.Name)
@@ -397,7 +399,7 @@ Public Class ImportZUGFeRDFiles
' That 's why we set it to String.Empty here. ' That 's why we set it to String.Empty here.
Create_HistoryEntry(oMessageId, String.Empty, "REJECTED - ZUGFeRD yes but unsupported format", oFBTransaction) Create_HistoryEntry(oMessageId, String.Empty, "REJECTED - ZUGFeRD yes but unsupported format", oFBTransaction)
Dim oBody = EmailStrings.EMAIL_UNSUPPORTED_DOCUMENT Dim oBody As String = String.Format(EmailStrings.EMAIL_UNSUPPORTED_DOCUMENT, ex.XmlFile)
Dim oEmailData = MoveAndRenameEmailToRejected(oArgs, oMessageId) Dim oEmailData = MoveAndRenameEmailToRejected(oArgs, oMessageId)
_email.AddToEmailQueueMSSQL(oMessageId, oBody, oEmailData, "UnsupportedFerdException", _EmailOutAccountId, oArgs.NamePortal) _email.AddToEmailQueueMSSQL(oMessageId, oBody, oEmailData, "UnsupportedFerdException", _EmailOutAccountId, oArgs.NamePortal)
AddRejectedState(oMessageId, "UnsupportedFerdException", "Nicht unterstütztes Datenformat", "", oSQLTransaction) AddRejectedState(oMessageId, "UnsupportedFerdException", "Nicht unterstütztes Datenformat", "", oSQLTransaction)