9 Commits

Author SHA1 Message Date
Jonathan Jenne
70bb33f823 Base: move Files 2023-09-05 10:25:49 +02:00
Jonathan Jenne
e63d1ea557 Logging: Improve json logging 2023-09-01 13:56:37 +02:00
Jonathan Jenne
2b80e8fa97 Jobs: Remove obsolete history function 2023-09-01 13:56:12 +02:00
Jonathan Jenne
9cab65f941 Jobs: Prepare Service Refactor, fix nullref error with emaildata, remove obsolete loops 2023-09-01 13:55:55 +02:00
Jonathan Jenne
4c8bdb27fd Jobs: add filename property MD5HashException, Add meaningful message to MissingValueException 2023-09-01 13:44:00 +02:00
Jonathan Jenne
b604ffcba2 Jobs: Only support one watch directory 2023-09-01 13:43:19 +02:00
Jonathan Jenne
6ef1e97deb Jobs: Add filename placeholder to EMAIL_MD5_ERROR 2023-09-01 13:42:53 +02:00
Jonathan Jenne
60bcf26379 Jobs: Add default Values to email data 2023-09-01 13:42:26 +02:00
Jonathan Jenne
a4a3dc4536 Restructure Base 2023-09-01 13:41:40 +02:00
21 changed files with 1366 additions and 586 deletions

View File

@@ -77,10 +77,12 @@
<Import Include="System.Threading.Tasks" /> <Import Include="System.Threading.Tasks" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Compile Include="BaseClass.vb" /> <Compile Include="Base\BaseClass.vb" />
<Compile Include="BaseUtils.vb" /> <Compile Include="Base\BaseUtils.vb" />
<Compile Include="Encryption\Compression.vb" />
<Compile Include="Encryption\Encryption.vb" />
<Compile Include="Encryption\EncryptionLegacy.vb" />
<Compile Include="DatabaseEx.vb" /> <Compile Include="DatabaseEx.vb" />
<Compile Include="ECM\ECM.vb" />
<Compile Include="MimeEx.vb" /> <Compile Include="MimeEx.vb" />
<Compile Include="WindowsEx.vb" /> <Compile Include="WindowsEx.vb" />
<Compile Include="ModuleExtensions.vb" /> <Compile Include="ModuleExtensions.vb" />
@@ -88,9 +90,6 @@
<Compile Include="NativeMethods.vb" /> <Compile Include="NativeMethods.vb" />
<Compile Include="ObjectEx.vb" /> <Compile Include="ObjectEx.vb" />
<Compile Include="GraphicsEx.vb" /> <Compile Include="GraphicsEx.vb" />
<Compile Include="IDB\Attributes.vb" />
<Compile Include="IDB\Database.vb" />
<Compile Include="IDB\FileStore.vb" />
<Compile Include="LanguageEx.vb" /> <Compile Include="LanguageEx.vb" />
<Compile Include="My Project\AssemblyInfo.vb" /> <Compile Include="My Project\AssemblyInfo.vb" />
<Compile Include="My Project\Application.Designer.vb"> <Compile Include="My Project\Application.Designer.vb">
@@ -140,5 +139,8 @@
<Name>Logging</Name> <Name>Logging</Name>
</ProjectReference> </ProjectReference>
</ItemGroup> </ItemGroup>
<ItemGroup>
<Folder Include="Static\" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.VisualBasic.targets" /> <Import Project="$(MSBuildToolsPath)\Microsoft.VisualBasic.targets" />
</Project> </Project>

View File

@@ -1,7 +0,0 @@
Public Class ECM
Public Enum Product
ProcessManager
GlobalIndexer
ClipboardWatcher
End Enum
End Class

View File

@@ -0,0 +1,70 @@
Imports System.IO
Imports System.IO.Compression
Imports DigitalData.Modules.Logging
Public Class Compression
Private ReadOnly _logger As Logger
Public Sub New(LogConfig As LogConfig)
_logger = LogConfig.GetLogger()
End Sub
Public Async Function CompressAsync(data As Byte()) As Task(Of Byte())
Return Await Task.Run(Function() As Byte()
Return Compress(data)
End Function)
End Function
Public Function Compress(data As Byte()) As Byte()
Try
' ByteArray in Stream umwandeln
Using originalStream As New MemoryStream(data)
' Ziel Stream erstellen
Using compressedStream As New MemoryStream()
' Gzip-Stream erstellen, der alle Daten komprimiert und zu compressedStream durchleitet
'
' > MemoryStream > GzipStream > MemoryStream
' originalStream --> compressionStream --> compressedFileStream
'
Using compressionStream As New GZipStream(compressedStream, CompressionMode.Compress)
originalStream.CopyTo(compressionStream)
compressionStream.Close()
Return compressedStream.ToArray()
End Using
End Using
End Using
Catch ex As Exception
_logger.Error(ex)
Throw ex
End Try
End Function
Public Async Function DecompressAsync(data As Byte()) As Task(Of Byte())
Return Await Task.Run(Function() As Byte()
Return Decompress(data)
End Function)
End Function
Public Function Decompress(data As Byte()) As Byte()
Try
' ByteArray in Stream umwandeln
Using compressedStream As New MemoryStream(data)
' Ziel Stream erstellen
Using decompressedStream As New MemoryStream()
' Gzip-Stream erstellen, der alle Daten komprimiert und zu compressedStream durchleitet
'
' > MemoryStream > GzipStream > MemoryStream
' compressedStream --> decompressionStream --> decompressedStream
'
Using decompressionStream As New GZipStream(compressedStream, CompressionMode.Decompress)
decompressionStream.CopyTo(decompressedStream)
Return decompressedStream.ToArray()
End Using
End Using
End Using
Catch ex As Exception
_logger.Error(ex)
Throw ex
End Try
End Function
End Class

View File

