ZUGFeRDService: Integrate MSSQL Transactions, Rollback for Application Exceptions #MR-2

This commit is contained in:
Jonathan Jenne 2021-04-15 15:57:09 +02:00
parent 07ce5488df
commit f6fc3be8ed
2 changed files with 74 additions and 47 deletions

View File

@ -2,6 +2,7 @@
Imports DigitalData.Modules.Database Imports DigitalData.Modules.Database
Imports System.Data Imports System.Data
Imports System.IO Imports System.IO
Imports System.Data.SqlClient
Public Class EmailFunctions Public Class EmailFunctions
Private ReadOnly _logConfig As LogConfig Private ReadOnly _logConfig As LogConfig
@ -62,7 +63,7 @@ Public Class EmailFunctions
_logger.Error(ex) _logger.Error(ex)
End Try End Try
End Sub End Sub
Public Sub AddToEmailQueueMSSQL(MessageId As String, BodyText As String, pEmailData As EmailData, SourceProcedure As String, pEmailAccountId As Integer) Public Sub AddToEmailQueueMSSQL(MessageId As String, BodyText As String, pEmailData As EmailData, SourceProcedure As String, pEmailAccountId As Integer, Transaction As SqlTransaction)
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!")
Exit Sub Exit Sub
@ -97,7 +98,7 @@ Public Class EmailFunctions
_logger.Debug("Subject: {0}", oSubject) _logger.Debug("Subject: {0}", oSubject)
_logger.Debug("Body {0}", oFinalBodyText) _logger.Debug("Body {0}", oFinalBodyText)
Dim osql = $"Select MAX(GUID) FROM TBEMLP_HISTORY WHERE EMAIL_MSGID = '{MessageId}'" Dim osql = $"Select MAX(GUID) FROM TBEMLP_HISTORY WHERE EMAIL_MSGID = '{MessageId}'"
Dim oHistoryID = _mssql.GetScalarValue(osql) Dim oHistoryID = _mssql.GetScalarValue(osql, Transaction)
'osql = $"select * from TBEMLP_EMAIL_OUT where REFERENCE_ID = {oHistoryID} and EMAIL_ADRESS = '{oEmailTo}' and EMAIL_SUBJ = '{oSubject}'" 'osql = $"select * from TBEMLP_EMAIL_OUT where REFERENCE_ID = {oHistoryID} and EMAIL_ADRESS = '{oEmailTo}' and EMAIL_SUBJ = '{oSubject}'"
@ -128,7 +129,7 @@ Public Class EmailFunctions
,'{SourceProcedure}' ,'{SourceProcedure}'
,'{oCreatedWho}' ,'{oCreatedWho}'
,'{oAttachment}')" ,'{oAttachment}')"
_mssql.ExecuteNonQuery(oInsert) _mssql.ExecuteNonQuery(oInsert, Transaction)
Else Else
'If oDTResult.Rows.Count = 0 Then 'If oDTResult.Rows.Count = 0 Then
' _logger.Debug("Email has already been sent!!") ' _logger.Debug("Email has already been sent!!")
@ -173,7 +174,7 @@ Public Class EmailFunctions
Dim oAttachmentFile = MessageId & ".eml" Dim oAttachmentFile = MessageId & ".eml"
Dim oAttachmentPath = Path.Combine(oAttachmentDirectory, oAttachmentFile) Dim oAttachmentPath = Path.Combine(oAttachmentDirectory, oAttachmentFile)
If IO.File.Exists(oAttachmentPath) Then If File.Exists(oAttachmentPath) Then
Return oAttachmentPath Return oAttachmentPath
Else Else
_logger.Warn("Email File {0} does not exist. Empty String will be returned.", oAttachmentPath) _logger.Warn("Email File {0} does not exist. Empty String will be returned.", oAttachmentPath)

View File

