Jobs/Zugferd: Improve structure

This commit is contained in:
Jonathan Jenne 2023-08-22 08:37:15 +02:00
parent 7fea3dc1ff
commit 72f7211d63
5 changed files with 367 additions and 361 deletions

View File

@ -100,6 +100,8 @@
<Compile Include="ZUGFeRD\EmailData.vb" /> <Compile Include="ZUGFeRD\EmailData.vb" />
<Compile Include="ZUGFeRD\EmailFunctions.vb" /> <Compile Include="ZUGFeRD\EmailFunctions.vb" />
<Compile Include="ZUGFeRD\EmailStrings.vb" /> <Compile Include="ZUGFeRD\EmailStrings.vb" />
<Compile Include="ZUGFeRD\FileFunctions.vb" />
<Compile Include="ZUGFeRD\HistoryFunctions.vb" />
<Compile Include="ZUGFeRD\ImportZUGFeRDFiles.vb" /> <Compile Include="ZUGFeRD\ImportZUGFeRDFiles.vb" />
<Compile Include="ZUGFeRD\WorkerArgs.vb" /> <Compile Include="ZUGFeRD\WorkerArgs.vb" />
<Compile Include="Exceptions.vb" /> <Compile Include="Exceptions.vb" />

View File

@ -1,10 +1,12 @@
Imports DigitalData.Modules.Logging Imports DigitalData.Modules.Logging
Imports DigitalData.Modules.Database Imports DigitalData.Modules.Database
Imports DigitalData.Modules.Language Imports DigitalData.Modules.Base
Imports System.Data Imports System.Data
Imports System.IO Imports System.IO
Imports System.Data.SqlClient Imports System.Data.SqlClient
Imports System.Collections.Generic
Namespace ZUGFeRD
Public Class EmailFunctions Public Class EmailFunctions
Private ReadOnly _logConfig As LogConfig Private ReadOnly _logConfig As LogConfig
Private ReadOnly _logger As Logger Private ReadOnly _logger As Logger
@ -16,53 +18,6 @@ Public Class EmailFunctions
_mssql = MSSQL _mssql = MSSQL
End Sub End Sub
'Public Sub AddToEmailQueueFB(MessageId As String, BodyText As String, EmailData As EmailData, NamePortal As String)
' If EmailData Is Nothing Then
' _logger.Warn("EmailData is empty. Email will not be sent!")
' Exit Sub
' End If
' Try
' Dim oJobId = RandomValue(1, 10000)
' Dim oReference = MessageId
' Dim oEmailTo = ""
' Dim oSubject = EmailStrings.EMAIL_SUBJECT_REJECTED.Replace(EmailStrings.constNAME_ZUGFERD_PORTAL, NamePortal)
' Dim oAccountId = 1
' Dim oCreatedWho = "ZUGFeRD Service"
' Dim oFinalBodyText = String.Format(EmailStrings.EMAIL_WRAPPING_TEXT.Replace(EmailStrings.constNAME_ZUGFERD_PORTAL, NamePortal), BodyText)
' Dim oEmailAddress = EmailData.From
' Dim oAttachment = EmailData.Attachment
' If IsNothing(oEmailAddress) OrElse String.IsNullOrWhiteSpace(oEmailAddress) Then
' _logger.Warn("Could not find email-address for MessageId {0}", MessageId)
' oEmailTo = String.Empty
' Else
' oEmailTo = oEmailAddress
' End If
' _logger.Debug("Generated Email:")
' _logger.Debug("To: {0}", oEmailTo)
' _logger.Debug("Subject: {0}", oSubject)
' _logger.Debug("Body {0}", oFinalBodyText)
' Dim osql = $"select * from TBEDM_EMAIL_QUEUE where REFERENCE1 = '{oReference} and EMAIL_TO = ''{oEmailTo}' and EMAIL_SUBJ = '{oSubject}'"
' Dim oDTResult As DataTable = _firebird.GetDatatable(osql)
' If oDTResult.Rows.Count = 0 Then
' Dim oSQLInsert = $"INSERT INTO TBEDM_EMAIL_QUEUE "
' oSQLInsert &= "(JOB_ID, REFERENCE1, EMAIL_ACCOUNT_ID, EMAIL_TO, EMAIL_SUBJ, EMAIL_BODY, CREATEDWHO, EMAIL_ATTMT1) VALUES "
' oSQLInsert &= $"({oJobId}, '{oReference}', {oAccountId}, '{oEmailTo}', '{oSubject}', '{oFinalBodyText.Replace("'", "''")}', '{oCreatedWho}', '{oAttachment}')"
' _firebird.ExecuteNonQuery(oSQLInsert)
' _logger.Debug("Email Queue updated for MessageId {0}.", MessageId, oEmailTo)
' Else
' _logger.Debug("Email has already been sent!!")
' End If
' Catch ex As Exception
' _logger.Error(ex)
' End Try
'End Sub
Public Sub AddToEmailQueueMSSQL(MessageId As String, BodyText As String, pEmailData As EmailData, SourceProcedure As String, pEmailAccountId As Integer, NamePortal As String) Public Sub AddToEmailQueueMSSQL(MessageId As String, BodyText As String, pEmailData As EmailData, SourceProcedure As String, pEmailAccountId As Integer, NamePortal As String)
If pEmailData Is Nothing Then If pEmailData Is Nothing Then
_logger.Warn("EmailData is empty. Email will not be sent!") _logger.Warn("EmailData is empty. Email will not be sent!")
@ -162,10 +117,12 @@ Public Class EmailFunctions
Dim oSubjectDefault = String.Format("No Subject found for ({0})", MessageId) Dim oSubjectDefault = String.Format("No Subject found for ({0})", MessageId)
Dim oSubject = oRow.ItemEx("EMAIL_SUBJECT", oSubjectDefault) Dim oSubject = oRow.ItemEx("EMAIL_SUBJECT", oSubjectDefault)
_logger.Info("Email Data for [{0}] fetched!", MessageId)
Return New EmailData() With { Return New EmailData() With {
.From = oFrom, .From = oFrom,
.Subject = oSubject .Subject = oSubject
} }
Catch ex As Exception Catch ex As Exception
_logger.Warn("Could not fetch Email Data for FileId {0}", MessageId) _logger.Warn("Could not fetch Email Data for FileId {0}", MessageId)
Return Nothing Return Nothing
@ -188,6 +145,8 @@ Public Class EmailFunctions
Dim oCleanSubject = String.Join("", UncleanedSubject.Split(Path.GetInvalidPathChars())) Dim oCleanSubject = String.Join("", UncleanedSubject.Split(Path.GetInvalidPathChars()))
Dim oAttachmentDirectory = RejectedEmailDirectory Dim oAttachmentDirectory = RejectedEmailDirectory
Dim oAttachmentFile = oCleanSubject & ".eml" Dim oAttachmentFile = oCleanSubject & ".eml"
_logger.Debug("Email Filename is [{0}]", oAttachmentFile)
Dim oAttachmentPath = Path.Combine(oAttachmentDirectory, oAttachmentFile) Dim oAttachmentPath = Path.Combine(oAttachmentDirectory, oAttachmentFile)
Return oAttachmentPath Return oAttachmentPath
@ -197,4 +156,27 @@ Public Class EmailFunctions
Dim oRandomValue = CInt(Math.Floor((upperBound - lowerBound + 1) * Rnd())) + lowerBound Dim oRandomValue = CInt(Math.Floor((upperBound - lowerBound + 1) * Rnd())) + lowerBound
Return oRandomValue Return oRandomValue
End Function End Function
Public Function CreateBodyForMissingProperties(OriginalFilename As String, MissingProperties As List(Of String)) As String
Dim oBody = String.Format(EmailStrings.EMAIL_MISSINGPROPERTIES_1, OriginalFilename)
If MissingProperties.Count > 0 Then
oBody &= $"{vbNewLine}{vbNewLine}"
oBody &= EmailStrings.EMAIL_MISSINGPROPERTIES_2
oBody &= $"{vbNewLine}{vbNewLine}"
For Each prop In MissingProperties
oBody &= $"- {prop}"
Next
End If
Return oBody
End Function
Public Function CreateBodyForUnhandledException(MessageId As String, Exception As Exception) As String
Dim oBody = String.Format(EmailStrings.EMAIL_UNHANDLED_EXCEPTION, MessageId, Exception.Message, Exception.StackTrace)
Return oBody
End Function
End Class End Class
End Namespace

