Modules/Jobs/ZUGFeRD/ImportZUGFeRDFiles.vb

1250 lines
58 KiB
VB.net

Imports System.Collections.Generic
Imports System.Data
Imports System.Data.SqlClient
Imports System.IO
Imports System.Linq
Imports DigitalData.Modules.Base
Imports DigitalData.Modules.Config
Imports DigitalData.Modules.Database
Imports DigitalData.Modules.Interfaces
Imports DigitalData.Modules.Interfaces.Exceptions
Imports DigitalData.Modules.Interfaces.PropertyValues
Imports DigitalData.Modules.Jobs.Exceptions
Imports DigitalData.Modules.Logging
Imports GdPicture14
Public Class ImportZUGFeRDFiles
Implements IJob
Public Const ZUGFERD_IN = "ZUGFeRD in"
Public Const ZUGFERD_ERROR = "ZUGFeRD Error"
Public Const ZUGFERD_SUCCESS = "ZUGFeRD Success"
Public Const ZUGFERD_EML = "ZUGFeRD Eml"
Public Const ZUGFERD_REJECTED_EML = "ZUGFeRD Eml Rejected"
Public Const ZUGFERD_ATTACHMENTS = "ZUGFeRD Attachments"
Public Const ZUGFERD_NO_ZUGFERD = "Non-ZUGFeRD Files"
Public HISTORY_ID As Integer
Private Const DIRECTORY_DONT_MOVE = "DIRECTORY_DONT_MOVE"
Private Const MIME_TYPE_PDF = "application/pdf"
Private Const MIME_TYPE_XLSX = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
Private Const MIME_TYPE_ODT = "application/vnd.oasis.opendocument.spreadsheet"
' List of allowed extensions for PDF/A Attachments
' This list should not contain xml so the zugferd xml file will be filtered out
Private ReadOnly AllowedExtensions As New List(Of String) From {"docx", "doc", "pdf", "xls", "xlsx", "ppt", "pptx", "txt"}
' List of the Columns we need to store embedded files on disk and database
Private ReadOnly EmbeddedFilesColumnNames As List(Of String) = New List(Of String) From {
"ATTACHMENT_FILE_FILENAME", "ATTACHMENT_FILE_VALUE", "ATTACHMENT_FILE_MIMECODE"
}
' List of the allowed MIME-Codes
' Allowed Values are:
'- application/pdf
'- application/vnd.openxmlformats-officedocument.spreadsheetml.sheet (xlsx)
'- application/vnd.oasis.opendocument.spreadsheet (odt)
'- image/jpeg
'- image/png
'- image/tiff (UBL)
'- text/csv
'- text/xml (UBL)
Private ReadOnly AllowedMimeTypesInEmbeddedFiles As List(Of String) = New List(Of String) From {
MIME_TYPE_PDF,
MIME_TYPE_XLSX,
MIME_TYPE_ODT
}
Private ReadOnly _logger As Logger
Private ReadOnly _logConfig As LogConfig
Private ReadOnly _filesystem As FilesystemEx
Private ReadOnly _mssql As MSSQLServer
Private ReadOnly _email As ZUGFeRD.EmailFunctions
Private ReadOnly _file As ZUGFeRD.FileFunctions
Private ReadOnly _history As ZUGFeRD.HistoryFunctions
Private ReadOnly _hash As HashFunctions
Private ReadOnly _embeds As PDFEmbeds
Private SQL_xRechnung_ItemTemplate As String = ""
Private ReadOnly _gdpictureLicenseKey As String
Private ReadOnly _xRechnungCreator As XRechnungViewDocument
Private _zugferd As ZUGFeRDInterface
Private _EmailOutAccountId As Integer
Private MyTemplateValues_xInvDT As DataTable
Private Class ProcessFileResult
Public ZugferdFileFound As Boolean = False
Public ZugferdFileCount As Integer = 0
Public MD5Checksum As String = Nothing
Public EmailAttachmentFiles As New List(Of FileInfo)
Public EmbeddedAttachmentFiles As New List(Of PDFEmbeds.EmbeddedFile)
End Class
Private Class DatabaseConnections
Public Property SQLServerConnection As SqlConnection
Public Property SQLServerTransaction As SqlTransaction
End Class
Public Sub New(LogConfig As LogConfig, Optional MSSQL As MSSQLServer = Nothing)
_logConfig = LogConfig
_logger = LogConfig.GetLogger()
_filesystem = New FilesystemEx(_logConfig)
_mssql = MSSQL
_email = New ZUGFeRD.EmailFunctions(LogConfig, _mssql)
_file = New ZUGFeRD.FileFunctions(LogConfig, _mssql)
_history = New ZUGFeRD.HistoryFunctions(LogConfig, _mssql)
_embeds = New PDFEmbeds(LogConfig)
_hash = New HashFunctions(_logConfig, _mssql)
_xRechnungCreator = New XRechnungViewDocument(_logConfig, _mssql, _gdpictureLicenseKey)
_logger.Debug("Registering GDPicture License")
If _mssql IsNot Nothing Then
_gdpictureLicenseKey = ConfigDbFunct.GetProductLicense("GDPICTURE", "11.2024", _logConfig, _mssql.CurrentConnectionString)
Else
_logger.Warn("GDPicture License could not be registered! MSSQL is not enabled!")
Throw New ArgumentNullException("MSSQL")
End If
End Sub
Public Sub Start(Arguments As Object) Implements IJob.Start
Dim oArgs As WorkerArgs = Arguments
Dim oAttachmentExtractor = New PDFEmbeds(_logConfig)
_EmailOutAccountId = oArgs.EmailOutProfileId
_zugferd = New ZUGFeRDInterface(_logConfig, _gdpictureLicenseKey, New ZUGFeRDInterface.ZugferdOptions() With {
.AllowFacturX_Filename = oArgs.AllowFacturX,
.AllowXRechnung_Filename = oArgs.AllowXRechnung,
.AllowPeppol_3_x_Schema = oArgs.AllowPeppolBISBill3x
})
_logger.Debug("Starting Job {0}", [GetType].Name)
If oArgs.AllowXRechnung Then
' TODO - Config-Schalter hat NIX mit XRechnung-Dateien u. Sichtbelegen zu tun, sondern nur mit Dateinamen zu tun.
Dim oSQL = "SELECT SQL_COMMAND FROM TBDD_SQL_COMMANDS WHERE TITLE = 'VWDD_ZUGFERD_VIEW_RECEIPT_TEMPLATE_ITEMS'"
SQL_xRechnung_ItemTemplate = _mssql.GetScalarValue(oSQL)
End If
Try
'For Each oPath As String In oArgs.WatchDirectory
Dim oPath As String = oArgs.WatchDirectory
Dim oDirInfo As New DirectoryInfo(oPath)
_logger.Debug($"Start processing directory {oDirInfo.FullName}")
If oDirInfo.Exists = False Then
_logger.Warn("Watch directory exists. Exiting.")
Exit Sub
End If
' Filter out *.lock files
Dim oFiles As List(Of FileInfo) = oDirInfo.
GetFiles().
Where(Function(f) Not f.Name.EndsWith(".lock")).
ToList()
If oFiles.Count = 0 Then
_logger.Debug("No files to process. Exiting.")
Exit Sub
End If
_logger.Info("Found {0} files", oFiles.Count)
' Group files by messageId
Dim oGrouped As Dictionary(Of String, List(Of FileInfo)) = _zugferd.FileGroup.GroupFiles(oFiles)
_logger.Info("Found [{0}] file groups", oGrouped.Count)
'Process each file group together
'oGrouped equals one e-invoice
For Each oFileGroup In oGrouped
' Start a new transaction for each file group.
' This way we can rollback database changes for the whole filegroup in case something goes wrong.
Dim oSQLConnection As SqlConnection = _mssql.GetConnection()
Dim oSQLTransaction As SqlTransaction = oSQLConnection?.BeginTransaction()
Dim oConnections As New DatabaseConnections() With {
.SQLServerConnection = oSQLConnection,
.SQLServerTransaction = oSQLTransaction
}
' Count the amount of ZUGFeRD files
Dim oZUGFeRDCount As Integer = 0
' Set the default Move Directory
Dim oMoveDirectory As String = oArgs.ErrorDirectory
' Flag to save if the whole process was a success.
' Will be set only at the end of the function if no error occurred.
Dim oIsSuccess As Boolean = False
' Flag to save if the occurred error (if any) was expected
' Used to determine if transactions should be committed or not
Dim oExpectedError As Boolean = True
' Create file lists
Dim oEInvoiceFileGroup As List(Of FileInfo) = oFileGroup.Value
Dim oEmailAttachmentFiles As New List(Of FileInfo)
Dim oEmbeddedAttachmentFiles As New List(Of PDFEmbeds.EmbeddedFile)
Dim oMessageId As String = oFileGroup.Key
Dim oMD5CheckSum As String = String.Empty
_logger.Info("START processing file group {0}", oMessageId)
If _file.CheckFileAge(oEInvoiceFileGroup, oArgs.MinFileAgeInMinutes) Then
_logger.Info("At least one file was created less than [{0}] minutes ago. Skipping file group.", oArgs.MinFileAgeInMinutes)
Continue For
End If
Dim oEmailDataBase = _email.GetEmailDataForMessageId(oMessageId)
Dim oFileCounter As Integer = 0
Try
For Each oFile In oEInvoiceFileGroup
oFileCounter += 1
Dim oResult As ProcessFileResult
If oFileCounter = 1 AndAlso oFile.Name.ToUpper.EndsWith(".XML") Then
oResult = ProcessXMLFile(oMessageId, oZUGFeRDCount, oFile, oConnections, oArgs)
Else
oResult = ProcessFile(oMessageId, oZUGFeRDCount, oFile, oConnections, oArgs)
End If
If oResult.ZugferdFileFound = True Then
_logger.Debug("Zugferd File found")
oMD5CheckSum = oResult.MD5Checksum
oZUGFeRDCount = oResult.ZugferdFileCount
oEmailAttachmentFiles.AddRange(oResult.EmailAttachmentFiles)
oEmbeddedAttachmentFiles.AddRange(oResult.EmbeddedAttachmentFiles)
Else ' No zugferd found!
oEmailAttachmentFiles.AddRange(oResult.EmailAttachmentFiles)
oEmbeddedAttachmentFiles.AddRange(oResult.EmbeddedAttachmentFiles)
End If
Next
'Check if there are no ZUGFeRD files
If oZUGFeRDCount = 0 Then
' If NonZugferdDirectory is not set, a NoFerdsException will be thrown and a rejection will be generated
' This is the default/initial behaviour.
If String.IsNullOrEmpty(oArgs.NonZugferdDirectory) Then
Throw New NoFerdsException()
End If
' Also, if the directory is set but does not exist, still a rejection will be generated.
If Not Directory.Exists(oArgs.NonZugferdDirectory) Then
Throw New NoFerdsException()
End If
' Only if the directory is set and does exist, it will be used and any file groups which
' do NOT CONTAIN ANY ZUGFERD DOCUMENTS, are moved to that directory.
Throw New NoFerdsAlternateException()
End If
'If no errors occurred, update the history table for this MessageId
If String.IsNullOrEmpty(oMD5CheckSum) Then
_history.Update_HistoryEntry(oMessageId, String.Empty, "SUCCESS (with empty MD5Hash)")
Else
_history.Update_HistoryEntry(oMessageId, oMD5CheckSum, "SUCCESS")
End If
oIsSuccess = True
oMoveDirectory = oArgs.SuccessDirectory
Catch ex As ValidationException
_logger.Error(ex)
Dim oRejectionCodeString = GetRejectionCodeString(oMessageId, ErrorCode.ValidationException)
'Dim oMessage = "REJECTED - ZUGFeRD yes but formal validation failed!"
_history.Update_HistoryEntry(oMessageId, oMD5CheckSum, oRejectionCodeString)
Dim oErrors = ex.ValidationErrors
Dim oErrorList As String = ""
Dim oErrorListDE As String = ""
For Each oError In oErrors
oErrorList += $"<li>Element '{oError.ElementName}' with Value '{oError.ElementValue}': {oError.ErrorMessage}</li>"
oErrorListDE += $"<li>Element '{oError.ElementName}' mit Wert '{oError.ElementValue}': {oError.ErrorMessageDE}</li>"
Next
Dim oBody = String.Format(EmailStrings.EMAIL_VALIDATION_ERROR, oErrorList)
Dim oEmailData = _file.MoveAndRenameEmailToRejected(oArgs, oMessageId)
_email.AddToEmailQueueMSSQL(oMessageId, oSQLTransaction, oBody, oEmailData, "ValidationException", _EmailOutAccountId, oArgs.NamePortal, oArgs.RejectionTemplateId, ErrorCode.ValidationException, oErrorListDE, oErrorList)
AddRejectedState(oMessageId, oRejectionCodeString, "Die Rechnungsvalidierung ist fehlgeschlagen!", "", oSQLTransaction)
Catch ex As MD5HashException
_logger.Error(ex)
Dim oRejectionCodeString = GetRejectionCodeString(oMessageId, ErrorCode.MD5HashException)
' When MD5HashException is thrown, we don't have a MD5Hash yet.
' Thats why we set it to String.Empty here.
'Dim oMessage = "REJECTED - Already processed (MD5Hash)"
_history.Update_HistoryEntry(oMessageId, String.Empty, oRejectionCodeString)
Dim oBody = String.Format(EmailStrings.EMAIL_MD5_ERROR, ex.FileName)
Dim oEmailData = _file.MoveAndRenameEmailToRejected(oArgs, oMessageId)
_email.AddToEmailQueueMSSQL(oMessageId, oSQLTransaction, oBody, oEmailData, "MD5HashException", _EmailOutAccountId, oArgs.NamePortal, oArgs.RejectionTemplateId, ErrorCode.MD5HashException, ex.FileName, "")
AddRejectedState(oMessageId, oRejectionCodeString, "Die gesendete Rechnung wurde bereits verarbeitet!", "", oSQLTransaction)
Catch ex As UnsupportedFerdException
_logger.Error(ex)
Dim oRejectionCodeString = GetRejectionCodeString(oMessageId, ErrorCode.UnsupportedFerdException)
' When UnsupportedFerdException is thrown, we don't have a MD5Hash yet.
' Thats why we set it to String.Empty here.
_history.Update_HistoryEntry(oMessageId, String.Empty, oRejectionCodeString)
Dim oEmailData = _file.MoveAndRenameEmailToRejected(oArgs, oMessageId)
Dim oBody As String = String.Format(EmailStrings.EMAIL_UNSUPPORTED_DOCUMENT, oEmailData.Subject, ex.XmlFile)
_email.AddToEmailQueueMSSQL(oMessageId, oSQLTransaction, oBody, oEmailData, "UnsupportedFerdException", _EmailOutAccountId, oArgs.NamePortal, oArgs.RejectionTemplateId, ErrorCode.UnsupportedFerdException, ex.XmlFile, "")
AddRejectedState(oMessageId, oRejectionCodeString, "Nicht unterstütztes Datenformat", "", oSQLTransaction)
Catch ex As InvalidFerdException
_logger.Error(ex)
Dim oRejectionCodeString = GetRejectionCodeString(oMessageId, ErrorCode.InvalidFerdException)
' When InvalidFerdException is thrown, we don't have a MD5Hash yet.
' Thats why we set it to String.Empty here.
_history.Update_HistoryEntry(oMessageId, String.Empty, oRejectionCodeString)
Dim oEmailData = _file.MoveAndRenameEmailToRejected(oArgs, oMessageId)
Dim oBody = String.Format(EmailStrings.EMAIL_INVALID_DOCUMENT, oEmailData.Subject)
_email.AddToEmailQueueMSSQL(oMessageId, oSQLTransaction, oBody, oEmailData, "InvalidFerdException", _EmailOutAccountId, oArgs.NamePortal, oArgs.RejectionTemplateId, ErrorCode.InvalidFerdException, "", "")
AddRejectedState(oMessageId, oRejectionCodeString, "Inkorrektes Format", "", oSQLTransaction)
Catch ex As TooMuchFerdsException
_logger.Error(ex)
Dim oRejectionCodeString = GetRejectionCodeString(oMessageId, ErrorCode.TooMuchFerdsException)
_history.Update_HistoryEntry(oMessageId, oMD5CheckSum, oRejectionCodeString)
Dim oEmailData = _file.MoveAndRenameEmailToRejected(oArgs, oMessageId)
Dim oBody = String.Format(EmailStrings.EMAIL_TOO_MUCH_FERDS, oEmailData.Subject)
_email.AddToEmailQueueMSSQL(oMessageId, oSQLTransaction, oBody, oEmailData, "TooMuchFerdsException", _EmailOutAccountId, oArgs.NamePortal, oArgs.RejectionTemplateId, ErrorCode.TooMuchFerdsException, "", "")
AddRejectedState(oMessageId, oRejectionCodeString, "Email enthielt mehr als ein ZUGFeRD-Dokument", "", oSQLTransaction)
Catch ex As NoFerdsException
_logger.Error(ex)
Dim oRejectionCodeString = GetRejectionCodeString(oMessageId, ErrorCode.NoFerdsException)
_history.Update_HistoryEntry(oMessageId, oMD5CheckSum, oRejectionCodeString)
Dim oEmailData = _file.MoveAndRenameEmailToRejected(oArgs, oMessageId)
Dim oBody = String.Format(EmailStrings.EMAIL_NO_FERDS, oEmailData.Subject)
_email.AddToEmailQueueMSSQL(oMessageId, oSQLTransaction, oBody, oEmailData, "NoFerdsException", _EmailOutAccountId, oArgs.NamePortal, oArgs.RejectionTemplateId, ErrorCode.NoFerdsException, "", "")
AddRejectedState(oMessageId, oRejectionCodeString, "Email enthielt keine ZUGFeRD-Dokumente", "", oSQLTransaction)
Catch ex As MissingValueException
_logger.Error(ex)
Dim oRejectionCodeString = GetRejectionCodeString(oMessageId, ErrorCode.MissingValueException)
_history.Update_HistoryEntry(oMessageId, oMD5CheckSum, oRejectionCodeString)
Dim oMissingFieldList As String = ""
For Each oMissingFieldDescription In ex.MissingProperties
oMissingFieldList += $"<li>{oMissingFieldDescription.Description}<br/><em>{oMissingFieldDescription.XMLPath}</em></li>"
Next
Dim oOrgFilename = _hash.GetOriginalFilename(ex.File.Name)
Dim oBody = _email.CreateBodyForMissingProperties(ex.File.Name, ex.MissingProperties)
Dim oEmailData = _file.MoveAndRenameEmailToRejected(oArgs, oMessageId)
_email.AddToEmailQueueMSSQL(oMessageId, oSQLTransaction, oBody, oEmailData, "MissingValueException", _EmailOutAccountId, oArgs.NamePortal, oArgs.RejectionTemplateId, ErrorCode.MissingValueException, oOrgFilename, oMissingFieldList)
AddRejectedState(oMessageId, oRejectionCodeString, "Es fehlten ZugferdSpezifikationen", "", oSQLTransaction)
Catch ex As FileSizeLimitReachedException
_logger.Error(ex)
Dim oRejectionCodeString = GetRejectionCodeString(oMessageId, ErrorCode.FileSizeLimitReachedException)
_history.Update_HistoryEntry(oMessageId, oMD5CheckSum, oRejectionCodeString)
Dim oEmailData = _file.MoveAndRenameEmailToRejected(oArgs, oMessageId)
Dim oKey = FileSizeLimitReachedException.KEY_FILENAME
Dim oFileExceedingThreshold As String = IIf(ex.Data.Contains(oKey), ex.Data.Item(oKey), "")
Dim oOrgFilename = _hash.GetOriginalFilename(oFileExceedingThreshold)
Dim oBody = String.Format(EmailStrings.EMAIL_FILE_SIZE_REACHED, oArgs.MaxAttachmentSizeInMegaBytes, oOrgFilename)
_email.AddToEmailQueueMSSQL(oMessageId, oSQLTransaction, oBody, oEmailData, "FileSizeLimitReachedException", _EmailOutAccountId, oArgs.NamePortal, oArgs.RejectionTemplateId, ErrorCode.FileSizeLimitReachedException, oArgs.MaxAttachmentSizeInMegaBytes, oOrgFilename)
AddRejectedState(oMessageId, oRejectionCodeString, "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
_logger.Warn("OutOfMemory Error occurred: {0}", ex.Message)
_logger.Error(ex)
' Send Email to Digital Data
Dim oBody = _email.CreateBodyForUnhandledException(oMessageId, ex)
Dim oEmailData As New EmailData With {
.From = oArgs.ExceptionEmailAddress,
.Subject = $"OutOfMemoryException im ZUGFeRD-Parser @ {oMessageId}"
}
_email.AddToEmailQueueMSSQL(oMessageId, oSQLTransaction, oBody, oEmailData, "OutOfMemoryException", _EmailOutAccountId, oArgs.NamePortal, oArgs.RejectionTemplateId, ErrorCode.UnhandledException, ex.Message, ex.StackTrace)
' Rollback Transaction
oSQLTransaction.Rollback()
oMoveDirectory = DIRECTORY_DONT_MOVE
oExpectedError = False
Catch ex As Exception
_logger.Warn("Unknown Error occurred: {0}", ex.Message)
_logger.Error(ex)
oMoveDirectory = DIRECTORY_DONT_MOVE
oExpectedError = False
If oSQLConnection IsNot Nothing And oSQLTransaction IsNot Nothing Then
' Send Email to Digital Data
Dim oBody = _email.CreateBodyForUnhandledException(oMessageId, ex)
Dim oEmailData As New EmailData With {
.From = oArgs.ExceptionEmailAddress,
.Subject = $"UnhandledException im ZUGFeRD-Parser @ {oMessageId}"
}
_email.AddToEmailQueueMSSQL(oMessageId, oSQLTransaction, oBody, oEmailData, "UnhandledException", _EmailOutAccountId, oArgs.NamePortal, oArgs.RejectionTemplateId, ErrorCode.UnhandledException, ex.Message, ex.StackTrace)
' Rollback Transaction
oSQLTransaction.Rollback()
End If
Finally
Dim oxRechnungHandle As Boolean = False
Try
Dim oRegularMove As Boolean = False
' If an application error occurred, dont move files so they will be processed again later
If oMoveDirectory = DIRECTORY_DONT_MOVE Then
_logger.Info("Application Error occurred. Files for message Id {0} will not be moved.", oMessageId)
ElseIf oArgs.AllowXRechnung And oIsSuccess And oEInvoiceFileGroup.Item(0).Extension = ".xml" Then
_logger.Debug("Before Creating the PDF-File from XML data / Before Commit")
oxRechnungHandle = True
' Hier das neue PDF erzeugen
'but before we need to get all Data we need
MyTemplateValues_xInvDT = Nothing
Dim oSQL_MsgIDReplace = SQL_xRechnung_ItemTemplate
oSQL_MsgIDReplace = oSQL_MsgIDReplace.Replace("@MSG_ID", oFileGroup.Key)
If oSQLTransaction IsNot Nothing Then
' Commit Transaction
oSQLTransaction.Commit()
_logger.Debug("XML commit triggered")
End If
MyTemplateValues_xInvDT = _mssql.GetDatatable(oSQL_MsgIDReplace)
If Not IsNothing(MyTemplateValues_xInvDT) Then
If MyTemplateValues_xInvDT.Rows.Count > 0 Then
Dim oViewReceiptFileInfo As FileInfo = _xRechnungCreator.Create_PDFfromXML(oEInvoiceFileGroup.Item(0), MyTemplateValues_xInvDT)
If Not IsNothing(oViewReceiptFileInfo) Then
oEInvoiceFileGroup.Item(0) = oViewReceiptFileInfo
oRegularMove = True
End If
End If
End If
Else
oRegularMove = True
End If
If oRegularMove Then
' Move all files of the current group
_file.MoveFiles(oArgs, oMessageId, oEInvoiceFileGroup, oEmailAttachmentFiles, oEmbeddedAttachmentFiles, oMoveDirectory, oIsSuccess)
End If
_logger.Info("END processing file group {0}", oMessageId)
Catch ex As Exception
' Send Email to Digital Data
Dim oBody = _email.CreateBodyForUnhandledException(oMessageId, ex)
Dim oEmailData As New EmailData With {
.From = oArgs.ExceptionEmailAddress,
.Subject = $"FileMoveException im ZUGFeRD-Parser @ {oMessageId}"
}
_email.AddToEmailQueueMSSQL(oMessageId, oSQLTransaction, oBody, oEmailData, "FileMoveException", _EmailOutAccountId, oArgs.NamePortal, oArgs.RejectionTemplateId, ErrorCode.UnhandledException, ex.Message, ex.StackTrace)
_logger.Warn("Could not move files!")
_logger.Error(ex)
Throw ex
End Try
Try
' If everything went OK or an expected error occurred,
' finally commit all changes To the Database
' ==================================================================
If oIsSuccess Or oExpectedError Then
_logger.Debug("Before default sql commit: oxRechnungHandle [{0}]", oxRechnungHandle)
If oxRechnungHandle = False AndAlso oSQLTransaction IsNot Nothing Then
' Commit Transaction
oSQLTransaction.Commit()
_logger.Debug("default commit triggered")
End If
End If
Catch ex As Exception
_logger.Error(ex)
_logger.Warn("Database Transactions were not committed successfully.")
End Try
Try
If oSQLConnection IsNot Nothing Then
_logger.Debug("Before default sql close")
oSQLConnection.Close()
End If
Catch ex As Exception
_logger.Error(ex)
_logger.Warn("Database Connections were not closed successfully.")
End Try
End Try
Next
_logger.Debug("Finishing Job {0}", Me.GetType.Name)
Catch ex As Exception
_logger.Error(ex)
_logger.Info("Job Failed! See error log for details")
End Try
End Sub
Private Function GetRejectionCodeString(pMessageId As String, pRejectionCode As ErrorCode) As String
Dim intCode As Integer = DirectCast(pRejectionCode, Integer)
Dim oRejectionCodeString = $"{EmailStrings.ErrorCodePraefix}{intCode}"
' Wir wollen im error-Log den Code und die MessageID haben, um die es geht
Dim oInfoMessage = $"Rejection {oRejectionCodeString} triggered for '{pMessageId}'"
_logger.Error(oInfoMessage)
Return oRejectionCodeString
End Function
Private Function ProcessXMLFile(pMessageId As String, pZugferdFileCounter As Integer, pFile As FileInfo, pConnections As DatabaseConnections, pArgs As WorkerArgs) As ProcessFileResult
Dim oDocument As ZUGFeRDInterface.ZugferdResult
Dim oResult As New ProcessFileResult()
If pFile.Extension.Equals(".xml", StringComparison.OrdinalIgnoreCase) = False Then
' Diese Methode ist nur für den xml-Beleg gedacht
Return oResult
End If
_logger.Info("Start xml processing file {0}", pFile.Name)
' Checking filesize
If _filesystem.TestFileSizeIsLessThanMaxFileSize(pFile.FullName, pArgs.MaxAttachmentSizeInMegaBytes) = False Then
_logger.Warn("Filesize for File [{0}] exceeded limit of {1} MB", pFile.Name, pArgs.MaxAttachmentSizeInMegaBytes)
Throw New FileSizeLimitReachedException(pFile.Name, pArgs.MaxAttachmentSizeInMegaBytes)
End If
Try
oDocument = _zugferd.GetSerializedXMLContentFromFile(pFile)
Catch ex As ValidationException
Throw ex
Catch ex As ZUGFeRDExecption
Select Case ex.ErrorType
Case ZUGFeRDInterface.ErrorType.NoZugferd
_logger.Info("File [{0}] is not a valid ZUGFeRD document. Skipping.", pFile.Name)
oResult.EmailAttachmentFiles.Add(pFile)
Return oResult
Case ZUGFeRDInterface.ErrorType.UnsupportedFormat
_logger.Info("File [{0}/{1}] is an unsupported ZUFeRD document format!", pFile.Name, ex.XmlFile)
Throw New UnsupportedFerdException(ex.XmlFile)
Case ZUGFeRDInterface.ErrorType.NoValidZugferd
_logger.Info("File [{0}] is an Incorrectly formatted ZUGFeRD document!", pFile.Name)
Throw New InvalidFerdException()
Case Else
_logger.Warn("Unexpected Error occurred while extracting ZUGFeRD Information from file {0}", pFile.Name)
Throw ex
End Select
End Try
Try
oDocument.ReceiptFileType = ZUGFeRDInterface.RECEIPT_TYPE_XML
Dim sqlResult As Boolean = StoreXMLItemsInDatabase(pMessageId, oDocument, pFile, pConnections, pArgs, oResult)
Catch ex As Exception
Throw ex
End Try
_logger.Debug("File processed.")
Dim oMD5Checksum = _hash.GenerateAndCheck_MD5Sum(pFile, pMessageId, pArgs.IgnoreRejectionStatus)
oResult.ZugferdFileFound = True
oResult.MD5Checksum = oMD5Checksum
oResult.ZugferdFileCount = 1 ' Es kann hier nur genau einen Treffer geben!
Return oResult
End Function
Private Function ProcessFile(pMessageId As String, pZugferdFileCounter As Integer, pFile As FileInfo, pConnections As DatabaseConnections, pArgs As WorkerArgs) As ProcessFileResult
Dim oDocument As ZUGFeRDInterface.ZugferdResult
Dim oResult As New ProcessFileResult()
' Only pdf files are allowed from here on
If Not pFile.Name.ToUpper.EndsWith(".PDF") Then
_logger.Debug("Skipping non-pdf file {0}", pFile.Name)
oResult.EmailAttachmentFiles.Add(pFile)
' Checking filesize for attachment files
If _filesystem.TestFileSizeIsLessThanMaxFileSize(pFile.FullName, pArgs.MaxAttachmentSizeInMegaBytes) = False Then
_logger.Warn("Filesize for File [{0}] exceeded limit of {1} MB", pFile.Name, pArgs.MaxAttachmentSizeInMegaBytes)
Throw New FileSizeLimitReachedException(pFile.Name, pArgs.MaxAttachmentSizeInMegaBytes)
End If
Return oResult
End If
_logger.Info("Start processing file {0}", pFile.Name)
' Checking filesize for pdf files
If _filesystem.TestFileSizeIsLessThanMaxFileSize(pFile.FullName, pArgs.MaxAttachmentSizeInMegaBytes) = False Then
_logger.Warn("Filesize for File [{0}] exceeded limit of {1} MB", pFile.Name, pArgs.MaxAttachmentSizeInMegaBytes)
Throw New FileSizeLimitReachedException(pFile.Name, pArgs.MaxAttachmentSizeInMegaBytes)
End If
Try
oDocument = _zugferd.ExtractZUGFeRDFileWithGDPicture(pFile.FullName)
Catch ex As ValidationException
Throw ex
Catch ex As ZUGFeRDExecption
Select Case ex.ErrorType
Case ZUGFeRDInterface.ErrorType.NoZugferd
_logger.Info("File [{0}] is not a valid ZUGFeRD document. Skipping.", pFile.Name)
oResult.EmailAttachmentFiles.Add(pFile)
Return oResult
Case ZUGFeRDInterface.ErrorType.UnsupportedFormat
_logger.Info("File [{0}/{1}] is an unsupported ZUFeRD document format!", pFile.Name, ex.XmlFile)
Throw New UnsupportedFerdException(ex.XmlFile)
Case ZUGFeRDInterface.ErrorType.NoValidZugferd
_logger.Info("File [{0}] is an Incorrectly formatted ZUGFeRD document!", pFile.Name)
Throw New InvalidFerdException()
Case Else
_logger.Warn("Unexpected Error occurred while extracting ZUGFeRD Information from file {0}", pFile.Name)
Throw ex
End Select
End Try
' Check if there are more than one ZUGFeRD files
If pZugferdFileCounter = 1 Then
Throw New TooMuchFerdsException()
End If
' Since extraction went well, increase the amount of ZUGFeRD files
pZugferdFileCounter += 1
_logger.Info("Zugferd file found. Increasing counter.")
' Extract all attachments with the extensions specified in `AllowedExtensions`.
' If you need to extract and use embedded xml files, you need to filter out the zugferd-invoice.xml yourself.
' Right now the zugferd-invoice.xml is filtered out because `AllowedExtensions` does not contain `xml`.
Dim oAttachments = _embeds.Extract(pFile.FullName, AllowedExtensions)
If oAttachments Is Nothing Then
_logger.Warn("Attachments for file [{0}] could not be extracted", pFile.FullName)
Else
oResult.EmbeddedAttachmentFiles.AddRange(oAttachments)
End If
Try
oDocument.ReceiptFileType = ZUGFeRDInterface.RECEIPT_TYPE_PDF
Dim sqlResult As Boolean = StoreXMLItemsInDatabase(pMessageId, oDocument, pFile, pConnections, pArgs, oResult)
Catch ex As Exception
Throw ex
End Try
_logger.Debug("File processed.")
' Check the Checksum and rejection status
Dim oMD5Checksum = _hash.GenerateAndCheck_MD5Sum(pFile, pMessageId, pArgs.IgnoreRejectionStatus)
oResult.ZugferdFileFound = True
oResult.MD5Checksum = oMD5Checksum
oResult.ZugferdFileCount = pZugferdFileCounter
Return oResult
End Function
Private Function StoreXMLItemsInDatabase(pMessageId As String, pDocument As ZUGFeRDInterface.ZugferdResult, pFile As FileInfo, pConnections As DatabaseConnections, pArgs As WorkerArgs, pProcessFileResult As ProcessFileResult) As Boolean
' Check the document against the configured property map and return:
' - a List of valid properties
' - a List of missing properties
Dim oPropertyMap = _zugferd.FilterPropertyMap(pArgs.PropertyMap, pDocument.Specification)
Dim oCheckResult = _zugferd.PropertyValues.CheckPropertyValues(pDocument.SchemaObject, oPropertyMap, pMessageId)
_logger.Info("Properties checked: [{0}] missing properties / [{1}] valid properties found.", oCheckResult.MissingProperties.Count, oCheckResult.ValidProperties.Count)
If oCheckResult.MissingProperties.Count > 0 Then
_logger.Warn("[{0}] missing properties found. Exiting.", oCheckResult.MissingProperties.Count)
Throw New MissingValueException(pFile, oCheckResult.MissingProperties)
Else
_logger.Debug("No missing properties found. Continuing.")
End If
' Daten in die Datenbank speichern
If BulkInsertDataToDatabase(pMessageId, pDocument, pConnections, oCheckResult) = False Then
_logger.Error("Bulk Insert for MessageId [{0}] failed!", pMessageId)
Throw New Exception("Bulk Insert failed! Exiting.")
End If
' Eingebettete Dateien speichern
If HandleEmbeddedAttachments(pMessageId, pDocument, pConnections, oCheckResult, pArgs, pProcessFileResult) = False Then
_logger.Debug("Files saving for MessageId [{0}] failed!", pMessageId)
End If
Return True
End Function
''' <summary>
''' Hier werden die Dateianhänge behandelt, die im XML als base64 eingetragen wurden.
''' Die zusammengehörigen Knoten müssen über "FILES" gruppiert werden!
'''
''' Die erwarteten Knoten-Namen sind in der List EmbeddedFilesColumnNames enthalten!
''' </summary>
Private Function HandleEmbeddedAttachments(pMessageId As String, pDocument As ZUGFeRDInterface.ZugferdResult, pConnections As DatabaseConnections,
pCheckResult As CheckPropertyValuesResult, pArgs As WorkerArgs, pProcessFileResult As ProcessFileResult) As Boolean
If (pCheckResult Is Nothing) Then
_logger.Debug("pCheckResult is empty!")
Return True
End If
If (CheckEmbeddedAttachmentEntries(pCheckResult) = False) Then
_logger.Debug("No embedded Files in XML found!")
Return True
End If
Dim embAttachmentList As List(Of ValidProperty) = pCheckResult.ValidProperties.Where(
Function(z)
Return EmbeddedFilesColumnNames.Contains(z.TableColumn)
End Function
).ToList()
If embAttachmentList Is Nothing OrElse embAttachmentList.Count <= 0 Then
_logger.Debug("No Fields for Embedded Files configured!")
Return True
End If
' GroupCounter Werte in Hashset eintragen, um distinct Werte zu erhalten
Dim oIndexList As HashSet(Of Integer) = New HashSet(Of Integer)
For Each resultItem In embAttachmentList
oIndexList.Add(resultItem.GroupCounter)
Next
Dim oOutputPath As String = GetOutputPathForEmbeddedAttachments(pArgs)
Dim nextAttachmentIndex As Integer = 0
nextAttachmentIndex = GetNextAttachmentIndex(pMessageId)
If nextAttachmentIndex <= 0 Then
nextAttachmentIndex = 1
End If
For Each groupIndex In oIndexList
Dim oMimeCodeString As String = String.Empty
Dim oOrgFilename As String = String.Empty
Dim oBase64String As String = String.Empty
Dim oMimeTypeProperty As ValidProperty = GetIndexProperty(embAttachmentList, groupIndex, "ATTACHMENT_FILE_MIMECODE")
If oMimeTypeProperty IsNot Nothing AndAlso oMimeTypeProperty.Value.IsNotNullOrEmpty() Then
oMimeCodeString = oMimeTypeProperty.Value.ToLower()
Else
_logger.Debug("Empty MIME-Code! File can not be stored!")
Continue For
End If
Dim oFilenameProperty As ValidProperty = GetIndexProperty(embAttachmentList, groupIndex, "ATTACHMENT_FILE_FILENAME")
If oFilenameProperty IsNot Nothing AndAlso oFilenameProperty.Value.IsNotNullOrEmpty() Then
oOrgFilename = oFilenameProperty.Value
Else
_logger.Debug("Empty Filename! File can not be stored!")
Continue For
End If
Dim oBase64ValueProperty As ValidProperty = GetIndexProperty(embAttachmentList, groupIndex, "ATTACHMENT_FILE_VALUE")
If oBase64ValueProperty IsNot Nothing AndAlso oBase64ValueProperty.Value.IsNotNullOrEmpty() Then
oBase64String = oBase64ValueProperty.Value
Else
_logger.Error("Empty base64 String! File can not be stored!")
Continue For
End If
Dim newAttachmentFilename = pMessageId + "~attm" + nextAttachmentIndex.ToString
Dim oFileExtension = GetEmbeddedFileExtension(oMimeTypeProperty.Value)
If oFileExtension.IsNotNullOrEmpty() Then
newAttachmentFilename += "." + oFileExtension
Else
_logger.Warn("No extension found! File can not be stored!")
Continue For
End If
Dim embeddedFilePath = Path.Combine(oOutputPath, newAttachmentFilename)
_logger.Debug("Next Attachment File is [{0}]", embeddedFilePath)
If SaveBase64ToDisk(embeddedFilePath, oBase64String) = True Then
_logger.Debug("Saved file [{0}] to disk", embeddedFilePath)
pProcessFileResult.EmailAttachmentFiles.Add(New FileInfo(embeddedFilePath))
Else
_logger.Error("Could not save File to Disk!")
Dim oReasonString = "Could not save file " + newAttachmentFilename + " to disk."
AddRejectedState(pMessageId, oReasonString, "EMBEDDED FILE CONSISTENCY NOT OK", "Info GUI", pConnections.SQLServerTransaction)
Continue For
End If
If TestFileOnDisk(embeddedFilePath, oMimeCodeString) = False Then
_logger.Error("Could not save File to Disk!")
Dim oReasonString = "Validation of file " + newAttachmentFilename + " on disk was NOT succesfully."
AddRejectedState(pMessageId, oReasonString, "EMBEDDED FILE CONSISTENCY NOT OK", "Info GUI", pConnections.SQLServerTransaction)
Continue For
End If
If InsertAttachmentHistoryEntry(pMessageId, oOrgFilename, embeddedFilePath) = False Then
_logger.Error("Could not save attachment Data to DB!")
Return False
End If
If InsertEmbeddedFileDataToDB(pMessageId, oBase64String, oOrgFilename, oMimeCodeString, groupIndex) = False Then
_logger.Error("Could not save attachment Data to DB!")
Return False
End If
nextAttachmentIndex += 1
Next
Return True
End Function
Private Function TestFileOnDisk(pEmbeddedFilePath As String, pMimeCodeString As String) As Boolean
Try
If pMimeCodeString = MIME_TYPE_PDF Then
Dim oGdPicturePDF As New GdPicturePDF
Dim oStatus As GdPictureStatus = oGdPicturePDF.LoadFromFile(pEmbeddedFilePath, True)
If oStatus <> GdPictureStatus.OK Then
_logger.Error("File [{0}] has no proper state!", pEmbeddedFilePath)
Return False
End If
Else
' Test other files
Dim fileInfo As FileInfo = New FileInfo(pEmbeddedFilePath)
If fileInfo.Exists = False Then
_logger.Error("Could not find File [{0}] on Disk!", pEmbeddedFilePath)
Return False
End If
End If
Return True
Catch ex As Exception
_logger.Error(ex)
Return False
End Try
End Function
Private Function GetEmbeddedFileExtension(pMimeTypeValue As String) As String
If pMimeTypeValue.IsNullOrEmpty() Then
_logger.Warn("Empty MimeCode is not allowed!")
Return String.Empty
End If
Select Case pMimeTypeValue.ToLower()
Case MIME_TYPE_PDF
Return "pdf"
Case MIME_TYPE_XLSX
Return "xlsx"
Case MIME_TYPE_ODT
Return "odt"
Case "image/jpeg"
Return "jpg"
Case "image/png"
Return "png"
Case "image/tiff"
Return "tif"
Case "text/csv"
Return "csv"
Case "text/xml"
Return "xml"
Case Else
Return String.Empty
End Select
End Function
Private Shared Function GetIndexProperty(pListResult As List(Of ValidProperty), pGroupIndex As Integer, pTableColumn As String) As ValidProperty
Return pListResult.Where(
Function(z)
Return z.GroupCounter = pGroupIndex AndAlso z.TableColumn = pTableColumn
End Function
).FirstOrDefault
End Function
''' <summary>
''' Speichert die Daten inkl. base64-String in die Datenbank
''' </summary>
Private Function InsertEmbeddedFileDataToDB(pMessageId As String, pItemValue As String, pOrgFilename As String, pMimeType As String, pGroupIndex As Integer) As Boolean
Try
Dim oCommand = New SqlCommand(
"INSERT INTO TBEDMI_ITEM_FILES (
REFERENCE_GUID,
ITEM_VALUE,
ORG_FILENAME,
MIME_TYPE,
GROUP_INDEX,
CREATED_WHO
) VALUES (
@MESSAGE_ID,
@ITEM_VALUE,
@ORG_FILENAME,
@MIME_TYPE,
@GROUP_INDEX,
@CREATED_WHO
)")
Dim fileBytes As Byte() = Convert.FromBase64String(pItemValue)
oCommand.Parameters.Add("MESSAGE_ID", SqlDbType.VarChar, 250).Value = pMessageId
oCommand.Parameters.Add("ITEM_VALUE", SqlDbType.VarBinary).Value = fileBytes
oCommand.Parameters.Add("ORG_FILENAME", SqlDbType.VarChar, 256).Value = pOrgFilename
oCommand.Parameters.Add("MIME_TYPE", SqlDbType.VarChar, 256).Value = pMimeType
oCommand.Parameters.Add("GROUP_INDEX", SqlDbType.Int).Value = pGroupIndex
oCommand.Parameters.Add("CREATED_WHO", SqlDbType.VarChar, 100).Value = "eInvoice Parser"
_mssql.ExecuteNonQuery(oCommand)
Return True
Catch ex As Exception
_logger.Error(ex)
Return False
End Try
End Function
''' <summary>
''' Ermittelt den Ausgabepfad für die eingebetteten Anhänge
''' </summary>
Private Function GetOutputPathForEmbeddedAttachments(pArgs As WorkerArgs) As String
Return pArgs.WatchDirectory
End Function
''' <summary>
''' Prüft, ob Embedded Attachments in den XML-Ergebnissen enthalten sind,
''' in dem geprüft wird, ob bestimmte MIME-Codes vorhanden sind.
''' </summary>
''' <param name="pCheckResult"></param>
''' <returns></returns>
Private Function CheckEmbeddedAttachmentEntries(pCheckResult As CheckPropertyValuesResult) As Boolean
Try
Dim resultList = pCheckResult.ValidProperties.Where(
Function(z)
Return (z.TableColumn = "ATTACHMENT_FILE_MIMECODE" AndAlso AllowedMimeTypesInEmbeddedFiles.Contains(z.Value.ToLower()))
End Function
).ToList()
If resultList.Count > 0 Then
_logger.Info("Found [{0}] embedded XML-Attachments.", resultList.Count)
Return True
Else
_logger.Info("No embedded XML-Attachments found.")
Return False
End If
Catch ex As Exception
_logger.Error("Error searching pCheckResult! {0}", ex.Message)
Return False
End Try
End Function
''' <summary>
''' Speichere base64 als Datei auf der Platte ab.
''' </summary>
Private Function SaveBase64ToDisk(pExportFilePath As String, pBase64String As String) As Boolean
Try
Dim oFilename As String = pExportFilePath
Dim base64BinaryDataString As String = pBase64String
Dim binaryDataString As Byte() = Convert.FromBase64String(base64BinaryDataString)
' Using verwenden, um blockieren der Datei zu verhindern
Using fs = New FileStream(oFilename, FileMode.Create, FileAccess.ReadWrite)
fs.Write(binaryDataString, 0, binaryDataString.Length)
fs.Flush()
fs.Close()
End Using
Return True
Catch ex As Exception
_logger.Error("Could NOT save File [{0}] to Disk! Exception: [{1}]", pExportFilePath, ex.Message)
Return False
End Try
End Function
''' <summary>
''' Die Methode lädt die bisherigen Dateinamen zu einer MessageID
''' Die Datei mit dem höchsten Index gibt den folgenden Index vor.
''' </summary>
''' <returns>Nächster Attachment Index</returns>
Private Function GetNextAttachmentIndex(pMessageId As String) As Integer
Try
Dim oSQL = $"SELECT count(*) FROM TBEMLP_HISTORY_ATTACHMENT WHERE EMAIL_MSGID = '{pMessageId}'"
Dim sqlResult = _mssql.GetScalarValue(oSQL)
If sqlResult = 0 Then
sqlResult = 1 ' Kleinster Index = 1
End If
Return sqlResult
Catch ex As Exception
_logger.Error(ex)
Throw ex
End Try
End Function
''' <summary>
''' Speichert die Infos zu einem embedded Dateianhang in die DB.
''' Mangels EMail-Daten werden die EMail-Felder (FROM, BODY, usw.) nicht gefüllt
''' </summary>
''' <returns>true, wenn erfolgreich</returns>
Private Function InsertAttachmentHistoryEntry(pMessageId As String, pFileName As String, pNewFileName As String) As Boolean
Try
Dim oCommand = New SqlCommand(
"INSERT INTO TBEMLP_HISTORY_ATTACHMENT (
WORK_PROCESS,
EMAIL_MSGID,
EMAIL_ATTMT,
EMAIL_ATTMT_INDEX,
EMAIL_FROM,
EMAIL_BODY
) VALUES (
@WORK_PROCESS,
@MESSAGE_ID,
@ATTACHMENT,
@ATTACHMENT_INDEX,
'-',
'-'
)")
oCommand.Parameters.Add("WORK_PROCESS", SqlDbType.VarChar, 100).Value = "Attachment Sniffer (Embedded Files)"
oCommand.Parameters.Add("MESSAGE_ID", SqlDbType.VarChar, 500).Value = pMessageId
oCommand.Parameters.Add("ATTACHMENT", SqlDbType.VarChar, 500).Value = pFileName
oCommand.Parameters.Add("ATTACHMENT_INDEX", SqlDbType.VarChar, 500).Value = pNewFileName
_mssql.ExecuteNonQuery(oCommand)
Return True
Catch ex As Exception
_logger.Error(ex)
Return False
End Try
End Function
Private Function BulkInsertDataToDatabase(pMessageId As String, pDocument As ZUGFeRDInterface.ZugferdResult, pConnections As DatabaseConnections, pCheckResults As CheckPropertyValuesResult) As Boolean
If DeleteExistingPropertyValues(pMessageId, pConnections) = False Then
Throw New Exception("Could not cleanup data. Exiting.")
End If
' DataTable vorbereiten
Dim oDataTable As DataTable = FillDataTable(pMessageId, pCheckResults, pDocument)
' ColumnList initialisieren
Dim oColumnNames As List(Of String) = New List(Of String) From {
"REFERENCE_GUID",
"ITEM_DESCRIPTION",
"ITEM_VALUE",
"GROUP_COUNTER",
"SPEC_NAME",
"IS_REQUIRED"
}
Dim oBulkResult = BulkInsert(pConnections, oDataTable, "TBEDMI_ITEM_VALUE", oColumnNames)
If oBulkResult = False Then
_logger.Error("Bulk Insert for MessageId [{0}] failed!", pMessageId)
Throw New Exception("Bulk Insert failed! Exiting.")
End If
_logger.Info("Bulk Insert finished. [{0}] rows inserted for MessageId [{1}].", oDataTable.Rows.Count, pMessageId)
Return True
End Function
Private Function FillDataTable(pMessageId As String, pCheckResult As PropertyValues.CheckPropertyValuesResult, pDocument As ZUGFeRDInterface.ZugferdResult) As DataTable
Dim oDataTable As DataTable = New DataTable()
oDataTable.Columns.Add(New DataColumn("REFERENCE_GUID", GetType(String)))
oDataTable.Columns.Add(New DataColumn("ITEM_DESCRIPTION", GetType(String)))
oDataTable.Columns.Add(New DataColumn("ITEM_VALUE", GetType(String)))
oDataTable.Columns.Add(New DataColumn("GROUP_COUNTER", GetType(Int32)))
oDataTable.Columns.Add(New DataColumn("SPEC_NAME", GetType(String)))
oDataTable.Columns.Add(New DataColumn("IS_REQUIRED", GetType(Boolean)))
' Erste Zeile enthält die Spezifikation
Dim oFirstRow As DataRow = oDataTable.NewRow()
oFirstRow("REFERENCE_GUID") = pMessageId
oFirstRow("ITEM_DESCRIPTION") = "ZUGFeRDSpezifikation"
oFirstRow("ITEM_VALUE") = pDocument.Specification
oFirstRow("GROUP_COUNTER") = 0
oFirstRow("SPEC_NAME") = "ZUGFERD_SPECIFICATION"
oFirstRow("IS_REQUIRED") = False
_logger.Debug("Mapping Property [ZUGFERD_SPECIFICATION] with value [{0}]", pDocument.Specification)
oDataTable.Rows.Add(oFirstRow)
' Zweite Zeile enthält das verwendete XML Schema
Dim oSecondRow As DataRow = oDataTable.NewRow()
oSecondRow("REFERENCE_GUID") = pMessageId
oSecondRow("ITEM_DESCRIPTION") = "ZUGFeRDXMLSchema"
oSecondRow("ITEM_VALUE") = pDocument.UsedXMLSchema
oSecondRow("GROUP_COUNTER") = 0
oSecondRow("SPEC_NAME") = "ZUGFERD_XML_SCHEMA"
oSecondRow("IS_REQUIRED") = False
_logger.Debug("Mapping Property [ZUGFERD_XML_SCHEMA] with value [{0}]", pDocument.UsedXMLSchema)
oDataTable.Rows.Add(oSecondRow)
' Dritte Zeile enthält das verwendete Datei-Format des Belegs (PDF/XML)
Dim oThirdRow As DataRow = oDataTable.NewRow()
oThirdRow("REFERENCE_GUID") = pMessageId
oThirdRow("ITEM_DESCRIPTION") = "ReceiptFileType"
oThirdRow("ITEM_VALUE") = pDocument.ReceiptFileType
oThirdRow("GROUP_COUNTER") = 0
oThirdRow("SPEC_NAME") = "RECEIPT_FILE_TYPE"
oThirdRow("IS_REQUIRED") = False
_logger.Debug("Mapping Property [RECEIPT_FILE_TYPE] with value [{0}]", pDocument.ReceiptFileType)
oDataTable.Rows.Add(oThirdRow)
For Each oProperty In pCheckResult.ValidProperties
' ItemType = 3 => eingebettete Datei, nicht den base64 speichern
If oProperty.ItemType = 3 Then
Continue For
End If
' ItemType = 0 (normale texte) dürfen nicht leer sein
If oProperty.ItemType = 0 And oProperty.Value.IsNullOrEmpty Then
_logger.Debug("No Mapping for Property [{0}] with empty value, because of ItemType = 0.", oProperty.TableColumn)
Continue For
End If
' If GroupCounter is -1, it means this is a default property that can only occur once.
' Set the actual inserted value to 0
Dim oGroupCounterValue As Integer = oProperty.GroupCounter
If oGroupCounterValue = -1 Then
oGroupCounterValue = 0
End If
If oProperty.Value.Length > 900 Then
_logger.Warn("Value for field [{0}] is longer than 900 characters, will be truncated!", oProperty.TableColumn)
End If
Dim oNewRow As DataRow = oDataTable.NewRow()
oNewRow("REFERENCE_GUID") = pMessageId
oNewRow("ITEM_DESCRIPTION") = oProperty.Description
oNewRow("ITEM_VALUE") = oProperty.Value.Truncate(900)
oNewRow("GROUP_COUNTER") = oGroupCounterValue
oNewRow("SPEC_NAME") = oProperty.TableColumn
oNewRow("IS_REQUIRED") = oProperty.IsRequired
_logger.Debug("Mapping Property [{0}] with value [{1}]", oProperty.TableColumn, oProperty.Value)
oDataTable.Rows.Add(oNewRow)
Next
Return oDataTable
End Function
Private Function DeleteExistingPropertyValues(pMessageId As String, pConnections As DatabaseConnections) As Boolean
Dim oDelSQL = $"DELETE FROM TBEDMI_ITEM_VALUE where REFERENCE_GUID = '{pMessageId}'"
Dim oStep As String = "TBEDMI_ITEM_VALUE Delete MessageID Items"
Try
Dim retValue As Boolean = _mssql.ExecuteNonQueryWithConnectionObject(oDelSQL, pConnections.SQLServerConnection, MSSQLServer.TransactionMode.ExternalTransaction, pConnections.SQLServerTransaction)
Return retValue
Catch ex As Exception
_logger.Warn("Step [{0}] with SQL [{1}] was not successful.", oStep, oDelSQL)
End Try
Try
oDelSQL = $"DELETE FROM TBEDMI_ITEM_FILES where REFERENCE_GUID = '{pMessageId}'"
oStep = "TBEDMI_ITEM_FILES Delete MessageID Items"
Dim retValue As Boolean = _mssql.ExecuteNonQueryWithConnectionObject(oDelSQL, pConnections.SQLServerConnection, MSSQLServer.TransactionMode.ExternalTransaction, pConnections.SQLServerTransaction)
Return retValue
Catch ex As Exception
_logger.Warn("Step [{0}] with SQL [{1}] was not successful.", oStep, oDelSQL)
End Try
Return False
End Function
Private Function BulkInsert(pConnections As DatabaseConnections, pTable As DataTable, pDestinationTable As String, pColumns As List(Of String)) As Boolean
Using oBulkCopy = New SqlBulkCopy(pConnections.SQLServerConnection, SqlBulkCopyOptions.Default, pConnections.SQLServerTransaction)
oBulkCopy.DestinationTableName = pDestinationTable
For Each oColumn In pColumns
oBulkCopy.ColumnMappings.Add(New SqlBulkCopyColumnMapping(oColumn, oColumn))
Next
Try
oBulkCopy.WriteToServer(pTable)
Catch ex As Exception
_logger.Error(ex)
Return False
End Try
End Using
Return True
End Function
''' <summary>
''' Fügt neue Datensätze in Tabelle TBEMLP_HISTORY_STATE ein,
''' per Prozedur DD_ECM.[dbo].[PRCUST_ADD_HISTORY_STATE]
''' </summary>
Private Sub AddRejectedState(pMessageID As String, pTitle As String, pTitle1 As String, pComment As String, pTransaction As SqlTransaction)
Try
'PRCUST_ADD_HISTORY_STATE: @MessageID VARCHAR(250), @TITLE1 VARCHAR(250), @TITLE2 VARCHAR(250)
Dim oSQL = $"EXEC PRCUST_ADD_HISTORY_STATE '{pMessageID}','{pTitle}','{pTitle1}','{pComment.Replace("'", "''")}'"
_mssql.ExecuteNonQuery(oSQL, pTransaction)
Catch ex As Exception
_logger.Error(ex)
End Try
End Sub
End Class