@ -2,18 +2,14 @@
Imports System.Data Imports System.Data
Imports System.IO Imports System.IO
Imports System.Linq Imports System.Linq
Imports System.Reflection
Imports System.Security.Cryptography Imports System.Security.Cryptography
Imports System.Text.RegularExpressions
Imports System.Xml
Imports DigitalData.Modules.Filesystem
Imports DigitalData.Modules.Database Imports DigitalData.Modules.Database
Imports DigitalData.Modules.Interfaces 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 FirebirdSql.Data.FirebirdClient
Imports GdPicture14 Imports System.Data.SqlClient
Public Class ImportZUGFeRDFiles Public Class ImportZUGFeRDFiles
Implements IJob Implements IJob
@ -111,11 +107,11 @@ Public Class ImportZUGFeRDFiles
Return oEmailData Return oEmailData
End Function End Function
Private Sub AddRejectedState(oMessageID As String, oTitle As String, oTitle1 As String, oComment As String) Private Sub AddRejectedState(oMessageID As String, oTitle As String, oTitle1 As String, oComment As String, Transaction As SqlTransaction)
Try Try
'PRCUST_ADD_HISTORY_STATE: @MessageID VARCHAR(250), @TITLE1 VARCHAR(250), @TITLE2 VARCHAR(250) 'PRCUST_ADD_HISTORY_STATE: @MessageID VARCHAR(250), @TITLE1 VARCHAR(250), @TITLE2 VARCHAR(250)
Dim oSQL = $"EXEC PRCUST_ADD_HISTORY_STATE '{oMessageID}','{oTitle}','{oTitle1}','{oComment.Replace("'", "''")}'" Dim oSQL = $"EXEC PRCUST_ADD_HISTORY_STATE '{oMessageID}','{oTitle}','{oTitle1}','{oComment.Replace("'", "''")}'"
_mssql.ExecuteNonQuery(oSQL) _mssql.ExecuteNonQuery(oSQL, Transaction)
Catch ex As Exception Catch ex As Exception
_logger.Error(ex) _logger.Error(ex)
End Try End Try
@ -159,12 +155,18 @@ Public Class ImportZUGFeRDFiles
For Each oFileGroup In oGrouped For Each oFileGroup In oGrouped
' Start a new transaction for each file group. ' Start a new transaction for each file group.
' This way we can rollback database changes for the whole filegroup in case something goes wrong. ' This way we can rollback database changes for the whole filegroup in case something goes wrong.
Dim oConnection As FbConnection = _firebird.GetConnection() Dim oFBConnection As FbConnection = _firebird.GetConnection()
Dim oTransaction As FbTransaction = oConnection.BeginTransaction() Dim oFBTransaction As FbTransaction = oFBConnection.BeginTransaction()
Dim oSQLConnection As SqlConnection = _mssql.GetConnection()
Dim oSQLTransaction As SqlTransaction = oSQLConnection.BeginTransaction()
' Count the amount of ZUGFeRD files ' Count the amount of ZUGFeRD files
Dim oZUGFeRDCount As Integer = 0 Dim oZUGFeRDCount As Integer = 0
' Set the default Move Directory ' Set the default Move Directory
Dim oMoveDirectory As String = oArgs.ErrorDirectory Dim oMoveDirectory As String = oArgs.ErrorDirectory
' Flag to save if the whole process was a success. ' Flag to save if the whole process was a success.
' Will be set only at the end of the function if no error occurred. ' Will be set only at the end of the function if no error occurred.
Dim oIsSuccess As Boolean = False Dim oIsSuccess As Boolean = False
@ -275,10 +277,9 @@ Public Class ImportZUGFeRDFiles
Dim oDelSQL = $"DELETE FROM TBEDMI_ITEM_VALUE where REFERENCE_GUID = '{oMessageId}'" Dim oDelSQL = $"DELETE FROM TBEDMI_ITEM_VALUE where REFERENCE_GUID = '{oMessageId}'"
Dim oStep As String Dim oStep As String
oStep = "Firebird TBEDMI_ITEM_VALUE Delete messageID Items" oStep = "Firebird TBEDMI_ITEM_VALUE Delete messageID Items"
Try Try
_firebird.ExecuteNonQueryWithConnection(oDelSQL, oConnection, Firebird.TransactionMode.ExternalTransaction, oTransaction) _firebird.ExecuteNonQueryWithConnection(oDelSQL, oFBConnection)
Catch ex As Exception Catch ex As Exception
_logger.Error(ex) _logger.Error(ex)
_logger.Warn("Step [{0}] with SQL [{1}] was not successful.", oStep, oDelSQL) _logger.Warn("Step [{0}] with SQL [{1}] was not successful.", oStep, oDelSQL)
@ -287,7 +288,7 @@ Public Class ImportZUGFeRDFiles
If oArgs.InsertIntoSQLServer = True Then If oArgs.InsertIntoSQLServer = True Then
oStep = "MSSQL TBEDMI_ITEM_VALUE Delete messageID Items" oStep = "MSSQL TBEDMI_ITEM_VALUE Delete messageID Items"
Try Try
_mssql.ExecuteNonQuery(oDelSQL) _mssql.ExecuteNonQueryWithConnectionObject(oDelSQL, oSQLConnection)
Catch ex As Exception Catch ex As Exception
_logger.Warn("Step [{0}] with SQL [{1}] was not successful.", oStep, oDelSQL) _logger.Warn("Step [{0}] with SQL [{1}] was not successful.", oStep, oDelSQL)
End Try End Try
@ -307,13 +308,13 @@ Public Class ImportZUGFeRDFiles
_logger.Debug("Mapping Property [{0}] with value [{1}], Will be inserted into table [{2}]", oProperty.TableColumn, oProperty.Value.Replace("'", "''"), oProperty.TableName) _logger.Debug("Mapping Property [{0}] with value [{1}], Will be inserted into table [{2}]", oProperty.TableColumn, oProperty.Value.Replace("'", "''"), oProperty.TableName)
' Insert into SQL Server ' Insert into SQL Server
If oArgs.InsertIntoSQLServer = True Then If oArgs.InsertIntoSQLServer = True Then
Dim oResult = _mssql.ExecuteNonQuery(oCommand) Dim oResult = _mssql.ExecuteNonQueryWithConnectionObject(oCommand, oSQLConnection, MSSQLServer.TransactionMode.ExternalTransaction, oSQLTransaction)
If oResult = False Then If oResult = False Then
_logger.Warn($"SQL Command [{oCommand}] was not successful. Check the log.") _logger.Warn($"SQL Command [{oCommand}] was not successful. Check the log.")
End If End If
End If End If
' Insert into Firebird ' Insert into Firebird
_firebird.ExecuteNonQueryWithConnection(oCommand, oConnection, Firebird.TransactionMode.ExternalTransaction, oTransaction) _firebird.ExecuteNonQueryWithConnection(oCommand, oFBConnection, Firebird.TransactionMode.ExternalTransaction, oFBTransaction)
Next Next
Next Next
@ -326,9 +327,11 @@ Public Class ImportZUGFeRDFiles
'Log the History 'Log the History
If oMD5CheckSum <> String.Empty Then If oMD5CheckSum <> String.Empty Then
Dim oInsertCommand = $"INSERT INTO TBEDM_ZUGFERD_HISTORY_IN (MESSAGE_ID, MD5HASH) VALUES ('{oMessageId}', '{oMD5CheckSum}')" Dim oInsertCommand = $"INSERT INTO TBEDM_ZUGFERD_HISTORY_IN (MESSAGE_ID, MD5HASH) VALUES ('{oMessageId}', '{oMD5CheckSum}')"
_firebird.ExecuteNonQueryWithConnection(oInsertCommand, oConnection, Firebird.TransactionMode.ExternalTransaction, oTransaction) _firebird.ExecuteNonQueryWithConnection(oInsertCommand, oFBConnection, Firebird.TransactionMode.ExternalTransaction, oFBTransaction)
'commit the transaction
oTransaction.Commit() ' History ID is only need in case of an error
oFBTransaction.Commit()
Try Try
Dim oSQL = $"SELECT MAX(GUID) FROM TBEDM_ZUGFERD_HISTORY_IN WHERE MESSAGE_ID = '{oMessageId}'" Dim oSQL = $"SELECT MAX(GUID) FROM TBEDM_ZUGFERD_HISTORY_IN WHERE MESSAGE_ID = '{oMessageId}'"
HISTORY_ID = _firebird.GetScalarValue(oSQL) HISTORY_ID = _firebird.GetScalarValue(oSQL)
@ -342,55 +345,55 @@ Public Class ImportZUGFeRDFiles
Catch ex As MD5HashException Catch ex As MD5HashException
_logger.Error(ex) _logger.Error(ex)
oTransaction.Rollback() 'oFBTransaction.Rollback()
Dim oSQL = $"UPDATE TBEDM_ZUGFERD_HISTORY_IN SET COMMENT = 'REJECTED - Already processed (MD5Hash)' WHERE GUID = '{HISTORY_ID}'" Dim oSQL = $"UPDATE TBEDM_ZUGFERD_HISTORY_IN SET COMMENT = 'REJECTED - Already processed (MD5Hash)' WHERE GUID = '{HISTORY_ID}'"
_firebird.ExecuteNonQuery(oSQL) _firebird.ExecuteNonQuery(oSQL)
Dim oBody = EmailStrings.EMAIL_MD5_ERROR Dim oBody = EmailStrings.EMAIL_MD5_ERROR
Dim oEmailData = MoveAndRenameEmailToRejected(oArgs, oMessageId) Dim oEmailData = MoveAndRenameEmailToRejected(oArgs, oMessageId)
_email.AddToEmailQueueMSSQL(oMessageId, oBody, oEmailData, "MD5HashException", _EmailOutAccountId) _email.AddToEmailQueueMSSQL(oMessageId, oBody, oEmailData, "MD5HashException", _EmailOutAccountId, oSQLTransaction)
AddRejectedState(oMessageId, "MD5HashException", "Die gesendete Rechnung wurde bereits verarbeitet!", "") AddRejectedState(oMessageId, "MD5HashException", "Die gesendete Rechnung wurde bereits verarbeitet!", "", oSQLTransaction)
Catch ex As InvalidFerdException Catch ex As InvalidFerdException
_logger.Error(ex) _logger.Error(ex)
oTransaction.Rollback() 'oFBTransaction.Rollback()
Dim oSQL = $"UPDATE TBEDM_ZUGFERD_HISTORY_IN SET COMMENT = 'REJECTED - ZUGFeRD yes but incorrect format' WHERE GUID = '{HISTORY_ID}'" Dim oSQL = $"UPDATE TBEDM_ZUGFERD_HISTORY_IN SET COMMENT = 'REJECTED - ZUGFeRD yes but incorrect format' WHERE GUID = '{HISTORY_ID}'"
_firebird.ExecuteNonQuery(oSQL) _firebird.ExecuteNonQuery(oSQL)
Dim oBody = EmailStrings.EMAIL_INVALID_DOCUMENT Dim oBody = EmailStrings.EMAIL_INVALID_DOCUMENT
Dim oEmailData = MoveAndRenameEmailToRejected(oArgs, oMessageId) Dim oEmailData = MoveAndRenameEmailToRejected(oArgs, oMessageId)
_email.AddToEmailQueueMSSQL(oMessageId, oBody, oEmailData, "InvalidFerdException", _EmailOutAccountId) _email.AddToEmailQueueMSSQL(oMessageId, oBody, oEmailData, "InvalidFerdException", _EmailOutAccountId, oSQLTransaction)
AddRejectedState(oMessageId, "InvalidFerdException", "Inkorrekte Formate", "") AddRejectedState(oMessageId, "InvalidFerdException", "Inkorrekte Formate", "", oSQLTransaction)
Catch ex As TooMuchFerdsException Catch ex As TooMuchFerdsException
_logger.Error(ex) _logger.Error(ex)
oTransaction.Rollback() 'oFBTransaction.Rollback()
Dim oSQL = $"UPDATE TBEDM_ZUGFERD_HISTORY_IN SET COMMENT = 'REJECTED - More than one ZUGFeRD-document in email' WHERE GUID = '{HISTORY_ID}'" Dim oSQL = $"UPDATE TBEDM_ZUGFERD_HISTORY_IN SET COMMENT = 'REJECTED - More than one ZUGFeRD-document in email' WHERE GUID = '{HISTORY_ID}'"
_firebird.ExecuteNonQuery(oSQL) _firebird.ExecuteNonQuery(oSQL)
Dim oBody = EmailStrings.EMAIL_TOO_MUCH_FERDS Dim oBody = EmailStrings.EMAIL_TOO_MUCH_FERDS
Dim oEmailData = MoveAndRenameEmailToRejected(oArgs, oMessageId) Dim oEmailData = MoveAndRenameEmailToRejected(oArgs, oMessageId)
_email.AddToEmailQueueMSSQL(oMessageId, oBody, oEmailData, "TooMuchFerdsException", _EmailOutAccountId) _email.AddToEmailQueueMSSQL(oMessageId, oBody, oEmailData, "TooMuchFerdsException", _EmailOutAccountId, oSQLTransaction)
AddRejectedState(oMessageId, "TooMuchFerdsException", "Email enthielt mehr als ein ZUGFeRD-Dokument", "") AddRejectedState(oMessageId, "TooMuchFerdsException", "Email enthielt mehr als ein ZUGFeRD-Dokument", "", oSQLTransaction)
Catch ex As NoFerdsException Catch ex As NoFerdsException
_logger.Error(ex) _logger.Error(ex)
oTransaction.Rollback() 'oFBTransaction.Rollback()
Dim oSQL = $"UPDATE TBEDM_ZUGFERD_HISTORY_IN SET COMMENT = 'REJECTED - no ZUGFeRD-Document in email' WHERE GUID = '{HISTORY_ID}'" Dim oSQL = $"UPDATE TBEDM_ZUGFERD_HISTORY_IN SET COMMENT = 'REJECTED - no ZUGFeRD-Document in email' WHERE GUID = '{HISTORY_ID}'"
_firebird.ExecuteNonQuery(oSQL) _firebird.ExecuteNonQuery(oSQL)
Dim oBody = EmailStrings.EMAIL_NO_FERDS Dim oBody = EmailStrings.EMAIL_NO_FERDS
Dim oEmailData = MoveAndRenameEmailToRejected(oArgs, oMessageId) Dim oEmailData = MoveAndRenameEmailToRejected(oArgs, oMessageId)
_email.AddToEmailQueueMSSQL(oMessageId, oBody, oEmailData, "NoFerdsException", _EmailOutAccountId) _email.AddToEmailQueueMSSQL(oMessageId, oBody, oEmailData, "NoFerdsException", _EmailOutAccountId, oSQLTransaction)
AddRejectedState(oMessageId, "NoFerdsException", " Email enthielt keine ZUGFeRD-Dokumente", "") AddRejectedState(oMessageId, "NoFerdsException", " Email enthielt keine ZUGFeRD-Dokumente", "", oSQLTransaction)
Catch ex As MissingValueException Catch ex As MissingValueException
_logger.Error(ex) _logger.Error(ex)
oTransaction.Rollback() 'oFBTransaction.Rollback()
Dim oMessage As String = "" Dim oMessage As String = ""
For Each prop In oMissingProperties For Each prop In oMissingProperties
@ -401,33 +404,56 @@ Public Class ImportZUGFeRDFiles
Dim oBody = CreateBodyForMissingProperties(ex.File.Name, oMissingProperties) Dim oBody = CreateBodyForMissingProperties(ex.File.Name, oMissingProperties)
Dim oEmailData = MoveAndRenameEmailToRejected(oArgs, oMessageId) Dim oEmailData = MoveAndRenameEmailToRejected(oArgs, oMessageId)
_email.AddToEmailQueueMSSQL(oMessageId, oBody, oEmailData, "MissingValueException", _EmailOutAccountId) _email.AddToEmailQueueMSSQL(oMessageId, oBody, oEmailData, "MissingValueException", _EmailOutAccountId, oSQLTransaction)
AddRejectedState(oMessageId, "MissingValueException", "Es fehlten ZugferdSpezifikationen", oMessage) AddRejectedState(oMessageId, "MissingValueException", "Es fehlten ZugferdSpezifikationen", oMessage, oSQLTransaction)
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)
oTransaction.Rollback()
' Rollback Firebird
oFBTransaction.Rollback()
' Rollback MSSQL
oSQLTransaction.Rollback()
oMoveDirectory = DIRECTORY_DONT_MOVE oMoveDirectory = DIRECTORY_DONT_MOVE
'Dim oSQL = $"UPDATE TBEDM_ZUGFERD_HISTORY_IN SET COMMENT = 'REJECTED - Out of memory' WHERE GUID = '{HISTORY_ID}'"
'_firebird.ExecuteNonQuery(oSQL)
'AddRejectedState(oMessageId, "OutOfMemoryException", "", ex.Message)
Catch ex As Exception Catch ex As Exception
_logger.Warn("Unknown Error occurred: {0}", ex.Message) _logger.Warn("Unknown Error occurred: {0}", ex.Message)
_logger.Error(ex) _logger.Error(ex)
oTransaction.Rollback()
' Rollback Firebird
oFBTransaction.Rollback()
' Rollback MSSQL
oSQLTransaction.Rollback()
oMoveDirectory = DIRECTORY_DONT_MOVE oMoveDirectory = DIRECTORY_DONT_MOVE
'Dim oSQL = $"UPDATE TBEDM_ZUGFERD_HISTORY_IN SET COMMENT = 'REJECTED - Unknown error occured' WHERE GUID = '{HISTORY_ID}'"
'_firebird.ExecuteNonQuery(oSQL)
'oMoveDirectory = oArgs.ErrorDirectory
'AddRejectedState(oMessageId, "UnexpectedException", "", ex.Message)
Finally Finally
oConnection.Close() Try
' If everything went OK, finally commit all changes to the Database
' ==================================================================
If oIsSuccess Then
' Commit SQL Transaction
oSQLTransaction.Commit()
' Commit Firebird Transaction
oFBTransaction.Commit()
End If
Catch ex As Exception
_logger.Error(ex)
_logger.Warn("Database Transactions were not committed successfully.")
End Try
Try
oFBConnection.Close()
oSQLConnection.Close()
Catch ex As Exception
_logger.Error(ex)
_logger.Warn("Database Connections were not closed successfully.")
End Try
Try Try
' If an application error occurred, dont move files so they will be processed again later ' If an application error occurred, dont move files so they will be processed again later