View File

@ -0,0 +1,112 @@
Imports System.Collections.Generic
Imports System.IO
Imports System.Linq
Imports DigitalData.Modules.Database
Imports DigitalData.Modules.Interfaces
Imports DigitalData.Modules.Logging
Imports Microsoft.VisualBasic.FileIO
Namespace ZUGFeRD
Public Class FileFunctions
Private ReadOnly _logConfig As LogConfig
Private ReadOnly _logger As Logger
Private ReadOnly _mssql As MSSQLServer
Private ReadOnly _filesystem As Filesystem.File
Public Sub New(LogConfig As LogConfig, MSSQL As MSSQLServer)
_logConfig = LogConfig
_logger = _logConfig.GetLogger()
_mssql = MSSQL
_filesystem = New Filesystem.File(LogConfig)
End Sub
Public Sub MoveFiles(
Args As WorkerArgs,
MessageId As String,
Files As List(Of FileInfo),
AttachmentFiles As List(Of FileInfo),
EmbeddedAttachments As List(Of PDFEmbeds.EmbeddedFile),
MoveDirectory As String,
IsSuccess As Boolean)
Dim oFinalMoveDirectory As String = MoveDirectory
Dim oDateSubDirectoryName As String = Now.ToString("yyyy\\MM\\dd")
Dim oAttachmentDirectory As String = Path.Combine(oFinalMoveDirectory, Args.AttachmentsSubDirectory, oDateSubDirectoryName)
' Files will be moved to a subfolder for the current day if they are rejected
If Not IsSuccess Then
oFinalMoveDirectory = Path.Combine(oFinalMoveDirectory, oDateSubDirectoryName)
End If
' Create directories if they don't exist
If Not Directory.Exists(oFinalMoveDirectory) Then
Try
Directory.CreateDirectory(oFinalMoveDirectory)
Catch ex As Exception
_logger.Error(ex)
End Try
End If
If Not Directory.Exists(oAttachmentDirectory) And AttachmentFiles.Count > 0 Then
Try
Directory.CreateDirectory(oAttachmentDirectory)
Catch ex As Exception
_logger.Error(ex)
End Try
End If
' Filter out Attachments from `Files`
Dim oInvoiceFiles As List(Of FileInfo) = Files.Except(AttachmentFiles).ToList()
' Move PDF/A Files
For Each oFile In oInvoiceFiles
Try
Dim oFilePath = _filesystem.GetVersionedFilename(Path.Combine(oFinalMoveDirectory, oFile.Name))
_filesystem.MoveTo(oFile.FullName, oFilePath, oFinalMoveDirectory)
_logger.Info("File moved to {0}", oFilePath)
Catch ex As Exception
_logger.Warn("Could not move file {0}", oFile.FullName)
_logger.Error(ex)
End Try
Next
' Move non-PDF/A Email Attachments/Files
For Each oFile In AttachmentFiles
Try
Dim oFilePath = _filesystem.GetVersionedFilename(Path.Combine(oAttachmentDirectory, oFile.Name))
_filesystem.MoveTo(oFile.FullName, oFilePath, oAttachmentDirectory)
_logger.Info("Attachment moved to {0}", oFilePath)
Catch ex As Exception
_logger.Warn("Could not move attachment {0}", oFile.FullName)
_logger.Error(ex)
End Try
Next
' Write Embedded Files to disk
For Each oResult In EmbeddedAttachments
Try
Dim oFileName As String = $"{MessageId}~{oResult.FileName}"
Dim oFilePath As String = Path.Combine(oAttachmentDirectory, oFileName)
If Not File.Exists(oAttachmentDirectory) Then
Directory.CreateDirectory(oAttachmentDirectory)
End If
Using oWriter As New FileStream(oFilePath, FileMode.Create)
oWriter.Write(oResult.FileContents, 0, oResult.FileContents.Length)
_logger.Info("Embedded Attachment moved to {0}", oFilePath)
End Using
Catch ex As Exception
_logger.Warn("Could not save embedded attachment {0}", oResult.FileName)
_logger.Error(ex)
End Try
Next
_logger.Info("Finished moving files")
End Sub
End Class
End Namespace