@@ -0,0 +1,148 @@
Imports System.IO
Imports System.Security.Cryptography
Imports System.Text.Encoding
Imports DigitalData.Modules.Logging
''' <summary>
''' https://stackoverflow.com/questions/10168240/encrypting-decrypting-a-string-in-c-sharp
''' </summary>
Public Class Encryption
' This constant is used to determine the keysize of the encryption algorithm in bits.
' We divide this by 8 within the code below to get the equivalent number of bytes.
Private Const KEY_SIZE As Integer = 256
' This constant determines the number of iterations for the password bytes generation function.
Private Const DERIVATION_ITERATIONS As Integer = 1000
Private Const BLOCK_SIZE As Integer = 256
Private _paddingMode As PaddingMode = PaddingMode.Zeros
Private _cipherMode As CipherMode = CipherMode.CBC
Private ReadOnly _password As String
Private _logger As Logger
Public Sub New(LogConfig As LogConfig, Password As String)
_logger = LogConfig.GetLogger()
If IsNothing(Password) Then
Throw New ArgumentNullException("Password")
End If
_password = Password
End Sub
Public Async Function EncryptAsync(PlainTextBytes As Byte()) As Task(Of Byte())
Return Await Task.Run(Function() As Byte()
Return Encrypt(PlainTextBytes)
End Function)
End Function
Public Function Encrypt(PlainText As String) As String
Try
Dim oBytes As Byte() = UTF8.GetBytes(PlainText)
Dim oEncrypted As Byte() = Encrypt(oBytes)
Return UTF8.GetString(oEncrypted)
Catch ex As Exception
_logger.Error(ex)
Throw ex
End Try
End Function
Public Function Encrypt(PlainTextBytes As Byte()) As Byte()
Try
' Salt and IV is randomly generated each time, but is preprended to encrypted cipher text
' so that the same Salt and IV values can be used when decrypting.
Dim oSaltStringBytes = Generate256BitsOfRandomEntropy()
Dim oIvStringBytes = Generate256BitsOfRandomEntropy()
Using oPassword = New Rfc2898DeriveBytes(_password, oSaltStringBytes, DERIVATION_ITERATIONS)
Dim oKeyBytes = oPassword.GetBytes(KEY_SIZE / 8)
Using oSymmetricKey = New RijndaelManaged()
oSymmetricKey.BlockSize = BLOCK_SIZE
oSymmetricKey.Mode = _cipherMode
oSymmetricKey.Padding = _paddingMode
Using oEncryptor = oSymmetricKey.CreateEncryptor(oKeyBytes, oIvStringBytes)
Using oMemoryStream = New MemoryStream()
Using oCryptoStream = New CryptoStream(oMemoryStream, oEncryptor, CryptoStreamMode.Write)
oCryptoStream.Write(PlainTextBytes, 0, PlainTextBytes.Length)
oCryptoStream.FlushFinalBlock()
' Create the final bytes as a concatenation of the random salt bytes, the random iv bytes and the cipher bytes.
Dim oCipherTextBytes = oSaltStringBytes
oCipherTextBytes = oCipherTextBytes.Concat(oIvStringBytes).ToArray()
oCipherTextBytes = oCipherTextBytes.Concat(oMemoryStream.ToArray()).ToArray()
oMemoryStream.Close()
oCryptoStream.Close()
Return oCipherTextBytes
End Using
End Using
End Using
End Using
End Using
Catch ex As Exception
_logger.Error(ex)
Throw ex
End Try
End Function
Public Async Function DecryptAsync(CipherTextBytesWithSaltAndIv As Byte()) As Task(Of Byte())
Return Await Task.Run(Function() As Byte()
Return Decrypt(CipherTextBytesWithSaltAndIv)
End Function)
End Function
Public Function Decrypt(CipherTextPlainWithSaltAndIv As String) As String
Try
Dim oBytes As Byte() = UTF8.GetBytes(CipherTextPlainWithSaltAndIv)
Dim oDecrypted As Byte() = Decrypt(oBytes)
Return UTF8.GetString(oDecrypted)
Catch ex As Exception
_logger.Error(ex)
Throw ex
End Try
End Function
Public Function Decrypt(CipherTextBytesWithSaltAndIv As Byte()) As Byte()
Try
' Get the complete stream of bytes that represent:
' [32 bytes of Salt] + [32 bytes of IV] + [n bytes of CipherText]
' Get the saltbytes by extracting the first 32 bytes from the supplied cipherText bytes.
Dim oSaltStringBytes = CipherTextBytesWithSaltAndIv.Take(KEY_SIZE / 8).ToArray()
' Get the IV bytes by extracting the next 32 bytes from the supplied cipherText bytes.
Dim oIvStringBytes = CipherTextBytesWithSaltAndIv.Skip(KEY_SIZE / 8).Take(KEY_SIZE / 8).ToArray()
' Get the actual cipher text bytes by removing the first 64 bytes from the cipherText string.
Dim oCipherTextBytes = CipherTextBytesWithSaltAndIv.Skip((KEY_SIZE / 8) * 2).Take(CipherTextBytesWithSaltAndIv.Length - ((KEY_SIZE / 8) * 2)).ToArray()
Using oPassword = New Rfc2898DeriveBytes(_password, oSaltStringBytes, DERIVATION_ITERATIONS)
Dim oKeyBytes = oPassword.GetBytes(KEY_SIZE / 8)
Using oSymmetricKey = New RijndaelManaged()
oSymmetricKey.BlockSize = BLOCK_SIZE
oSymmetricKey.Mode = _cipherMode
oSymmetricKey.Padding = _paddingMode
Using oDecryptor = oSymmetricKey.CreateDecryptor(oKeyBytes, oIvStringBytes)
Using oMemoryStream = New MemoryStream(oCipherTextBytes)
Using oCryptoStream = New CryptoStream(oMemoryStream, oDecryptor, CryptoStreamMode.Read)
Dim oPlainTextBytes = New Byte(oCipherTextBytes.Length - 1) {}
Dim oDecryptedByteCount = oCryptoStream.Read(oPlainTextBytes, 0, oPlainTextBytes.Length)
oMemoryStream.Close()
oCryptoStream.Close()
Return oPlainTextBytes
End Using
End Using
End Using
End Using
End Using
Catch ex As Exception
_logger.Error(ex)
Throw ex
End Try
End Function
Private Shared Function Generate256BitsOfRandomEntropy() As Byte()
Dim oRandomBytes = New Byte(31) {}
' 32 Bytes will give us 256 bits.
Using oRNGCsp = New RNGCryptoServiceProvider()
' Fill the array with cryptographically secure random bytes.
oRNGCsp.GetBytes(oRandomBytes)
End Using
Return oRandomBytes
End Function
End Class

View File

@@ -0,0 +1,85 @@
Imports System.Security.Cryptography
Imports System.Data
Imports System.Data.SqlClient
Public Class EncryptionLegacy
Private TripleDes As New TripleDESCryptoServiceProvider
Private DEFAULT_KEY As String = "!35452didalog="
Private SALT_VALUE As String = "!Didalog35452Heuchelheim="
Sub New()
TripleDes.Key = TruncateHash(DEFAULT_KEY, TripleDes.KeySize \ 8)
TripleDes.IV = TruncateHash("", TripleDes.BlockSize \ 8)
End Sub
Sub New(key As String)
' Initialize the crypto provider.
TripleDes.Key = TruncateHash(key, TripleDes.KeySize \ 8)
TripleDes.IV = TruncateHash("", TripleDes.BlockSize \ 8)
End Sub
Private Function TruncateHash(ByVal key As String, ByVal length As Integer) As Byte()
Dim sha1 As New SHA1CryptoServiceProvider
' Hash the key.
Dim keyBytes() As Byte =
System.Text.Encoding.Unicode.GetBytes(key)
Dim hash() As Byte = sha1.ComputeHash(keyBytes)
' Truncate or pad the hash.
ReDim Preserve hash(length - 1)
Return hash
End Function
<DebuggerStepThrough>
Public Function EncryptData(ByVal plaintext As String) As String
Try
' Convert the plaintext string to a byte array.
Dim plaintextBytes() As Byte =
System.Text.Encoding.Unicode.GetBytes(SALT_VALUE & plaintext)
' Create the stream.
Dim ms As New System.IO.MemoryStream
' Create the encoder to write to the stream.
Dim encStream As New CryptoStream(ms,
TripleDes.CreateEncryptor(),
System.Security.Cryptography.CryptoStreamMode.Write)
' Use the crypto stream to write the byte array to the stream.
encStream.Write(plaintextBytes, 0, plaintextBytes.Length)
encStream.FlushFinalBlock()
' Convert the encrypted stream to a printable string.
Return Convert.ToBase64String(ms.ToArray)
Catch ex As Exception
Return plaintext
End Try
End Function
'Entschlüsselt die Zeichenfolge
<DebuggerStepThrough>
Public Function DecryptData(ByVal EncryptedText As String) As String
Try
' Convert the encrypted text string to a byte array.
Dim oEncryptedBytes() As Byte = Convert.FromBase64String(EncryptedText)
' Create the stream.
Dim oMemoryStream As New System.IO.MemoryStream
' Create the decoder to write to the stream.
Dim oCryptoStream As New CryptoStream(oMemoryStream,
TripleDes.CreateDecryptor(),
System.Security.Cryptography.CryptoStreamMode.Write)
' Use the crypto stream to write the byte array to the stream.
oCryptoStream.Write(oEncryptedBytes, 0, oEncryptedBytes.Length)
oCryptoStream.FlushFinalBlock()
Dim oResult = System.Text.Encoding.Unicode.GetString(oMemoryStream.ToArray)
oResult = oResult.Replace(SALT_VALUE, "")
' Convert the plaintext stream to a string.
Return oResult
Catch ex As Exception
Return EncryptedText
End Try
End Function
End Class

View File

@@ -1,15 +0,0 @@
Namespace IDB
Public Class Attributes
Public Const ATTRIBUTE_DOCTYPE = "Doctype"
Public Const ATTRIBUTE_DYNAMIC_FOLDER = "Dynamic Folder"
Public Const ATTRIBUTE_ORIGIN_FILENAME = "OriginFileName"
Public Const ATTRIBUTE_ORIGIN_CHANGED = "OriginChangedDatetime"
Public Const ATTRIBUTE_ORIGIN_CREATED = "OriginCreationDatetime"
Public Const ATTRIBUTE_DISPLAY_FILENAME = "DisplayFileName"
Public Const ATTRIBUTE_DISPLAY_FILENAME1 = "DisplayFileName1"
End Class
End Namespace

View File

@@ -1,11 +0,0 @@
Namespace IDB
Public Class Database
Public Enum NamedDatabase
ECM
IDB
End Enum
End Class
End Namespace

View File

@@ -1,20 +0,0 @@
Namespace IDB
Public Class FileStore
Public Const FILE_STORE_INVALID_OBEJCT_ID = 0
Public Const FILE_CHANGED_QUESTION = "QUESTION VERSION"
Public Const FILE_CHANGED_OVERWRITE = "AUTO REPLACE"
Public Const FILE_CHANGED_VERSION = "AUTO VERSION"
Public Const OBJECT_STATE_FILE_ADDED = "File added"
Public Const OBJECT_STATE_FILE_VERSIONED = "File versioned"
Public Const OBJECT_STATE_FILE_CHANGED = "File changed"
Public Const OBJECT_STATE_FILE_OPENED = "File opened"
Public Const OBJECT_STATE_FILE_DELETED = "File deleted"
Public Const OBJECT_STATE_METADATA_CHANGED = "Metadata changed"
Public Const OBJECT_STATE_ATTRIBUTEVALUE_DELETED = "Attributevalue deleted"
Public Const OBJECT_STATE_FILE_CHECKED_OUT = "File Checked Out"
Public Const OBJECT_STATE_FILE_CHECKED_IN = "File Checked In"
End Class
End Namespace

View File

@@ -13,7 +13,7 @@ Imports System.Runtime.InteropServices
<Assembly: AssemblyCompany("")> <Assembly: AssemblyCompany("")>
<Assembly: AssemblyProduct("Base")> <Assembly: AssemblyProduct("Base")>
<Assembly: AssemblyCopyright("Copyright © 2023")> <Assembly: AssemblyCopyright("Copyright © 2023")>
<Assembly: AssemblyTrademark("1.3.5.0")> <Assembly: AssemblyTrademark("1.3.6.0")>
<Assembly: ComVisible(False)> <Assembly: ComVisible(False)>
@@ -31,5 +31,5 @@ Imports System.Runtime.InteropServices
' indem Sie "*" wie unten gezeigt eingeben: ' indem Sie "*" wie unten gezeigt eingeben:
' <Assembly: AssemblyVersion("1.0.*")> ' <Assembly: AssemblyVersion("1.0.*")>
<Assembly: AssemblyVersion("1.3.5.0")> <Assembly: AssemblyVersion("1.3.6.0")>
<Assembly: AssemblyFileVersion("1.3.5.0")> <Assembly: AssemblyFileVersion("1.3.6.0")>

View File

@@ -12,7 +12,7 @@ Public Class StringEx
''' And consecutive hyphens. ''' And consecutive hyphens.
''' </summary> ''' </summary>
''' <param name="s">The string to convert</param> ''' <param name="s">The string to convert</param>
Public Shared Function ConvertTextToSlug(ByVal s As String) As String Public Shared Function ConvertTextToSlug(s As String) As String
Dim oBuilder As New StringBuilder() Dim oBuilder As New StringBuilder()
Dim oWasHyphen As Boolean = True Dim oWasHyphen As Boolean = True
@@ -27,7 +27,7 @@ Public Class StringEx
oWasHyphen = True oWasHyphen = True
ElseIf Char.IsWhiteSpace(oChar) AndAlso Not oWasHyphen Then ElseIf Char.IsWhiteSpace(oChar) AndAlso Not oWasHyphen Then
oBuilder.Append("-"c) oBuilder.Append("_"c)
oWasHyphen = True oWasHyphen = True
End If End If
Next Next

View File

@@ -9,7 +9,7 @@ Public Class Exceptions
Public ReadOnly File As FileInfo Public ReadOnly File As FileInfo
Public Sub New(File As FileInfo) Public Sub New(File As FileInfo)
MyBase.New() MyBase.New($"Missing values in [{File.Name}]")
Me.File = File Me.File = File
End Sub End Sub
@@ -73,8 +73,11 @@ Public Class Exceptions
Public Class MD5HashException Public Class MD5HashException
Inherits ApplicationException Inherits ApplicationException
Public Sub New(pInfo As String) Public ReadOnly FileName As String
MyBase.New(pInfo)
Public Sub New(pMessage As String, pFileName As String)
MyBase.New(pMessage)
FileName = pFileName
End Sub End Sub
End Class End Class
End Class End Class

View File

@@ -1,5 +1,5 @@
Public Class EmailData Public Class EmailData
Public Attachment As String = "" Public Attachment As String = ""
Public Subject As String Public Subject As String = ""
Public From As String Public From As String = ""
End Class End Class

View File

@@ -18,7 +18,7 @@
Public Const EMAIL_MISSINGPROPERTIES_1 = "<p>Die angehängte Datei entspricht nicht dem WISAG ZUGFeRD-Format: {0}</p>" Public Const EMAIL_MISSINGPROPERTIES_1 = "<p>Die angehängte Datei entspricht nicht dem WISAG ZUGFeRD-Format: {0}</p>"
Public Const EMAIL_MISSINGPROPERTIES_2 = "<p>Die folgenden Eigenschaften wurden als ERFORDERLICH eingestuft, wurden aber nicht gefunden:<p/>" Public Const EMAIL_MISSINGPROPERTIES_2 = "<p>Die folgenden Eigenschaften wurden als ERFORDERLICH eingestuft, wurden aber nicht gefunden:<p/>"
Public Const EMAIL_MD5_ERROR = "<p>Die von Ihnen gesendete Rechnung wurde bereits von unserem System verarbeitet.</p>" Public Const EMAIL_MD5_ERROR = "<p>Die von Ihnen gesendete Rechnung ({0}) wurde bereits von unserem System verarbeitet.</p>"
Public Const EMAIL_VALIDATION_ERROR = " Public Const EMAIL_VALIDATION_ERROR = "
<p>Die von Ihnen gesendete Rechnung hat die ZUGFeRD Validierung nicht bestanden.</p> <p>Die von Ihnen gesendete Rechnung hat die ZUGFeRD Validierung nicht bestanden.</p>

View File

@@ -1,4 +1,5 @@
Imports System.Data.SqlClient Imports System.Data.SqlClient
Imports System.ServiceModel.Channels
Imports DigitalData.Modules.Database Imports DigitalData.Modules.Database
Imports DigitalData.Modules.Logging Imports DigitalData.Modules.Logging
Imports Microsoft.VisualBasic.FileIO Imports Microsoft.VisualBasic.FileIO
@@ -15,42 +16,30 @@ Namespace ZUGFeRD
_mssql = MSSQL _mssql = MSSQL
End Sub End Sub
Public Function Create_HistoryEntry(MessageId As String, MD5Checksum As String, Message As String, Transaction As SqlTransaction) As Boolean Public Function Update_HistoryEntry(pMessageId As String, pMD5Checksum As String, pMessage As String) As Boolean
Try Try
_logger.Info("Creating History Entry for MessageId [{0}] with comment [{1}]", MessageId, Message) _logger.Info("Updating History Entry for MessageId [{0}] with comment [{1}]", pMessageId, pMessage)
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 ' Only look for history entry by MessageId since the MD5 Hash might not be generated yet
Using oConnection = _mssql.GetConnection() Using oConnection = _mssql.GetConnection()
' 09.07.2021: This can't be in the transaction since the history ' 09.07.2021: This can't be in the transaction since the history
' Entry needs to be accessed by MoveAndRenameEmailToRejected shortly after ' Entry needs to be accessed by MoveAndRenameEmailToRejected shortly after
Dim oSQL = $"UPDATE TBEMLP_HISTORY SET COMMENT = '{Message}' WHERE EMAIL_MSGID = '{MessageId}'"
Dim oSQL = $"UPDATE TBEMLP_HISTORY SET
COMMENT = '{pMessage}',
MD5HASH = '{pMD5Checksum}'
WHERE EMAIL_MSGID = '{pMessageId}'"
If pMessage.Contains("REJECTED") Then
oSQL = $"UPDATE TBEMLP_HISTORY SET
COMMENT = '{pMessage}',
MD5HASH = '{pMD5Checksum}',
STATUS = 'REJECTED',
CUST_REJECTED = 1,
CUST_REJECTED_WHEN = GETDATE()
WHERE EMAIL_MSGID = '{pMessageId}'"
End If
_mssql.ExecuteNonQueryWithConnectionObject(oSQL, oConnection) _mssql.ExecuteNonQueryWithConnectionObject(oSQL, oConnection)
End Using End Using
@@ -58,7 +47,7 @@ Namespace ZUGFeRD
Return True Return True
Catch ex As Exception Catch ex As Exception
_logger.Warn("History Entry count not be updated for message id [{0}] and md5 [{1}]", MessageId, MD5Checksum) _logger.Warn("History Entry count not be updated for message id [{0}] and md5 [{1}]", pMessageId, pMD5Checksum)
_logger.Error(ex) _logger.Error(ex)
Return False Return False

View File

@@ -37,12 +37,19 @@ Public Class ImportZUGFeRDFiles
Private ReadOnly _email As ZUGFeRD.EmailFunctions Private ReadOnly _email As ZUGFeRD.EmailFunctions
Private ReadOnly _file As ZUGFeRD.FileFunctions Private ReadOnly _file As ZUGFeRD.FileFunctions
Private ReadOnly _history As ZUGFeRD.HistoryFunctions Private ReadOnly _history As ZUGFeRD.HistoryFunctions
Private ReadOnly _embeds As PDFEmbeds
Private ReadOnly _gdpictureLicenseKey As String Private ReadOnly _gdpictureLicenseKey As String
Private _zugferd As ZUGFeRDInterface Private _zugferd As ZUGFeRDInterface
Private _EmailOutAccountId As Integer Private _EmailOutAccountId As Integer
Private Class ProcessFileResult
Public ZugferdFileCount As Integer
Public MD5Hash As String = Nothing
End Class
Private Class DatabaseConnections Private Class DatabaseConnections
Public Property SQLServerConnection As SqlConnection Public Property SQLServerConnection As SqlConnection
Public Property SQLServerTransaction As SqlTransaction Public Property SQLServerTransaction As SqlTransaction
@@ -56,6 +63,7 @@ Public Class ImportZUGFeRDFiles
_email = New ZUGFeRD.EmailFunctions(LogConfig, _mssql) _email = New ZUGFeRD.EmailFunctions(LogConfig, _mssql)
_file = New ZUGFeRD.FileFunctions(LogConfig, _mssql) _file = New ZUGFeRD.FileFunctions(LogConfig, _mssql)
_history = New ZUGFeRD.HistoryFunctions(LogConfig, _mssql) _history = New ZUGFeRD.HistoryFunctions(LogConfig, _mssql)
_embeds = New PDFEmbeds(LogConfig)
_logger.Debug("Registering GDPicture License") _logger.Debug("Registering GDPicture License")
If _mssql IsNot Nothing Then If _mssql IsNot Nothing Then
@@ -67,82 +75,6 @@ Public Class ImportZUGFeRDFiles
End If End If
End Sub End Sub
Private Function MoveAndRenameEmailToRejected(pArgs As WorkerArgs, pMessageId As String) As EmailData
_logger.Info("Moving Mail with MessageId [{0}] to Rejected folder", pMessageId)
_logger.Debug("Fetching Email Data")
Dim oEmailData = _email.GetEmailDataForMessageId(pMessageId)
_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 oDestination As String
Dim oRejectedDirectory As String = Path.Combine(pArgs.RejectedEmailDirectory, oDateSubDirectoryName)
' Create the destination directory if it does not exist
_logger.Debug("Creating destination directory [{0}]", oRejectedDirectory)
If Not Directory.Exists(oRejectedDirectory) Then
Try
Directory.CreateDirectory(oRejectedDirectory)
Catch ex As Exception
_logger.Error(ex)
End Try
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.
' This only should happen when testing and db-tables are deleted frequently
If oEmailData Is Nothing Then
oDestination = _email.GetEmailPathWithSubjectAsName(oRejectedDirectory, pMessageId)
Else
oDestination = _email.GetEmailPathWithSubjectAsName(oRejectedDirectory, StringEx.ConvertTextToSlug(oEmailData.Subject))
End If
_logger.Debug("Destination for eml file is {0}", oDestination)
Dim oFinalFileName = _filesystem.GetVersionedFilename(oDestination)
_logger.Debug("Versioned filename for eml file is {0}", oFinalFileName)
If oEmailData Is Nothing Then
_logger.Warn("Could not get Email Data from firebird-database. File {0} will not be moved!", oSource)
Return Nothing
End If
'---------------------------
Try
_logger.Info("Moving email from {0} to {1}", oSource, oFinalFileName)
File.Move(oSource, oFinalFileName)
oEmailData.Attachment = oFinalFileName
Catch ex As Exception
_logger.Warn("File {0} could not be moved! Original Filename will be used!", oSource)
_logger.Error(ex)
oEmailData.Attachment = oSource
End Try
_logger.Info("Email [{0}] moved to rejected folder!", pMessageId)
Return oEmailData
End Function
Private Sub AddRejectedState(oMessageID As String, oTitle As String, oTitle1 As String, oComment As String, Transaction As SqlTransaction)
Try
'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("'", "''")}'"
_mssql.ExecuteNonQuery(oSQL, Transaction)
Catch ex As Exception
_logger.Error(ex)
End Try
End Sub
Public Sub Start(Arguments As Object) Implements IJob.Start Public Sub Start(Arguments As Object) Implements IJob.Start
Dim oArgs As WorkerArgs = Arguments Dim oArgs As WorkerArgs = Arguments
Dim oPropertyExtractor = New PropertyValues(_logConfig) Dim oPropertyExtractor = New PropertyValues(_logConfig)
@@ -159,27 +91,30 @@ Public Class ImportZUGFeRDFiles
_logger.Debug("Starting Job {0}", [GetType].Name) _logger.Debug("Starting Job {0}", [GetType].Name)
Try Try
For Each oPath As String In oArgs.WatchDirectories 'For Each oPath As String In oArgs.WatchDirectory
Dim oPath As String = oArgs.WatchDirectory
Dim oDirInfo As New DirectoryInfo(oPath) Dim oDirInfo As New DirectoryInfo(oPath)
_logger.Debug($"Start processing directory {oDirInfo.FullName}") _logger.Debug($"Start processing directory {oDirInfo.FullName}")
If oDirInfo.Exists Then If oDirInfo.Exists = False Then
_logger.Warn("Watch directory exists. Exiting.")
Exit Sub
End If
' Filter out *.lock files ' Filter out *.lock files
Dim oFiles As List(Of FileInfo) = oDirInfo. Dim oFiles As List(Of FileInfo) = oDirInfo.
GetFiles(). GetFiles().
Where(Function(f) Not f.Name.EndsWith(".lock")). Where(Function(f) Not f.Name.EndsWith(".lock")).
ToList() ToList()
Dim oFileCount = oFiles.Count
Dim oCurrentFileCount = 0
If oFileCount = 0 Then If oFiles.Count = 0 Then
_logger.Debug("No files to process.") _logger.Debug("No files to process. Exiting.")
Continue For Exit Sub
Else
_logger.Info("Found {0} files", oFileCount)
End If End If
_logger.Info("Found {0} files", oFiles.Count)
' Group files by messageId ' Group files by messageId
Dim oGrouped As Dictionary(Of String, List(Of FileInfo)) = _zugferd.FileGroup.GroupFiles(oFiles) Dim oGrouped As Dictionary(Of String, List(Of FileInfo)) = _zugferd.FileGroup.GroupFiles(oFiles)
@@ -223,6 +158,9 @@ Public Class ImportZUGFeRDFiles
_logger.Info("Start processing file group {0}", oMessageId) _logger.Info("Start processing file group {0}", oMessageId)
' TODO: Use this refactored function
' ProcessFileGroup(oMessageId, oFileGroupFiles, oConnections, oArgs)
Try Try
For Each oFile In oFileGroupFiles For Each oFile In oFileGroupFiles
' 09.12.2021: oDocument is now an Object, because have different classes corresponding to the ' 09.12.2021: oDocument is now an Object, because have different classes corresponding to the
@@ -237,7 +175,6 @@ Public Class ImportZUGFeRDFiles
Dim oGlobalGroupCounter = 0 Dim oGlobalGroupCounter = 0
' Clear missing properties for the new file ' Clear missing properties for the new file
oMissingProperties = New List(Of String) oMissingProperties = New List(Of String)
oCurrentFileCount += 1
' Only pdf files are allowed from here on ' Only pdf files are allowed from here on
If Not oFile.Name.ToUpper.EndsWith(".PDF") Then If Not oFile.Name.ToUpper.EndsWith(".PDF") Then
@@ -307,7 +244,7 @@ Public Class ImportZUGFeRDFiles
End If End If
' Check the Checksum and rejection status ' Check the Checksum and rejection status
oMD5CheckSum = GenerateAndCheck_MD5Sum(oFile.FullName, oMessageId, oArgs.IgnoreRejectionStatus) oMD5CheckSum = GenerateAndCheck_MD5Sum(oFile, oMessageId, oArgs.IgnoreRejectionStatus)
' Check the document against the configured property map and return: ' Check the document against the configured property map and return:
' - a List of valid properties ' - a List of valid properties
@@ -369,9 +306,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
_history.Create_HistoryEntry(oMessageId, oMD5CheckSum, "SUCCESS", oSQLTransaction) _history.Update_HistoryEntry(oMessageId, oMD5CheckSum, "SUCCESS")
Else Else
_history.Create_HistoryEntry(oMessageId, String.Empty, "SUCCESS (with empty MD5Hash)", oSQLTransaction) _history.Update_HistoryEntry(oMessageId, String.Empty, "SUCCESS (with empty MD5Hash)")
End If End If
oIsSuccess = True oIsSuccess = True
@@ -382,7 +319,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!"
_history.Update_HistoryEntry(oMessageId, oMD5CheckSum, oMessage, oSQLTransaction) _history.Update_HistoryEntry(oMessageId, oMD5CheckSum, oMessage)
Dim oErrorList As String = "" Dim oErrorList As String = ""
For Each oError In oErrors For Each oError In oErrors
@@ -400,9 +337,9 @@ 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)"
_history.Update_HistoryEntry(oMessageId, String.Empty, oMessage, oSQLTransaction) _history.Update_HistoryEntry(oMessageId, String.Empty, oMessage)
Dim oBody = EmailStrings.EMAIL_MD5_ERROR Dim oBody = String.Format(EmailStrings.EMAIL_MD5_ERROR, ex.FileName)
Dim oEmailData = MoveAndRenameEmailToRejected(oArgs, oMessageId) Dim oEmailData = MoveAndRenameEmailToRejected(oArgs, oMessageId)
_email.AddToEmailQueueMSSQL(oMessageId, oBody, oEmailData, "MD5HashException", _EmailOutAccountId, oArgs.NamePortal) _email.AddToEmailQueueMSSQL(oMessageId, oBody, oEmailData, "MD5HashException", _EmailOutAccountId, oArgs.NamePortal)
AddRejectedState(oMessageId, "MD5HashException", "Die gesendete Rechnung wurde bereits verarbeitet!", "", oSQLTransaction) AddRejectedState(oMessageId, "MD5HashException", "Die gesendete Rechnung wurde bereits verarbeitet!", "", oSQLTransaction)
@@ -412,7 +349,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.
_history.Create_HistoryEntry(oMessageId, String.Empty, "REJECTED - ZUGFeRD yes but unsupported format", oSQLTransaction) _history.Update_HistoryEntry(oMessageId, String.Empty, "REJECTED - ZUGFeRD yes but unsupported format")
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)
@@ -425,7 +362,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.
_history.Create_HistoryEntry(oMessageId, String.Empty, "REJECTED - ZUGFeRD yes but incorrect format", oSQLTransaction) _history.Update_HistoryEntry(oMessageId, String.Empty, "REJECTED - ZUGFeRD yes but incorrect format")
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)
@@ -436,7 +373,7 @@ Public Class ImportZUGFeRDFiles
Catch ex As TooMuchFerdsException Catch ex As TooMuchFerdsException
_logger.Error(ex) _logger.Error(ex)
_history.Create_HistoryEntry(oMessageId, oMD5CheckSum, "REJECTED - More than one ZUGFeRD-document in email", oSQLTransaction) _history.Update_HistoryEntry(oMessageId, oMD5CheckSum, "REJECTED - More than one ZUGFeRD-document in email")
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)
@@ -447,7 +384,7 @@ Public Class ImportZUGFeRDFiles
Catch ex As NoFerdsException Catch ex As NoFerdsException
_logger.Error(ex) _logger.Error(ex)
_history.Create_HistoryEntry(oMessageId, oMD5CheckSum, "REJECTED - no ZUGFeRD-Document in email", oSQLTransaction) _history.Update_HistoryEntry(oMessageId, oMD5CheckSum, "REJECTED - no ZUGFeRD-Document in email")
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)
@@ -463,7 +400,7 @@ Public Class ImportZUGFeRDFiles
oMessage &= $"- {prop}" oMessage &= $"- {prop}"
Next Next
_history.Create_HistoryEntry(oMessageId, oMD5CheckSum, $"REJECTED - Missing Required Properties: [{oMessage}]", oSQLTransaction) _history.Update_HistoryEntry(oMessageId, oMD5CheckSum, $"REJECTED - Missing Required Properties: [{oMessage}]")
Dim oBody = _email.CreateBodyForMissingProperties(ex.File.Name, oMissingProperties) Dim oBody = _email.CreateBodyForMissingProperties(ex.File.Name, oMissingProperties)
Dim oEmailData = MoveAndRenameEmailToRejected(oArgs, oMessageId) Dim oEmailData = MoveAndRenameEmailToRejected(oArgs, oMessageId)
@@ -473,7 +410,7 @@ Public Class ImportZUGFeRDFiles
Catch ex As FileSizeLimitReachedException Catch ex As FileSizeLimitReachedException
_logger.Error(ex) _logger.Error(ex)
_history.Create_HistoryEntry(oMessageId, oMD5CheckSum, "REJECTED - File size limit reached", oSQLTransaction) _history.Update_HistoryEntry(oMessageId, oMD5CheckSum, "REJECTED - File size limit reached")
Dim oEmailData = MoveAndRenameEmailToRejected(oArgs, oMessageId) Dim oEmailData = MoveAndRenameEmailToRejected(oArgs, oMessageId)
@@ -576,8 +513,7 @@ Public Class ImportZUGFeRDFiles
_logger.Warn("Database Connections were not closed successfully.") _logger.Warn("Database Connections were not closed successfully.")
End Try End Try
End Try End Try
Next
End If
Next Next
_logger.Debug("Finishing Job {0}", Me.GetType.Name) _logger.Debug("Finishing Job {0}", Me.GetType.Name)
@@ -587,6 +523,520 @@ Public Class ImportZUGFeRDFiles
End Try End Try
End Sub End Sub
#Region "=== REFACTOR"
Private Function ProcessFileGroup(oMessageId As String, pFiles As List(Of FileInfo), oConnections As DatabaseConnections, pArgs As WorkerArgs)
Dim oMissingProperties = New List(Of String)
Dim oEmailAttachmentFiles = New List(Of FileInfo)
Dim oEmbeddedAttachmentFiles = New List(Of PDFEmbeds.EmbeddedFile)
Dim oZUGFeRDCount = 0
Dim oMD5CheckSum As String = Nothing
' Set the default Move Directory
Dim oMoveDirectory As String = pArgs.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
Try
For Each oFile In pFiles
' 09.12.2021: oDocument is now an Object, because have different classes corresponding to the
' different versions of ZUGFeRD and the type is unknown at compile-time.
' 17.11.2022: oDocument is now a Tuple of (String, Object), to be able to return the filename
' of the extracted xml file.
' 21.12.2022: oDocument is now an object of type ZugferdResult to be able to save
' the new meta data, ie. the type of schema (zugferd version)
Dim oDocument As ZUGFeRDInterface.ZugferdResult
' Start a global group counter for each file
Dim oGlobalGroupCounter = 0
' Clear missing properties for the new file
oMissingProperties = New List(Of String)
' Only pdf files are allowed from here on
If Not oFile.Name.ToUpper.EndsWith(".PDF") Then
_logger.Debug("Skipping non-pdf file {0}", oFile.Name)
oEmailAttachmentFiles.Add(oFile)
' Checking filesize for attachment files
If _filesystem.TestFileSizeIsLessThanMaxFileSize(oFile.FullName, pArgs.MaxAttachmentSizeInMegaBytes) = False Then
_logger.Warn("Filesize for File [{0}] exceeded limit of {1} MB", oFile.Name, pArgs.MaxAttachmentSizeInMegaBytes)
Throw New FileSizeLimitReachedException(oFile.Name, pArgs.MaxAttachmentSizeInMegaBytes)
End If
Continue For
End If
_logger.Info("Start processing file {0}", oFile.Name)
' Checking filesize for pdf files
If _filesystem.TestFileSizeIsLessThanMaxFileSize(oFile.FullName, pArgs.MaxAttachmentSizeInMegaBytes) = False Then
_logger.Warn("Filesize for File [{0}] exceeded limit of {1} MB", oFile.Name, pArgs.MaxAttachmentSizeInMegaBytes)
Throw New FileSizeLimitReachedException(oFile.Name, pArgs.MaxAttachmentSizeInMegaBytes)
End If
Try
oDocument = _zugferd.ExtractZUGFeRDFileWithGDPicture(oFile.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.", oFile.Name)
oEmailAttachmentFiles.Add(oFile)
Continue For
Case ZUGFeRDInterface.ErrorType.UnsupportedFormat
_logger.Info("File [{0}/{1}] is an unsupported ZUFeRD document format!", oFile.Name, ex.XmlFile)
Throw New UnsupportedFerdException(ex.XmlFile)
Case ZUGFeRDInterface.ErrorType.NoValidZugferd
_logger.Info("File [{0}] is an Incorrectly formatted ZUGFeRD document!", oFile.Name)
Throw New InvalidFerdException()
Case Else
_logger.Warn("Unexpected Error occurred while extracting ZUGFeRD Information from file {0}", oFile.Name)
Throw ex
End Select
End Try
' Check if there are more than one ZUGFeRD files
If oZUGFeRDCount = 1 Then
Throw New TooMuchFerdsException()
End If
' Since extraction went well, increase the amount of ZUGFeRD files
oZUGFeRDCount += 1
' 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(oFile.FullName, AllowedExtensions)
If oAttachments Is Nothing Then
_logger.Warn("Attachments for file [{0}] could not be extracted", oFile.FullName)
Else
oEmbeddedAttachmentFiles.AddRange(oAttachments)
End If
' Check the Checksum and rejection status
oMD5CheckSum = GenerateAndCheck_MD5Sum(oFile, oMessageId, pArgs.IgnoreRejectionStatus)
' 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, oDocument.Specification)
Dim oCheckResult = _zugferd.PropertyValues.CheckPropertyValues(oDocument.SchemaObject, oPropertyMap, oMessageId)
_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)
oMissingProperties = oCheckResult.MissingProperties
Throw New MissingValueException(oFile)
Else
_logger.Debug("No missing properties found. Continuing.")
End If
DeleteExistingPropertyValues(oMessageId, oConnections)
Dim oFirstProperty = oCheckResult.ValidProperties.FirstOrDefault()
If oFirstProperty IsNot Nothing Then
InsertPropertyValue(oMessageId, oConnections, New PropertyValues.ValidProperty() With {
.MessageId = oMessageId,
.Description = "ZUGFeRDSpezifikation",
.GroupCounter = 0,
.IsRequired = False,
.Value = oDocument.Specification,
.TableName = oFirstProperty.TableName,
.TableColumn = "ZUGFERD_SPECIFICATION"
})
End If
For Each oProperty In oCheckResult.ValidProperties
InsertPropertyValue(oMessageId, oConnections, oProperty)
Next
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 pArgs.NonZugferdDirectory Is Nothing OrElse pArgs.NonZugferdDirectory = String.Empty Then
Throw New NoFerdsException()
End If
' Also, if the directory is set but does not exist, still a rejection will be generated.
If Not IO.Directory.Exists(pArgs.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...
'Log the History
If oMD5CheckSum <> String.Empty Then
_history.Update_HistoryEntry(oMessageId, oMD5CheckSum, "SUCCESS")
Else
_history.Update_HistoryEntry(oMessageId, String.Empty, "SUCCESS (with empty MD5Hash)")
End If
oIsSuccess = True
oMoveDirectory = pArgs.SuccessDirectory
Catch ex As ValidationException
_logger.Error(ex)
Dim oErrors = ex.ValidationErrors
Dim oMessage = "REJECTED - ZUGFeRD yes but formal validation failed!"
_history.Update_HistoryEntry(oMessageId, oMD5CheckSum, oMessage)
Dim oErrorList As String = ""
For Each oError In oErrors
oErrorList += $"<li>Element '{oError.ElementName}' mit Wert '{oError.ElementValue}': {oError.ErrorMessage}</li>"
Next
Dim oBody = String.Format(EmailStrings.EMAIL_VALIDATION_ERROR, oErrorList)
Dim oEmailData = MoveAndRenameEmailToRejected(pArgs, oMessageId)
_email.AddToEmailQueueMSSQL(oMessageId, oBody, oEmailData, "ValidationException", _EmailOutAccountId, pArgs.NamePortal)
AddRejectedState(oMessageId, "ValidationException", "Die Rechnungsvalidierung ist fehlgeschlagen!", "", oConnections.SQLServerTransaction)
Catch ex As MD5HashException
_logger.Error(ex)
' When MD5HashException is thrown, we don't have a MD5Hash yet.
' That 's why we set it to String.Empty here.
Dim oMessage = "REJECTED - Already processed (MD5Hash)"
_history.Update_HistoryEntry(oMessageId, String.Empty, oMessage)
Dim oBody = EmailStrings.EMAIL_MD5_ERROR
Dim oEmailData = MoveAndRenameEmailToRejected(pArgs, oMessageId)
_email.AddToEmailQueueMSSQL(oMessageId, oBody, oEmailData, "MD5HashException", _EmailOutAccountId, pArgs.NamePortal)
AddRejectedState(oMessageId, "MD5HashException", "Die gesendete Rechnung wurde bereits verarbeitet!", "", oConnections.SQLServerTransaction)
Catch ex As UnsupportedFerdException
_logger.Error(ex)
' When UnsupportedFerdException is thrown, we don't have a MD5Hash yet.
' That 's why we set it to String.Empty here.
_history.Update_HistoryEntry(oMessageId, String.Empty, "REJECTED - ZUGFeRD yes but unsupported format")
Dim oEmailData = MoveAndRenameEmailToRejected(pArgs, oMessageId)
Dim oBody As String = String.Format(EmailStrings.EMAIL_UNSUPPORTED_DOCUMENT, oEmailData.Subject, ex.XmlFile)
_email.AddToEmailQueueMSSQL(oMessageId, oBody, oEmailData, "UnsupportedFerdException", _EmailOutAccountId, pArgs.NamePortal)
AddRejectedState(oMessageId, "UnsupportedFerdException", "Nicht unterstütztes Datenformat", "", oConnections.SQLServerTransaction)
Catch ex As InvalidFerdException
_logger.Error(ex)
' When InvalidFerdException is thrown, we don't have a MD5Hash yet.
' That 's why we set it to String.Empty here.
_history.Update_HistoryEntry(oMessageId, String.Empty, "REJECTED - ZUGFeRD yes but incorrect format")
Dim oEmailData = MoveAndRenameEmailToRejected(pArgs, oMessageId)
Dim oBody = String.Format(EmailStrings.EMAIL_INVALID_DOCUMENT, oEmailData.Subject)
_email.AddToEmailQueueMSSQL(oMessageId, oBody, oEmailData, "InvalidFerdException", _EmailOutAccountId, pArgs.NamePortal)
AddRejectedState(oMessageId, "InvalidFerdException", "Inkorrekte Formate", "", oConnections.SQLServerTransaction)
Catch ex As TooMuchFerdsException
_logger.Error(ex)
_history.Update_HistoryEntry(oMessageId, oMD5CheckSum, "REJECTED - More than one ZUGFeRD-document in email")
Dim oEmailData = MoveAndRenameEmailToRejected(pArgs, oMessageId)
Dim oBody = String.Format(EmailStrings.EMAIL_TOO_MUCH_FERDS, oEmailData.Subject)
_email.AddToEmailQueueMSSQL(oMessageId, oBody, oEmailData, "TooMuchFerdsException", _EmailOutAccountId, pArgs.NamePortal)
AddRejectedState(oMessageId, "TooMuchFerdsException", "Email enthielt mehr als ein ZUGFeRD-Dokument", "", oConnections.SQLServerTransaction)
Catch ex As NoFerdsException
_logger.Error(ex)
_history.Update_HistoryEntry(oMessageId, oMD5CheckSum, "REJECTED - no ZUGFeRD-Document in email")
Dim oEmailData = MoveAndRenameEmailToRejected(pArgs, oMessageId)
Dim oBody = String.Format(EmailStrings.EMAIL_NO_FERDS, oEmailData.Subject)
_email.AddToEmailQueueMSSQL(oMessageId, oBody, oEmailData, "NoFerdsException", _EmailOutAccountId, pArgs.NamePortal)
AddRejectedState(oMessageId, "NoFerdsException", " Email enthielt keine ZUGFeRD-Dokumente", "", oConnections.SQLServerTransaction)
Catch ex As MissingValueException
_logger.Error(ex)
Dim oMessage As String = ""
For Each prop In oMissingProperties
oMessage &= $"- {prop}"
Next
_history.Update_HistoryEntry(oMessageId, oMD5CheckSum, $"REJECTED - Missing Required Properties: [{oMessage}]")
Dim oBody = _email.CreateBodyForMissingProperties(ex.File.Name, oMissingProperties)
Dim oEmailData = MoveAndRenameEmailToRejected(pArgs, oMessageId)
_email.AddToEmailQueueMSSQL(oMessageId, oBody, oEmailData, "MissingValueException", _EmailOutAccountId, pArgs.NamePortal)
AddRejectedState(oMessageId, "MissingValueException", "Es fehlten ZugferdSpezifikationen", oMessage, oConnections.SQLServerTransaction)
Catch ex As FileSizeLimitReachedException
_logger.Error(ex)
_history.Update_HistoryEntry(oMessageId, oMD5CheckSum, "REJECTED - File size limit reached")
Dim oEmailData = MoveAndRenameEmailToRejected(pArgs, oMessageId)
Dim oKey = FileSizeLimitReachedException.KEY_FILENAME
Dim oFileExceedingThreshold As String = IIf(ex.Data.Contains(oKey), ex.Data.Item(oKey), "")
Dim oFileWithoutMessageId = oFileExceedingThreshold.
Replace(oMessageId, "").
Replace("~", "")
Dim oBody = String.Format(EmailStrings.EMAIL_FILE_SIZE_REACHED, pArgs.MaxAttachmentSizeInMegaBytes, oFileWithoutMessageId)
_email.AddToEmailQueueMSSQL(oMessageId, oBody, oEmailData, "FileSizeLimitReachedException", _EmailOutAccountId, pArgs.NamePortal)
AddRejectedState(oMessageId, "FileSizeLimitReachedException", "Erlaubte Dateigröße überschritten", "", oConnections.SQLServerTransaction)
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 = pArgs.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 = pArgs.ExceptionEmailAddress,
.Subject = $"OutOfMemoryException im ZUGFeRD-Parser @ {oMessageId}"
}
_email.AddToEmailQueueMSSQL(oMessageId, oBody, oEmailData, "OutOfMemoryException", _EmailOutAccountId, pArgs.NamePortal)
' Rollback Transaction
oConnections.SQLServerTransaction.Rollback()
oMoveDirectory = DIRECTORY_DONT_MOVE
oExpectedError = False
Catch ex As Exception
_logger.Warn("Unknown 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 = pArgs.ExceptionEmailAddress,
.Subject = $"UnhandledException im ZUGFeRD-Parser @ {oMessageId}"
}
_email.AddToEmailQueueMSSQL(oMessageId, oBody, oEmailData, "UnhandledException", _EmailOutAccountId, pArgs.NamePortal)
' Rollback Transaction
oConnections.SQLServerTransaction.Rollback()
oMoveDirectory = DIRECTORY_DONT_MOVE
oExpectedError = False
Finally
Try
' 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)
Else
' Move all files of the current group
_file.MoveFiles(pArgs, oMessageId, pFiles, oEmailAttachmentFiles, oEmbeddedAttachmentFiles, oMoveDirectory, oIsSuccess)
End If
_logger.Info("Finished 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 = pArgs.ExceptionEmailAddress,
.Subject = $"FileMoveException im ZUGFeRD-Parser @ {oMessageId}"
}
_email.AddToEmailQueueMSSQL(oMessageId, oBody, oEmailData, "FileMoveException", _EmailOutAccountId, pArgs.NamePortal)
_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
' Commit Transaction
oConnections.SQLServerTransaction.Commit()
End If
_logger.Info("FileGroup for MessageId [{0}] successfully processed!", oMessageId)
Catch ex As Exception
_logger.Error(ex)
_logger.Warn("Database Transactions were not committed successfully.")
End Try
Try
oConnections.SQLServerConnection.Close()
Catch ex As Exception
_logger.Error(ex)
_logger.Warn("Database Connections were not closed successfully.")
End Try
End Try
End Function
Private Function ProcessFile(pMessageId As String, oFile As FileInfo, oConnections As DatabaseConnections, pArgs As WorkerArgs) As ProcessFileResult
' 09.12.2021: oDocument is now an Object, because have different classes corresponding to the
' different versions of ZUGFeRD and the type is unknown at compile-time.
' 17.11.2022: oDocument is now a Tuple of (String, Object), to be able to return the filename
' of the extracted xml file.
' 21.12.2022: oDocument is now an object of type ZugferdResult to be able to save
' the new meta data, ie. the type of schema (zugferd version)
Dim oDocument As ZUGFeRDInterface.ZugferdResult
Dim oMissingProperties = New List(Of String)
Dim oEmailAttachmentFiles = New List(Of FileInfo)
Dim oEmbeddedAttachmentFiles = New List(Of PDFEmbeds.EmbeddedFile)
Dim oZugferdFiles As Integer = 0
' Start a global group counter for each file
Dim oGlobalGroupCounter = 0
' Clear missing properties for the new file
oMissingProperties = New List(Of String)
' Only pdf files are allowed from here on
If Not oFile.Name.ToUpper.EndsWith(".PDF") Then
_logger.Debug("Skipping non-pdf file {0}", oFile.Name)
oEmailAttachmentFiles.Add(oFile)
' Checking filesize for attachment files
If _filesystem.TestFileSizeIsLessThanMaxFileSize(oFile.FullName, pArgs.MaxAttachmentSizeInMegaBytes) = False Then
_logger.Warn("Filesize for File [{0}] exceeded limit of {1} MB", oFile.Name, pArgs.MaxAttachmentSizeInMegaBytes)
Throw New FileSizeLimitReachedException(oFile.Name, pArgs.MaxAttachmentSizeInMegaBytes)
End If
'TODO: how to handle?
'Continue For
End If
_logger.Info("Start processing file {0}", oFile.Name)
' Checking filesize for pdf files
If _filesystem.TestFileSizeIsLessThanMaxFileSize(oFile.FullName, pArgs.MaxAttachmentSizeInMegaBytes) = False Then
_logger.Warn("Filesize for File [{0}] exceeded limit of {1} MB", oFile.Name, pArgs.MaxAttachmentSizeInMegaBytes)
Throw New FileSizeLimitReachedException(oFile.Name, pArgs.MaxAttachmentSizeInMegaBytes)
End If
Try
oDocument = _zugferd.ExtractZUGFeRDFileWithGDPicture(oFile.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.", oFile.Name)
oEmailAttachmentFiles.Add(oFile)
'TODO: How to handle?
'Continue For
Case ZUGFeRDInterface.ErrorType.UnsupportedFormat
_logger.Info("File [{0}/{1}] is an unsupported ZUFeRD document format!", oFile.Name, ex.XmlFile)
Throw New UnsupportedFerdException(ex.XmlFile)
Case ZUGFeRDInterface.ErrorType.NoValidZugferd
_logger.Info("File [{0}] is an Incorrectly formatted ZUGFeRD document!", oFile.Name)
Throw New InvalidFerdException()
Case Else
_logger.Warn("Unexpected Error occurred while extracting ZUGFeRD Information from file {0}", oFile.Name)
Throw ex
End Select
End Try
' Check if there are more than one ZUGFeRD files
If oZugferdFiles = 1 Then
Throw New TooMuchFerdsException()
End If
' Since extraction went well, increase the amount of ZUGFeRD files
oZugferdFiles += 1
' 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(oFile.FullName, AllowedExtensions)
If oAttachments Is Nothing Then
_logger.Warn("Attachments for file [{0}] could not be extracted", oFile.FullName)
Else
oEmbeddedAttachmentFiles.AddRange(oAttachments)
End If
' Check the Checksum and rejection status
Dim oMD5CheckSum = GenerateAndCheck_MD5Sum(oFile, pMessageId, pArgs.IgnoreRejectionStatus)
' 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, oDocument.Specification)
Dim oCheckResult = _zugferd.PropertyValues.CheckPropertyValues(oDocument.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)
oMissingProperties = oCheckResult.MissingProperties
Throw New MissingValueException(oFile)
Else
_logger.Debug("No missing properties found. Continuing.")
End If
DeleteExistingPropertyValues(pMessageId, oConnections)
Dim oFirstProperty = oCheckResult.ValidProperties.FirstOrDefault()
If oFirstProperty IsNot Nothing Then
InsertPropertyValue(pMessageId, oConnections, New PropertyValues.ValidProperty() With {
.MessageId = pMessageId,
.Description = "ZUGFeRDSpezifikation",
.GroupCounter = 0,
.IsRequired = False,
.Value = oDocument.Specification,
.TableName = oFirstProperty.TableName,
.TableColumn = "ZUGFERD_SPECIFICATION"
})
End If
For Each oProperty In oCheckResult.ValidProperties
InsertPropertyValue(pMessageId, oConnections, oProperty)
Next
Return New ProcessFileResult With {
.ZugferdFileCount = oZugferdFiles
}
End Function
#End Region
Private Sub DeleteExistingPropertyValues(pMessageId As String, pConnections As DatabaseConnections) Private Sub DeleteExistingPropertyValues(pMessageId As String, pConnections As DatabaseConnections)
Dim oDelSQL = $"DELETE FROM TBEDMI_ITEM_VALUE where REFERENCE_GUID = '{pMessageId}'" Dim oDelSQL = $"DELETE FROM TBEDMI_ITEM_VALUE where REFERENCE_GUID = '{pMessageId}'"
Dim oStep As String Dim oStep As String
@@ -648,12 +1098,12 @@ Public Class ImportZUGFeRDFiles
''' <param name="pIgnoreRejectionStatus">Should the check take into account the rejection status of the file?</param> ''' <param name="pIgnoreRejectionStatus">Should the check take into account the rejection status of the file?</param>
''' <returns>The MD5 Checksum of the file, or an empty string, if the Checksum could not be created</returns> ''' <returns>The MD5 Checksum of the file, or an empty string, if the Checksum could not be created</returns>
''' <exception cref="MD5HashException">Throws, when the file should be rejected, ie. if it already exists in the table</exception> ''' <exception cref="MD5HashException">Throws, when the file should be rejected, ie. if it already exists in the table</exception>
Private Function GenerateAndCheck_MD5Sum(pFilePath As String, pMessageId As String, pIgnoreRejectionStatus As Boolean) As String Private Function GenerateAndCheck_MD5Sum(pFile As FileInfo, pMessageId As String, pIgnoreRejectionStatus As Boolean) As String
Dim oMD5CheckSum = CreateMD5(pFilePath) Dim oMD5CheckSum = CreateMD5(pFile.FullName)
' Exit if MD5 could not be created ' Exit if MD5 could not be created
If oMD5CheckSum = String.Empty Then If oMD5CheckSum = String.Empty Then
_logger.Warn("MD5 Checksum is nothing for file [{0}]!", pFilePath) _logger.Warn("MD5 Checksum is nothing for file [{0}]!", pFile.FullName)
Return oMD5CheckSum Return oMD5CheckSum
End If End If
@@ -668,13 +1118,13 @@ Public Class ImportZUGFeRDFiles
' If History entries could not be fetched, just return the MD5 Checksum ' If History entries could not be fetched, just return the MD5 Checksum
If IsNothing(oTable) Then If IsNothing(oTable) Then
_logger.Warn("Be careful: oExistsDT is nothing for file [{0}]!", pFilePath) _logger.Warn("Be careful: oExistsDT is nothing for file [{0}]!", pFile.FullName)
Return oMD5CheckSum Return oMD5CheckSum
End If End If
' If Checksum does not exist in History entries, just return the MD5 Checksum ' If Checksum does not exist in History entries, just return the MD5 Checksum
If oTable.Rows.Count = 0 Then If oTable.Rows.Count = 0 Then
_logger.Debug("File [{0}] was not found in History!", pFilePath) _logger.Debug("File [{0}] was not found in History!", pFile.FullName)
Return oMD5CheckSum Return oMD5CheckSum
End If End If
@@ -711,12 +1161,88 @@ Public Class ImportZUGFeRDFiles
_logger.Info("ZuGFeRDFile already has been processed, but Rejection Status will be ignored!") _logger.Info("ZuGFeRDFile already has been processed, but Rejection Status will be ignored!")
ElseIf oRejected = False Then ElseIf oRejected = False Then
_logger.Info("ZuGFeRDFile already has been processed. Will be rejected.") _logger.Info("ZuGFeRDFile already has been processed. Will be rejected.")
Throw New MD5HashException($"There is already an identical invoice! - HistoryID [{oHistoryId}] - Case 1") Throw New MD5HashException($"There is already an identical invoice! - HistoryID [{oHistoryId}] - Case 1", pFile.Name)
Else Else
_logger.Info("ZuGFeRDFile already has been processed. Will be rejected.") _logger.Info("ZuGFeRDFile already has been processed. Will be rejected.")
Throw New MD5HashException($"There is already an identical invoice! - HistoryID [{oHistoryId}] - Case 2") Throw New MD5HashException($"There is already an identical invoice! - HistoryID [{oHistoryId}] - Case 2", pFile.Name)
End If End If
Return oMD5CheckSum Return oMD5CheckSum
End Function End Function
Private Function MoveAndRenameEmailToRejected(pArgs As WorkerArgs, pMessageId As String) As EmailData
_logger.Info("Moving Mail with MessageId [{0}] to Rejected folder", pMessageId)
_logger.Debug("Fetching Email Data")
Dim oEmailData = _email.GetEmailDataForMessageId(pMessageId)
_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 oDestination As String
Dim oRejectedDirectory As String = Path.Combine(pArgs.RejectedEmailDirectory, oDateSubDirectoryName)
' Create the destination directory if it does not exist
_logger.Debug("Creating destination directory [{0}]", oRejectedDirectory)
If Not Directory.Exists(oRejectedDirectory) Then
Try
Directory.CreateDirectory(oRejectedDirectory)
Catch ex As Exception
_logger.Error(ex)
End Try
End If
If oSource = String.Empty Then
_logger.Warn("Original Email for [{0}] could not be found. Exiting.", pMessageId)
Return New EmailData()
End If
' 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
If oEmailData Is Nothing Then
oDestination = _email.GetEmailPathWithSubjectAsName(oRejectedDirectory, pMessageId)
Else
oDestination = _email.GetEmailPathWithSubjectAsName(oRejectedDirectory, StringEx.ConvertTextToSlug(oEmailData.Subject))
End If
_logger.Debug("Destination for eml file is {0}", oDestination)
Dim oFinalFileName = _filesystem.GetVersionedFilename(oDestination)
_logger.Debug("Versioned filename for eml file is {0}", oFinalFileName)
If oEmailData Is Nothing Then
_logger.Warn("Could not get Email Data from firebird-database. File {0} will not be moved!", oSource)
Return New EmailData()
End If
'---------------------------
Try
_logger.Info("Moving email from {0} to {1}", oSource, oFinalFileName)
File.Move(oSource, oFinalFileName)
oEmailData.Attachment = oFinalFileName
Catch ex As Exception
_logger.Warn("File {0} could not be moved! Original Filename will be used!", oSource)
_logger.Error(ex)
oEmailData.Attachment = oSource
End Try
_logger.Info("Email [{0}] moved to rejected folder!", pMessageId)
Return oEmailData
End Function
Private Sub AddRejectedState(oMessageID As String, oTitle As String, oTitle1 As String, oComment As String, Transaction As SqlTransaction)
Try
'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("'", "''")}'"
_mssql.ExecuteNonQuery(oSQL, Transaction)
Catch ex As Exception
_logger.Error(ex)
End Try
End Sub
End Class End Class

View File

@@ -3,7 +3,7 @@ Imports DigitalData.Modules.Interfaces
Public Class WorkerArgs Public Class WorkerArgs
' Directory Parameters ' Directory Parameters
Public WatchDirectories As New List(Of String) Public WatchDirectory As String = Nothing
Public SuccessDirectory As String = Nothing Public SuccessDirectory As String = Nothing
Public ErrorDirectory As String = Nothing Public ErrorDirectory As String = Nothing
Public OriginalEmailDirectory As String = Nothing Public OriginalEmailDirectory As String = Nothing

View File

@@ -527,13 +527,13 @@ Public Class LogConfig
#Region "Log Targets" #Region "Log Targets"
Private Function GetJsonLogTarget(basePath As String) As FileTarget Private Function GetJsonLogTarget(basePath As String) As FileTarget
Dim oJsonLayout = New Layouts.JsonLayout Dim oJsonLayout = New Layouts.JsonLayout
oJsonLayout.Attributes.Add(New Layouts.JsonAttribute("level", "${level}")) oJsonLayout.Attributes.Add(New Layouts.JsonAttribute("Level", "${level}"))
oJsonLayout.Attributes.Add(New Layouts.JsonAttribute("message", "${message}")) oJsonLayout.Attributes.Add(New Layouts.JsonAttribute("Message", "${message}"))
oJsonLayout.Attributes.Add(New Layouts.JsonAttribute("date", "${shortdate}")) oJsonLayout.Attributes.Add(New Layouts.JsonAttribute("Time", "${date}"))
oJsonLayout.Attributes.Add(New Layouts.JsonAttribute("product", "${var:product}")) oJsonLayout.Attributes.Add(New Layouts.JsonAttribute("Product", "${var:product}"))
oJsonLayout.Attributes.Add(New Layouts.JsonAttribute("suffix", "${var:suffix}")) oJsonLayout.Attributes.Add(New Layouts.JsonAttribute("Suffix", "${var:suffix}"))
oJsonLayout.Attributes.Add(New Layouts.JsonAttribute("module", "${event-properties:item=ModuleName}")) oJsonLayout.Attributes.Add(New Layouts.JsonAttribute("Module", "${event-properties:item=ModuleName}"))
oJsonLayout.Attributes.Add(New Layouts.JsonAttribute("exception", "${exception:format=Message,StackTrace:innerFormat=Message:maxInnerExceptionLevel=3}")) oJsonLayout.Attributes.Add(New Layouts.JsonAttribute("Exception", "${exception:format=@,StackTrace:innerFormat=@:maxInnerExceptionLevel=3}"))
Dim jsonLog As New FileTarget() With { Dim jsonLog As New FileTarget() With {
.FileName = Path.Combine(basePath, FILE_NAME_FORMAT_JSON), .FileName = Path.Combine(basePath, FILE_NAME_FORMAT_JSON),

9
Logging/LogEntry.vb Normal file
View File

@@ -0,0 +1,9 @@
Public Class LogEntry
Public Property Level As String
Public Property Message As String
Public Property Product As String
Public Property Time As Date
Public Property Suffix As String
Public Property [Module] As String
Public Property Exception As String
End Class

View File

@@ -74,6 +74,7 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Compile Include="LogConfig.vb" /> <Compile Include="LogConfig.vb" />
<Compile Include="LogEntry.vb" />
<Compile Include="Logger.vb" /> <Compile Include="Logger.vb" />
<Compile Include="LogOptions.vb" /> <Compile Include="LogOptions.vb" />
<Compile Include="My Project\AssemblyInfo.vb" /> <Compile Include="My Project\AssemblyInfo.vb" />