View File

@ -0,0 +1,68 @@
Imports System.Data.SqlClient
Imports DigitalData.Modules.Database
Imports DigitalData.Modules.Logging
Imports Microsoft.VisualBasic.FileIO
Namespace ZUGFeRD
Public Class HistoryFunctions
Private ReadOnly _logConfig As LogConfig
Private ReadOnly _logger As Logger
Private ReadOnly _mssql As MSSQLServer
Public Sub New(LogConfig As LogConfig, MSSQL As MSSQLServer)
_logConfig = LogConfig
_logger = _logConfig.GetLogger()
_mssql = MSSQL
End Sub
Public Function Create_HistoryEntry(MessageId As String, MD5Checksum As String, Message As String, Transaction As SqlTransaction) As Boolean
Try
_logger.Info("Creating History Entry for MessageId [{0}] with comment [{1}]", MessageId, Message)
Dim oSQL = $"INSERT INTO TBEMLP_HISTORY (COMMENT, MD5HASH, EMAIL_MSGID) VALUES ('{Message}', '{MD5Checksum}', '{MessageId}')"
Using oConnection = _mssql.GetConnection()
' 09.07.2021: This can't be in the transaction since the history
' Entry needs to be accessed by MoveAndRenameEmailToRejected shortly after
_mssql.ExecuteNonQueryWithConnectionObject(oSQL, oConnection)
If Message.Contains("REJECTED") Then
oSQL = $"UPDATE TBEMLP_HISTORY SET STATUS = 'REJECTED', COMMENT = '{Message}', CUST_REJECTED = 1,CUST_REJECTED_WHEN = GETDATE() WHERE EMAIL_MSGID = '{MessageId}'"
_mssql.ExecuteNonQueryWithConnectionObject(oSQL, oConnection)
End If
_logger.Debug("History Entry created!")
End Using
Return True
Catch ex As Exception
_logger.Warn("History Entry count not be created for message id [{0}] and md5 [{1}]", MessageId, MD5Checksum)
_logger.Error(ex)
Return False
End Try
End Function
Public Function Update_HistoryEntry(MessageId As String, MD5Checksum As String, Message As String, Transaction As SqlTransaction) As Boolean
Try
_logger.Info("Updating History Entry for MessageId [{0}] with comment [{1}]", MessageId, Message)
' Only look for history entry by MessageId since the MD5 Hash might not be generated yet
Using oConnection = _mssql.GetConnection()
' 09.07.2021: This can't be in the transaction since the history
' Entry needs to be accessed by MoveAndRenameEmailToRejected shortly after
Dim oSQL = $"UPDATE TBEMLP_HISTORY SET COMMENT = '{Message}' WHERE EMAIL_MSGID = '{MessageId}'"
_mssql.ExecuteNonQueryWithConnectionObject(oSQL, oConnection)
End Using
_logger.Debug("History Entry created!")
Return True
Catch ex As Exception
_logger.Warn("History Entry count not be updated for message id [{0}] and md5 [{1}]", MessageId, MD5Checksum)
_logger.Error(ex)
Return False
End Try
End Function
End Class
End Namespace

View File

@ -9,7 +9,6 @@ Imports DigitalData.Modules.Interfaces
Imports DigitalData.Modules.Interfaces.Exceptions Imports DigitalData.Modules.Interfaces.Exceptions
Imports DigitalData.Modules.Jobs.Exceptions Imports DigitalData.Modules.Jobs.Exceptions
Imports DigitalData.Modules.Logging Imports DigitalData.Modules.Logging
Imports FirebirdSql.Data.FirebirdClient
Imports System.Data.SqlClient Imports System.Data.SqlClient
Public Class ImportZUGFeRDFiles Public Class ImportZUGFeRDFiles
@ -35,7 +34,10 @@ Public Class ImportZUGFeRDFiles
Private ReadOnly _logConfig As LogConfig Private ReadOnly _logConfig As LogConfig
Private ReadOnly _filesystem As Filesystem.File Private ReadOnly _filesystem As Filesystem.File
Private ReadOnly _mssql As MSSQLServer Private ReadOnly _mssql As MSSQLServer
Private ReadOnly _email As EmailFunctions Private ReadOnly _email As ZUGFeRD.EmailFunctions
Private ReadOnly _file As ZUGFeRD.FileFunctions
Private ReadOnly _history As ZUGFeRD.HistoryFunctions
Private ReadOnly _gdpictureLicenseKey As String Private ReadOnly _gdpictureLicenseKey As String
Private _zugferd As ZUGFeRDInterface Private _zugferd As ZUGFeRDInterface
@ -51,7 +53,9 @@ Public Class ImportZUGFeRDFiles
_logger = LogConfig.GetLogger() _logger = LogConfig.GetLogger()
_filesystem = New Filesystem.File(_logConfig) _filesystem = New Filesystem.File(_logConfig)
_mssql = MSSQL _mssql = MSSQL
_email = New EmailFunctions(LogConfig, _mssql) _email = New ZUGFeRD.EmailFunctions(LogConfig, _mssql)
_file = New ZUGFeRD.FileFunctions(LogConfig, _mssql)
_history = New ZUGFeRD.HistoryFunctions(LogConfig, _mssql)
_logger.Debug("Registering GDPicture License") _logger.Debug("Registering GDPicture License")
If _mssql IsNot Nothing Then If _mssql IsNot Nothing Then
@ -63,18 +67,23 @@ Public Class ImportZUGFeRDFiles
End If End If
End Sub End Sub
Private Function MoveAndRenameEmailToRejected(Args As WorkerArgs, MessageId As String) As EmailData Private Function MoveAndRenameEmailToRejected(pArgs As WorkerArgs, pMessageId As String) As EmailData
_logger.Info("Moving Mail with MessageId [{0}] to Rejected folder", MessageId) _logger.Info("Moving Mail with MessageId [{0}] to Rejected folder", pMessageId)
_logger.Debug("Fetching Email Data") _logger.Debug("Fetching Email Data")
Dim oEmailData = _email.GetEmailDataForMessageId(MessageId) Dim oEmailData = _email.GetEmailDataForMessageId(pMessageId)
Dim oSource = _email.GetOriginalEmailPath(Args.OriginalEmailDirectory, MessageId) _logger.Debug("Email Data fetched!")
Dim oSource = _email.GetOriginalEmailPath(pArgs.OriginalEmailDirectory, pMessageId)
_logger.Debug("Original email path: [{0}]", oSource)
Dim oDateSubDirectoryName As String = Now.ToString("yyyy-MM-dd") Dim oDateSubDirectoryName As String = Now.ToString("yyyy-MM-dd")
Dim oDestination As String Dim oDestination As String
Dim oRejectedDirectory As String = Path.Combine(Args.RejectedEmailDirectory, oDateSubDirectoryName) Dim oRejectedDirectory As String = Path.Combine(pArgs.RejectedEmailDirectory, oDateSubDirectoryName)
' Create the destination directory if it does not exist ' Create the destination directory if it does not exist
_logger.Debug("Creating destination directory [{0}]", oRejectedDirectory)
If Not Directory.Exists(oRejectedDirectory) Then If Not Directory.Exists(oRejectedDirectory) Then
Try Try
Directory.CreateDirectory(oRejectedDirectory) Directory.CreateDirectory(oRejectedDirectory)
@ -83,12 +92,17 @@ Public Class ImportZUGFeRDFiles
End Try End Try
End If End If
If oSource = String.Empty Then
_logger.Warn("Original Email for [{0}] could not be found. Exiting.", pMessageId)
Return Nothing
End If
' If oEmailData is Nothing, TBEDM_EMAIL_PROFILER_HISTORY for MessageId was not found. ' If oEmailData is Nothing, TBEDM_EMAIL_PROFILER_HISTORY for MessageId was not found.
' This only should happen when testing and db-tables are deleted frequently ' This only should happen when testing and db-tables are deleted frequently
If oEmailData Is Nothing Then If oEmailData Is Nothing Then
oDestination = _email.GetEmailPathWithSubjectAsName(oRejectedDirectory, MessageId) oDestination = _email.GetEmailPathWithSubjectAsName(oRejectedDirectory, pMessageId)
Else Else
oDestination = _email.GetEmailPathWithSubjectAsName(oRejectedDirectory, oEmailData.Subject) oDestination = _email.GetEmailPathWithSubjectAsName(oRejectedDirectory, StringEx.ConvertTextToSlug(oEmailData.Subject))
End If End If
_logger.Debug("Destination for eml file is {0}", oDestination) _logger.Debug("Destination for eml file is {0}", oDestination)
@ -102,6 +116,8 @@ Public Class ImportZUGFeRDFiles
Return Nothing Return Nothing
End If End If
'---------------------------
Try Try
_logger.Info("Moving email from {0} to {1}", oSource, oFinalFileName) _logger.Info("Moving email from {0} to {1}", oSource, oFinalFileName)
File.Move(oSource, oFinalFileName) File.Move(oSource, oFinalFileName)
@ -112,6 +128,8 @@ Public Class ImportZUGFeRDFiles
oEmailData.Attachment = oSource oEmailData.Attachment = oSource
End Try End Try
_logger.Info("Email [{0}] moved to rejected folder!", pMessageId)
Return oEmailData Return oEmailData
End Function End Function
@ -351,20 +369,9 @@ Public Class ImportZUGFeRDFiles
'If no errors occurred... 'If no errors occurred...
'Log the History 'Log the History
If oMD5CheckSum <> String.Empty Then If oMD5CheckSum <> String.Empty Then
Create_HistoryEntry(oMessageId, oMD5CheckSum, "SUCCESS", oSQLTransaction) _history.Create_HistoryEntry(oMessageId, oMD5CheckSum, "SUCCESS", oSQLTransaction)
'Dim oInsertCommand = $"INSERT INTO TBEDM_ZUGFERD_HISTORY_IN (MESSAGE_ID, MD5HASH) VALUES ('{oMessageId}', '{oMD5CheckSum}')"
'_firebird.ExecuteNonQueryWithConnection(oInsertCommand, oFBConnection, Firebird.TransactionMode.ExternalTransaction, oFBTransaction)
'' History ID is only need in case of an error
'oFBTransaction.Commit()
'Try
' Dim oSQL = $"SELECT MAX(GUID) FROM TBEDM_ZUGFERD_HISTORY_IN WHERE MESSAGE_ID = '{oMessageId}'"
' HISTORY_ID = _firebird.GetScalarValue(oSQL)
'Catch ex As Exception
' HISTORY_ID = 0
'End Try
Else Else
Create_HistoryEntry(oMessageId, String.Empty, "SUCCESS (with empty MD5Hash)", oSQLTransaction) _history.Create_HistoryEntry(oMessageId, String.Empty, "SUCCESS (with empty MD5Hash)", oSQLTransaction)
End If End If
oIsSuccess = True oIsSuccess = True
@ -375,7 +382,7 @@ Public Class ImportZUGFeRDFiles
Dim oErrors = ex.ValidationErrors Dim oErrors = ex.ValidationErrors
Dim oMessage = "REJECTED - ZUGFeRD yes but formal validation failed!" Dim oMessage = "REJECTED - ZUGFeRD yes but formal validation failed!"
Update_HistoryEntry(oMessageId, oMD5CheckSum, oMessage, oSQLTransaction) _history.Update_HistoryEntry(oMessageId, oMD5CheckSum, oMessage, oSQLTransaction)
Dim oErrorList As String = "" Dim oErrorList As String = ""
For Each oError In oErrors For Each oError In oErrors
@ -384,7 +391,6 @@ Public Class ImportZUGFeRDFiles
Dim oBody = String.Format(EmailStrings.EMAIL_VALIDATION_ERROR, oErrorList) Dim oBody = String.Format(EmailStrings.EMAIL_VALIDATION_ERROR, oErrorList)
Dim oEmailData = MoveAndRenameEmailToRejected(oArgs, oMessageId) Dim oEmailData = MoveAndRenameEmailToRejected(oArgs, oMessageId)
_email.AddToEmailQueueMSSQL(oMessageId, oBody, oEmailData, "ValidationException", _EmailOutAccountId, oArgs.NamePortal) _email.AddToEmailQueueMSSQL(oMessageId, oBody, oEmailData, "ValidationException", _EmailOutAccountId, oArgs.NamePortal)
AddRejectedState(oMessageId, "ValidationException", "Die Rechnungsvalidierung ist fehlgeschlagen!", "", oSQLTransaction) AddRejectedState(oMessageId, "ValidationException", "Die Rechnungsvalidierung ist fehlgeschlagen!", "", oSQLTransaction)
@ -394,7 +400,7 @@ Public Class ImportZUGFeRDFiles
' When MD5HashException is thrown, we don't have a MD5Hash yet. ' When MD5HashException is thrown, we don't have a MD5Hash yet.
' That 's why we set it to String.Empty here. ' That 's why we set it to String.Empty here.
Dim oMessage = "REJECTED - Already processed (MD5Hash)" Dim oMessage = "REJECTED - Already processed (MD5Hash)"
Update_HistoryEntry(oMessageId, String.Empty, oMessage, oSQLTransaction) _history.Update_HistoryEntry(oMessageId, String.Empty, oMessage, oSQLTransaction)
Dim oBody = EmailStrings.EMAIL_MD5_ERROR Dim oBody = EmailStrings.EMAIL_MD5_ERROR
Dim oEmailData = MoveAndRenameEmailToRejected(oArgs, oMessageId) Dim oEmailData = MoveAndRenameEmailToRejected(oArgs, oMessageId)
@ -406,7 +412,7 @@ Public Class ImportZUGFeRDFiles
' When UnsupportedFerdException is thrown, we don't have a MD5Hash yet. ' When UnsupportedFerdException is thrown, we don't have a MD5Hash yet.
' 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", oSQLTransaction) _history.Create_HistoryEntry(oMessageId, String.Empty, "REJECTED - ZUGFeRD yes but unsupported format", oSQLTransaction)
Dim oEmailData = MoveAndRenameEmailToRejected(oArgs, oMessageId) Dim oEmailData = MoveAndRenameEmailToRejected(oArgs, oMessageId)
Dim oBody As String = String.Format(EmailStrings.EMAIL_UNSUPPORTED_DOCUMENT, oEmailData.Subject, ex.XmlFile) Dim oBody As String = String.Format(EmailStrings.EMAIL_UNSUPPORTED_DOCUMENT, oEmailData.Subject, ex.XmlFile)
@ -419,7 +425,7 @@ Public Class ImportZUGFeRDFiles
' When InvalidFerdException is thrown, we don't have a MD5Hash yet. ' When InvalidFerdException is thrown, we don't have a MD5Hash yet.
' 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 incorrect format", oSQLTransaction) _history.Create_HistoryEntry(oMessageId, String.Empty, "REJECTED - ZUGFeRD yes but incorrect format", oSQLTransaction)
Dim oEmailData = MoveAndRenameEmailToRejected(oArgs, oMessageId) Dim oEmailData = MoveAndRenameEmailToRejected(oArgs, oMessageId)
Dim oBody = String.Format(EmailStrings.EMAIL_INVALID_DOCUMENT, oEmailData.Subject) Dim oBody = String.Format(EmailStrings.EMAIL_INVALID_DOCUMENT, oEmailData.Subject)
@ -430,7 +436,7 @@ Public Class ImportZUGFeRDFiles
Catch ex As TooMuchFerdsException Catch ex As TooMuchFerdsException
_logger.Error(ex) _logger.Error(ex)
Create_HistoryEntry(oMessageId, oMD5CheckSum, "REJECTED - More than one ZUGFeRD-document in email", oSQLTransaction) _history.Create_HistoryEntry(oMessageId, oMD5CheckSum, "REJECTED - More than one ZUGFeRD-document in email", oSQLTransaction)
Dim oEmailData = MoveAndRenameEmailToRejected(oArgs, oMessageId) Dim oEmailData = MoveAndRenameEmailToRejected(oArgs, oMessageId)
Dim oBody = String.Format(EmailStrings.EMAIL_TOO_MUCH_FERDS, oEmailData.Subject) Dim oBody = String.Format(EmailStrings.EMAIL_TOO_MUCH_FERDS, oEmailData.Subject)
@ -441,7 +447,7 @@ Public Class ImportZUGFeRDFiles
Catch ex As NoFerdsException Catch ex As NoFerdsException
_logger.Error(ex) _logger.Error(ex)
Create_HistoryEntry(oMessageId, oMD5CheckSum, "REJECTED - no ZUGFeRD-Document in email", oSQLTransaction) _history.Create_HistoryEntry(oMessageId, oMD5CheckSum, "REJECTED - no ZUGFeRD-Document in email", oSQLTransaction)
Dim oEmailData = MoveAndRenameEmailToRejected(oArgs, oMessageId) Dim oEmailData = MoveAndRenameEmailToRejected(oArgs, oMessageId)
Dim oBody = String.Format(EmailStrings.EMAIL_NO_FERDS, oEmailData.Subject) Dim oBody = String.Format(EmailStrings.EMAIL_NO_FERDS, oEmailData.Subject)
@ -449,11 +455,6 @@ Public Class ImportZUGFeRDFiles
_email.AddToEmailQueueMSSQL(oMessageId, oBody, oEmailData, "NoFerdsException", _EmailOutAccountId, oArgs.NamePortal) _email.AddToEmailQueueMSSQL(oMessageId, oBody, oEmailData, "NoFerdsException", _EmailOutAccountId, oArgs.NamePortal)
AddRejectedState(oMessageId, "NoFerdsException", " Email enthielt keine ZUGFeRD-Dokumente", "", oSQLTransaction) AddRejectedState(oMessageId, "NoFerdsException", " Email enthielt keine ZUGFeRD-Dokumente", "", oSQLTransaction)
Catch ex As NoFerdsAlternateException
' TODO: Maybe dont even log this 'error', since it's not really an error and it might happen *A LOT*
_logger.Error(ex)
oMoveDirectory = oArgs.NonZugferdDirectory
Catch ex As MissingValueException Catch ex As MissingValueException
_logger.Error(ex) _logger.Error(ex)
@ -462,9 +463,9 @@ Public Class ImportZUGFeRDFiles
oMessage &= $"- {prop}" oMessage &= $"- {prop}"
Next Next
Create_HistoryEntry(oMessageId, oMD5CheckSum, $"REJECTED - Missing Required Properties: [{oMessage}]", oSQLTransaction) _history.Create_HistoryEntry(oMessageId, oMD5CheckSum, $"REJECTED - Missing Required Properties: [{oMessage}]", oSQLTransaction)
Dim oBody = CreateBodyForMissingProperties(ex.File.Name, oMissingProperties) Dim oBody = _email.CreateBodyForMissingProperties(ex.File.Name, oMissingProperties)
Dim oEmailData = MoveAndRenameEmailToRejected(oArgs, oMessageId) Dim oEmailData = MoveAndRenameEmailToRejected(oArgs, oMessageId)
_email.AddToEmailQueueMSSQL(oMessageId, oBody, oEmailData, "MissingValueException", _EmailOutAccountId, oArgs.NamePortal) _email.AddToEmailQueueMSSQL(oMessageId, oBody, oEmailData, "MissingValueException", _EmailOutAccountId, oArgs.NamePortal)
AddRejectedState(oMessageId, "MissingValueException", "Es fehlten ZugferdSpezifikationen", oMessage, oSQLTransaction) AddRejectedState(oMessageId, "MissingValueException", "Es fehlten ZugferdSpezifikationen", oMessage, oSQLTransaction)
@ -472,7 +473,7 @@ Public Class ImportZUGFeRDFiles
Catch ex As FileSizeLimitReachedException Catch ex As FileSizeLimitReachedException
_logger.Error(ex) _logger.Error(ex)
Create_HistoryEntry(oMessageId, oMD5CheckSum, "REJECTED - File size limit reached", oSQLTransaction) _history.Create_HistoryEntry(oMessageId, oMD5CheckSum, "REJECTED - File size limit reached", oSQLTransaction)
Dim oEmailData = MoveAndRenameEmailToRejected(oArgs, oMessageId) Dim oEmailData = MoveAndRenameEmailToRejected(oArgs, oMessageId)
@ -487,12 +488,18 @@ Public Class ImportZUGFeRDFiles
_email.AddToEmailQueueMSSQL(oMessageId, oBody, oEmailData, "FileSizeLimitReachedException", _EmailOutAccountId, oArgs.NamePortal) _email.AddToEmailQueueMSSQL(oMessageId, oBody, oEmailData, "FileSizeLimitReachedException", _EmailOutAccountId, oArgs.NamePortal)
AddRejectedState(oMessageId, "FileSizeLimitReachedException", "Erlaubte Dateigröße überschritten", "", oSQLTransaction) AddRejectedState(oMessageId, "FileSizeLimitReachedException", "Erlaubte Dateigröße überschritten", "", oSQLTransaction)
Catch ex As NoFerdsAlternateException
' TODO: Maybe dont even log this 'error', since it's not really an error and it might happen *A LOT*
_logger.Error(ex)
oMoveDirectory = oArgs.NonZugferdDirectory
Catch ex As OutOfMemoryException Catch ex As OutOfMemoryException
_logger.Warn("OutOfMemory Error occurred: {0}", ex.Message) _logger.Warn("OutOfMemory Error occurred: {0}", ex.Message)
_logger.Error(ex) _logger.Error(ex)
' Send Email to Digital Data ' Send Email to Digital Data
Dim oBody = CreateBodyForUnhandledException(oMessageId, ex) Dim oBody = _email.CreateBodyForUnhandledException(oMessageId, ex)
Dim oEmailData As New EmailData With { Dim oEmailData As New EmailData With {
.From = oArgs.ExceptionEmailAddress, .From = oArgs.ExceptionEmailAddress,
.Subject = $"OutOfMemoryException im ZUGFeRD-Parser @ {oMessageId}" .Subject = $"OutOfMemoryException im ZUGFeRD-Parser @ {oMessageId}"
@ -511,7 +518,7 @@ Public Class ImportZUGFeRDFiles
_logger.Error(ex) _logger.Error(ex)
' Send Email to Digital Data ' Send Email to Digital Data
Dim oBody = CreateBodyForUnhandledException(oMessageId, ex) Dim oBody = _email.CreateBodyForUnhandledException(oMessageId, ex)
Dim oEmailData As New EmailData With { Dim oEmailData As New EmailData With {
.From = oArgs.ExceptionEmailAddress, .From = oArgs.ExceptionEmailAddress,
.Subject = $"UnhandledException im ZUGFeRD-Parser @ {oMessageId}" .Subject = $"UnhandledException im ZUGFeRD-Parser @ {oMessageId}"
@ -532,12 +539,12 @@ Public Class ImportZUGFeRDFiles
_logger.Info("Application Error occurred. Files for message Id {0} will not be moved.", oMessageId) _logger.Info("Application Error occurred. Files for message Id {0} will not be moved.", oMessageId)
Else Else
' Move all files of the current group ' Move all files of the current group
MoveFiles(oArgs, oMessageId, oFileGroupFiles, oEmailAttachmentFiles, oEmbeddedAttachmentFiles, oMoveDirectory, oIsSuccess) _file.MoveFiles(oArgs, oMessageId, oFileGroupFiles, oEmailAttachmentFiles, oEmbeddedAttachmentFiles, oMoveDirectory, oIsSuccess)
End If End If
_logger.Info("Finished processing file group {0}", oMessageId) _logger.Info("Finished processing file group {0}", oMessageId)
Catch ex As Exception Catch ex As Exception
' Send Email to Digital Data ' Send Email to Digital Data
Dim oBody = CreateBodyForUnhandledException(oMessageId, ex) Dim oBody = _email.CreateBodyForUnhandledException(oMessageId, ex)
Dim oEmailData As New EmailData With { Dim oEmailData As New EmailData With {
.From = oArgs.ExceptionEmailAddress, .From = oArgs.ExceptionEmailAddress,
.Subject = $"FileMoveException im ZUGFeRD-Parser @ {oMessageId}" .Subject = $"FileMoveException im ZUGFeRD-Parser @ {oMessageId}"
@ -612,123 +619,6 @@ Public Class ImportZUGFeRDFiles
End If End If
End Sub End Sub
Private Function DoGetPropertyMapFor(pWorkerArgs As WorkerArgs, pSpecification As String) As Dictionary(Of String, XmlItemProperty)
Return pWorkerArgs.PropertyMap.
Where(Function(kv) kv.Value.Specification = pSpecification).
ToDictionary(Function(kv) kv.Key, Function(kv) kv.Value)
End Function
Private Sub MoveFiles(
Args As WorkerArgs,
MessageId As String,
Files As List(Of FileInfo),
AttachmentFiles As List(Of FileInfo),
EmbeddedAttachments As List(Of PDFEmbeds.EmbeddedFile),
MoveDirectory As String,
IsSuccess As Boolean)
Dim oFinalMoveDirectory As String = MoveDirectory
Dim oDateSubDirectoryName As String = Now.ToString("yyyy\\MM\\dd")
Dim oAttachmentDirectory As String = Path.Combine(oFinalMoveDirectory, Args.AttachmentsSubDirectory, oDateSubDirectoryName)
' Files will be moved to a subfolder for the current day if they are rejected
If Not IsSuccess Then
oFinalMoveDirectory = Path.Combine(oFinalMoveDirectory, oDateSubDirectoryName)
End If
' Create directories if they don't exist
If Not Directory.Exists(oFinalMoveDirectory) Then
Try
Directory.CreateDirectory(oFinalMoveDirectory)
Catch ex As Exception
_logger.Error(ex)
End Try
End If
If Not Directory.Exists(oAttachmentDirectory) And AttachmentFiles.Count > 0 Then
Try
Directory.CreateDirectory(oAttachmentDirectory)
Catch ex As Exception
_logger.Error(ex)
End Try
End If
' Filter out Attachments from `Files`
Dim oInvoiceFiles As List(Of FileInfo) = Files.Except(AttachmentFiles).ToList()
' Move PDF/A Files
For Each oFile In oInvoiceFiles
Try
Dim oFilePath = _filesystem.GetVersionedFilename(Path.Combine(oFinalMoveDirectory, oFile.Name))
_filesystem.MoveTo(oFile.FullName, oFilePath, oFinalMoveDirectory)
_logger.Info("File moved to {0}", oFilePath)
Catch ex As Exception
_logger.Warn("Could not move file {0}", oFile.FullName)
_logger.Error(ex)
End Try
Next
' Move non-PDF/A Email Attachments/Files
For Each oFile In AttachmentFiles
Try
Dim oFilePath = _filesystem.GetVersionedFilename(Path.Combine(oAttachmentDirectory, oFile.Name))
_filesystem.MoveTo(oFile.FullName, oFilePath, oAttachmentDirectory)
_logger.Info("Attachment moved to {0}", oFilePath)
Catch ex As Exception
_logger.Warn("Could not move attachment {0}", oFile.FullName)
_logger.Error(ex)
End Try
Next
' Write Embedded Files to disk
For Each oResult In EmbeddedAttachments
Try
Dim oFileName As String = $"{MessageId}~{oResult.FileName}"
Dim oFilePath As String = Path.Combine(oAttachmentDirectory, oFileName)
If Not File.Exists(oAttachmentDirectory) Then
Directory.CreateDirectory(oAttachmentDirectory)
End If
Using oWriter As New FileStream(oFilePath, FileMode.Create)
oWriter.Write(oResult.FileContents, 0, oResult.FileContents.Length)
_logger.Info("Embedded Attachment moved to {0}", oFilePath)
End Using
Catch ex As Exception
_logger.Warn("Could not save embedded attachment {0}", oResult.FileName)
_logger.Error(ex)
End Try
Next
_logger.Info("Finished moving files")
End Sub
Private Function CreateBodyForMissingProperties(OriginalFilename As String, MissingProperties As List(Of String)) As String
Dim oBody = String.Format(EmailStrings.EMAIL_MISSINGPROPERTIES_1, OriginalFilename)
If MissingProperties.Count > 0 Then
oBody &= $"{vbNewLine}{vbNewLine}"
oBody &= EmailStrings.EMAIL_MISSINGPROPERTIES_2
oBody &= $"{vbNewLine}{vbNewLine}"
For Each prop In MissingProperties
oBody &= $"- {prop}"
Next
End If
Return oBody
End Function
Private Function CreateBodyForUnhandledException(MessageId As String, Exception As Exception) As String
Dim oBody = String.Format(EmailStrings.EMAIL_UNHANDLED_EXCEPTION, MessageId, Exception.Message, Exception.StackTrace)
Return oBody
End Function
Private Function CreateMD5(ByVal Filename As String) As String Private Function CreateMD5(ByVal Filename As String) As String
Try Try
Dim oMD5 As New MD5CryptoServiceProvider Dim oMD5 As New MD5CryptoServiceProvider
@ -749,55 +639,7 @@ Public Class ImportZUGFeRDFiles
End Try End Try
End Function End Function
Private Function Create_HistoryEntry(MessageId As String, MD5Checksum As String, Message As String, Transaction As SqlTransaction) As Boolean
Try
_logger.Info("Creating History Entry for MessageId [{0}] with comment [{1}]", MessageId, Message)
Dim oSQL = $"INSERT INTO TBEMLP_HISTORY (COMMENT, MD5HASH, EMAIL_MSGID) VALUES ('{Message}', '{MD5Checksum}', '{MessageId}')"
Using oConnection = _mssql.GetConnection()
' 09.07.2021: This can't be in the transaction since the history
' Entry needs to be accessed by MoveAndRenameEmailToRejected shortly after
_mssql.ExecuteNonQueryWithConnectionObject(oSQL, oConnection)
If Message.Contains("REJECTED") Then
oSQL = $"UPDATE TBEMLP_HISTORY SET STATUS = 'REJECTED', COMMENT = '{Message}', CUST_REJECTED = 1,CUST_REJECTED_WHEN = GETDATE() WHERE EMAIL_MSGID = '{MessageId}'"
_mssql.ExecuteNonQueryWithConnectionObject(oSQL, oConnection)
End If
_logger.Debug("History Entry created!")
End Using
Return True
Catch ex As Exception
_logger.Warn("History Entry count not be created for message id [{0}] and md5 [{1}]", MessageId, MD5Checksum)
_logger.Error(ex)
Return False
End Try
End Function
Private Function Update_HistoryEntry(MessageId As String, MD5Checksum As String, Message As String, Transaction As SqlTransaction) As Boolean
Try
_logger.Info("Updating History Entry for MessageId [{0}] with comment [{1}]", MessageId, Message)
' Only look for history entry by MessageId since the MD5 Hash might not be generated yet
Using oConnection = _mssql.GetConnection()
' 09.07.2021: This can't be in the transaction since the history
' Entry needs to be accessed by MoveAndRenameEmailToRejected shortly after
Dim oSQL = $"UPDATE TBEMLP_HISTORY SET COMMENT = '{Message}' WHERE EMAIL_MSGID = '{MessageId}'"
_mssql.ExecuteNonQueryWithConnectionObject(oSQL, oConnection)
End Using
_logger.Debug("History Entry created!")
Return True
Catch ex As Exception
_logger.Warn("History Entry count not be updated for message id [{0}] and md5 [{1}]", MessageId, MD5Checksum)
_logger.Error(ex)
Return False
End Try
End Function
''' <summary> ''' <summary>
''' Generates the MD5 Checksum of a file and checks it against the histroy table TBEDM_ZUGFERD_HISTORY_IN ''' Generates the MD5 Checksum of a file and checks it against the histroy table TBEDM_ZUGFERD_HISTORY_IN