Compare commits
9 Commits
86d61e720f
...
70bb33f823
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
70bb33f823 | ||
|
|
e63d1ea557 | ||
|
|
2b80e8fa97 | ||
|
|
9cab65f941 | ||
|
|
4c8bdb27fd | ||
|
|
b604ffcba2 | ||
|
|
6ef1e97deb | ||
|
|
60bcf26379 | ||
|
|
a4a3dc4536 |
@@ -77,10 +77,12 @@
|
||||
<Import Include="System.Threading.Tasks" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="BaseClass.vb" />
|
||||
<Compile Include="BaseUtils.vb" />
|
||||
<Compile Include="Base\BaseClass.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="ECM\ECM.vb" />
|
||||
<Compile Include="MimeEx.vb" />
|
||||
<Compile Include="WindowsEx.vb" />
|
||||
<Compile Include="ModuleExtensions.vb" />
|
||||
@@ -88,9 +90,6 @@
|
||||
<Compile Include="NativeMethods.vb" />
|
||||
<Compile Include="ObjectEx.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="My Project\AssemblyInfo.vb" />
|
||||
<Compile Include="My Project\Application.Designer.vb">
|
||||
@@ -140,5 +139,8 @@
|
||||
<Name>Logging</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Folder Include="Static\" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.VisualBasic.targets" />
|
||||
</Project>
|
||||
@@ -1,7 +0,0 @@
|
||||
Public Class ECM
|
||||
Public Enum Product
|
||||
ProcessManager
|
||||
GlobalIndexer
|
||||
ClipboardWatcher
|
||||
End Enum
|
||||
End Class
|
||||
70
Base/Encryption/Compression.vb
Normal file
70
Base/Encryption/Compression.vb
Normal 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
|
||||
148
Base/Encryption/Encryption.vb
Normal file
148
Base/Encryption/Encryption.vb
Normal 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
|
||||
85
Base/Encryption/EncryptionLegacy.vb
Normal file
85
Base/Encryption/EncryptionLegacy.vb
Normal 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
|
||||
|
||||
@@ -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
|
||||
@@ -1,11 +0,0 @@
|
||||
|
||||
Namespace IDB
|
||||
Public Class Database
|
||||
Public Enum NamedDatabase
|
||||
ECM
|
||||
IDB
|
||||
End Enum
|
||||
End Class
|
||||
|
||||
End Namespace
|
||||
|
||||
@@ -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
|
||||
@@ -13,7 +13,7 @@ Imports System.Runtime.InteropServices
|
||||
<Assembly: AssemblyCompany("")>
|
||||
<Assembly: AssemblyProduct("Base")>
|
||||
<Assembly: AssemblyCopyright("Copyright © 2023")>
|
||||
<Assembly: AssemblyTrademark("1.3.5.0")>
|
||||
<Assembly: AssemblyTrademark("1.3.6.0")>
|
||||
|
||||
<Assembly: ComVisible(False)>
|
||||
|
||||
@@ -31,5 +31,5 @@ Imports System.Runtime.InteropServices
|
||||
' indem Sie "*" wie unten gezeigt eingeben:
|
||||
' <Assembly: AssemblyVersion("1.0.*")>
|
||||
|
||||
<Assembly: AssemblyVersion("1.3.5.0")>
|
||||
<Assembly: AssemblyFileVersion("1.3.5.0")>
|
||||
<Assembly: AssemblyVersion("1.3.6.0")>
|
||||
<Assembly: AssemblyFileVersion("1.3.6.0")>
|
||||
|
||||
@@ -12,7 +12,7 @@ Public Class StringEx
|
||||
''' And consecutive hyphens.
|
||||
''' </summary>
|
||||
''' <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 oWasHyphen As Boolean = True
|
||||
|
||||
@@ -27,7 +27,7 @@ Public Class StringEx
|
||||
oWasHyphen = True
|
||||
|
||||
ElseIf Char.IsWhiteSpace(oChar) AndAlso Not oWasHyphen Then
|
||||
oBuilder.Append("-"c)
|
||||
oBuilder.Append("_"c)
|
||||
oWasHyphen = True
|
||||
End If
|
||||
Next
|
||||
|
||||
@@ -9,7 +9,7 @@ Public Class Exceptions
|
||||
Public ReadOnly File As FileInfo
|
||||
|
||||
Public Sub New(File As FileInfo)
|
||||
MyBase.New()
|
||||
MyBase.New($"Missing values in [{File.Name}]")
|
||||
|
||||
Me.File = File
|
||||
End Sub
|
||||
@@ -73,8 +73,11 @@ Public Class Exceptions
|
||||
Public Class MD5HashException
|
||||
Inherits ApplicationException
|
||||
|
||||
Public Sub New(pInfo As String)
|
||||
MyBase.New(pInfo)
|
||||
Public ReadOnly FileName As String
|
||||
|
||||
Public Sub New(pMessage As String, pFileName As String)
|
||||
MyBase.New(pMessage)
|
||||
FileName = pFileName
|
||||
End Sub
|
||||
End Class
|
||||
End Class
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
Public Class EmailData
|
||||
Public Attachment As String = ""
|
||||
Public Subject As String
|
||||
Public From As String
|
||||
Public Subject As String = ""
|
||||
Public From As String = ""
|
||||
End Class
|
||||
@@ -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_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 = "
|
||||
<p>Die von Ihnen gesendete Rechnung hat die ZUGFeRD Validierung nicht bestanden.</p>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
Imports System.Data.SqlClient
|
||||
Imports System.ServiceModel.Channels
|
||||
Imports DigitalData.Modules.Database
|
||||
Imports DigitalData.Modules.Logging
|
||||
Imports Microsoft.VisualBasic.FileIO
|
||||
@@ -15,42 +16,30 @@ Namespace ZUGFeRD
|
||||
_mssql = MSSQL
|
||||
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
|
||||
_logger.Info("Creating History Entry for MessageId [{0}] with comment [{1}]", MessageId, Message)
|
||||
Dim oSQL = $"INSERT INTO TBEMLP_HISTORY (COMMENT, MD5HASH, EMAIL_MSGID) VALUES ('{Message}', '{MD5Checksum}', '{MessageId}')"
|
||||
|
||||
Using oConnection = _mssql.GetConnection()
|
||||
' 09.07.2021: This can't be in the transaction since the history
|
||||
' Entry needs to be accessed by MoveAndRenameEmailToRejected shortly after
|
||||
_mssql.ExecuteNonQueryWithConnectionObject(oSQL, oConnection)
|
||||
|
||||
If Message.Contains("REJECTED") Then
|
||||
oSQL = $"UPDATE TBEMLP_HISTORY SET STATUS = 'REJECTED', COMMENT = '{Message}', CUST_REJECTED = 1,CUST_REJECTED_WHEN = GETDATE() WHERE EMAIL_MSGID = '{MessageId}'"
|
||||
_mssql.ExecuteNonQueryWithConnectionObject(oSQL, oConnection)
|
||||
End If
|
||||
|
||||
_logger.Debug("History Entry created!")
|
||||
End Using
|
||||
|
||||
Return True
|
||||
Catch ex As Exception
|
||||
_logger.Warn("History Entry count not be created for message id [{0}] and md5 [{1}]", MessageId, MD5Checksum)
|
||||
_logger.Error(ex)
|
||||
|
||||
Return False
|
||||
End Try
|
||||
End Function
|
||||
|
||||
Public Function Update_HistoryEntry(MessageId As String, MD5Checksum As String, Message As String, Transaction As SqlTransaction) As Boolean
|
||||
Try
|
||||
_logger.Info("Updating History Entry for MessageId [{0}] with comment [{1}]", MessageId, Message)
|
||||
_logger.Info("Updating History Entry for MessageId [{0}] with comment [{1}]", pMessageId, pMessage)
|
||||
' Only look for history entry by MessageId since the MD5 Hash might not be generated yet
|
||||
|
||||
Using oConnection = _mssql.GetConnection()
|
||||
' 09.07.2021: This can't be in the transaction since the history
|
||||
' Entry needs to be accessed by MoveAndRenameEmailToRejected shortly after
|
||||
Dim oSQL = $"UPDATE TBEMLP_HISTORY SET COMMENT = '{Message}' WHERE EMAIL_MSGID = '{MessageId}'"
|
||||
|
||||
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)
|
||||
End Using
|
||||
|
||||
@@ -58,7 +47,7 @@ Namespace ZUGFeRD
|
||||
|
||||
Return True
|
||||
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)
|
||||
|
||||
Return False
|
||||
|
||||
@@ -37,12 +37,19 @@ Public Class ImportZUGFeRDFiles
|
||||
Private ReadOnly _email As ZUGFeRD.EmailFunctions
|
||||
Private ReadOnly _file As ZUGFeRD.FileFunctions
|
||||
Private ReadOnly _history As ZUGFeRD.HistoryFunctions
|
||||
Private ReadOnly _embeds As PDFEmbeds
|
||||
|
||||
Private ReadOnly _gdpictureLicenseKey As String
|
||||
|
||||
Private _zugferd As ZUGFeRDInterface
|
||||
Private _EmailOutAccountId As Integer
|
||||
|
||||
Private Class ProcessFileResult
|
||||
Public ZugferdFileCount As Integer
|
||||
Public MD5Hash As String = Nothing
|
||||
|
||||
End Class
|
||||
|
||||
Private Class DatabaseConnections
|
||||
Public Property SQLServerConnection As SqlConnection
|
||||
Public Property SQLServerTransaction As SqlTransaction
|
||||
@@ -56,6 +63,7 @@ Public Class ImportZUGFeRDFiles
|
||||
_email = New ZUGFeRD.EmailFunctions(LogConfig, _mssql)
|
||||
_file = New ZUGFeRD.FileFunctions(LogConfig, _mssql)
|
||||
_history = New ZUGFeRD.HistoryFunctions(LogConfig, _mssql)
|
||||
_embeds = New PDFEmbeds(LogConfig)
|
||||
|
||||
_logger.Debug("Registering GDPicture License")
|
||||
If _mssql IsNot Nothing Then
|
||||
@@ -67,82 +75,6 @@ Public Class ImportZUGFeRDFiles
|
||||
End If
|
||||
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
|
||||
Dim oArgs As WorkerArgs = Arguments
|
||||
Dim oPropertyExtractor = New PropertyValues(_logConfig)
|
||||
@@ -159,27 +91,30 @@ Public Class ImportZUGFeRDFiles
|
||||
_logger.Debug("Starting Job {0}", [GetType].Name)
|
||||
|
||||
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)
|
||||
|
||||
_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
|
||||
Dim oFiles As List(Of FileInfo) = oDirInfo.
|
||||
GetFiles().
|
||||
Where(Function(f) Not f.Name.EndsWith(".lock")).
|
||||
ToList()
|
||||
Dim oFileCount = oFiles.Count
|
||||
Dim oCurrentFileCount = 0
|
||||
|
||||
If oFileCount = 0 Then
|
||||
_logger.Debug("No files to process.")
|
||||
Continue For
|
||||
Else
|
||||
_logger.Info("Found {0} files", oFileCount)
|
||||
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)
|
||||
|
||||
@@ -223,6 +158,9 @@ Public Class ImportZUGFeRDFiles
|
||||
|
||||
_logger.Info("Start processing file group {0}", oMessageId)
|
||||
|
||||
' TODO: Use this refactored function
|
||||
' ProcessFileGroup(oMessageId, oFileGroupFiles, oConnections, oArgs)
|
||||
|
||||
Try
|
||||
For Each oFile In oFileGroupFiles
|
||||
' 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
|
||||
' Clear missing properties for the new file
|
||||
oMissingProperties = New List(Of String)
|
||||
oCurrentFileCount += 1
|
||||
|
||||
' Only pdf files are allowed from here on
|
||||
If Not oFile.Name.ToUpper.EndsWith(".PDF") Then
|
||||
@@ -307,7 +244,7 @@ Public Class ImportZUGFeRDFiles
|
||||
End If
|
||||
|
||||
' 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:
|
||||
' - a List of valid properties
|
||||
@@ -369,9 +306,9 @@ Public Class ImportZUGFeRDFiles
|
||||
'If no errors occurred...
|
||||
'Log the History
|
||||
If oMD5CheckSum <> String.Empty Then
|
||||
_history.Create_HistoryEntry(oMessageId, oMD5CheckSum, "SUCCESS", oSQLTransaction)
|
||||
_history.Update_HistoryEntry(oMessageId, oMD5CheckSum, "SUCCESS")
|
||||
Else
|
||||
_history.Create_HistoryEntry(oMessageId, String.Empty, "SUCCESS (with empty MD5Hash)", oSQLTransaction)
|
||||
_history.Update_HistoryEntry(oMessageId, String.Empty, "SUCCESS (with empty MD5Hash)")
|
||||
End If
|
||||
|
||||
oIsSuccess = True
|
||||
@@ -382,7 +319,7 @@ Public Class ImportZUGFeRDFiles
|
||||
|
||||
Dim oErrors = ex.ValidationErrors
|
||||
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 = ""
|
||||
For Each oError In oErrors
|
||||
@@ -400,9 +337,9 @@ Public Class ImportZUGFeRDFiles
|
||||
' 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, 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)
|
||||
_email.AddToEmailQueueMSSQL(oMessageId, oBody, oEmailData, "MD5HashException", _EmailOutAccountId, oArgs.NamePortal)
|
||||
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.
|
||||
' 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 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.
|
||||
' 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 oBody = String.Format(EmailStrings.EMAIL_INVALID_DOCUMENT, oEmailData.Subject)
|
||||
@@ -436,7 +373,7 @@ Public Class ImportZUGFeRDFiles
|
||||
Catch ex As TooMuchFerdsException
|
||||
_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 oBody = String.Format(EmailStrings.EMAIL_TOO_MUCH_FERDS, oEmailData.Subject)
|
||||
@@ -447,7 +384,7 @@ Public Class ImportZUGFeRDFiles
|
||||
Catch ex As NoFerdsException
|
||||
_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 oBody = String.Format(EmailStrings.EMAIL_NO_FERDS, oEmailData.Subject)
|
||||
@@ -463,7 +400,7 @@ Public Class ImportZUGFeRDFiles
|
||||
oMessage &= $"- {prop}"
|
||||
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 oEmailData = MoveAndRenameEmailToRejected(oArgs, oMessageId)
|
||||
@@ -473,7 +410,7 @@ Public Class ImportZUGFeRDFiles
|
||||
Catch ex As FileSizeLimitReachedException
|
||||
_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)
|
||||
|
||||
@@ -576,8 +513,7 @@ Public Class ImportZUGFeRDFiles
|
||||
_logger.Warn("Database Connections were not closed successfully.")
|
||||
End Try
|
||||
End Try
|
||||
Next
|
||||
End If
|
||||
|
||||
Next
|
||||
|
||||
_logger.Debug("Finishing Job {0}", Me.GetType.Name)
|
||||
@@ -587,6 +523,520 @@ Public Class ImportZUGFeRDFiles
|
||||
End Try
|
||||
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)
|
||||
Dim oDelSQL = $"DELETE FROM TBEDMI_ITEM_VALUE where REFERENCE_GUID = '{pMessageId}'"
|
||||
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>
|
||||
''' <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>
|
||||
Private Function GenerateAndCheck_MD5Sum(pFilePath As String, pMessageId As String, pIgnoreRejectionStatus As Boolean) As String
|
||||
Dim oMD5CheckSum = CreateMD5(pFilePath)
|
||||
Private Function GenerateAndCheck_MD5Sum(pFile As FileInfo, pMessageId As String, pIgnoreRejectionStatus As Boolean) As String
|
||||
Dim oMD5CheckSum = CreateMD5(pFile.FullName)
|
||||
|
||||
' Exit if MD5 could not be created
|
||||
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
|
||||
End If
|
||||
|
||||
@@ -668,13 +1118,13 @@ Public Class ImportZUGFeRDFiles
|
||||
|
||||
' If History entries could not be fetched, just return the MD5 Checksum
|
||||
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
|
||||
End If
|
||||
|
||||
' If Checksum does not exist in History entries, just return the MD5 Checksum
|
||||
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
|
||||
End If
|
||||
|
||||
@@ -711,12 +1161,88 @@ Public Class ImportZUGFeRDFiles
|
||||
_logger.Info("ZuGFeRDFile already has been processed, but Rejection Status will be ignored!")
|
||||
ElseIf oRejected = False Then
|
||||
_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
|
||||
_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
|
||||
|
||||
Return oMD5CheckSum
|
||||
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
|
||||
|
||||
@@ -3,7 +3,7 @@ Imports DigitalData.Modules.Interfaces
|
||||
|
||||
Public Class WorkerArgs
|
||||
' Directory Parameters
|
||||
Public WatchDirectories As New List(Of String)
|
||||
Public WatchDirectory As String = Nothing
|
||||
Public SuccessDirectory As String = Nothing
|
||||
Public ErrorDirectory As String = Nothing
|
||||
Public OriginalEmailDirectory As String = Nothing
|
||||
|
||||
@@ -527,13 +527,13 @@ Public Class LogConfig
|
||||
#Region "Log Targets"
|
||||
Private Function GetJsonLogTarget(basePath As String) As FileTarget
|
||||
Dim oJsonLayout = New Layouts.JsonLayout
|
||||
oJsonLayout.Attributes.Add(New Layouts.JsonAttribute("level", "${level}"))
|
||||
oJsonLayout.Attributes.Add(New Layouts.JsonAttribute("message", "${message}"))
|
||||
oJsonLayout.Attributes.Add(New Layouts.JsonAttribute("date", "${shortdate}"))
|
||||
oJsonLayout.Attributes.Add(New Layouts.JsonAttribute("product", "${var:product}"))
|
||||
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("exception", "${exception:format=Message,StackTrace:innerFormat=Message:maxInnerExceptionLevel=3}"))
|
||||
oJsonLayout.Attributes.Add(New Layouts.JsonAttribute("Level", "${level}"))
|
||||
oJsonLayout.Attributes.Add(New Layouts.JsonAttribute("Message", "${message}"))
|
||||
oJsonLayout.Attributes.Add(New Layouts.JsonAttribute("Time", "${date}"))
|
||||
oJsonLayout.Attributes.Add(New Layouts.JsonAttribute("Product", "${var:product}"))
|
||||
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("Exception", "${exception:format=@,StackTrace:innerFormat=@:maxInnerExceptionLevel=3}"))
|
||||
|
||||
Dim jsonLog As New FileTarget() With {
|
||||
.FileName = Path.Combine(basePath, FILE_NAME_FORMAT_JSON),
|
||||
|
||||
9
Logging/LogEntry.vb
Normal file
9
Logging/LogEntry.vb
Normal 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
|
||||
@@ -74,6 +74,7 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="LogConfig.vb" />
|
||||
<Compile Include="LogEntry.vb" />
|
||||
<Compile Include="Logger.vb" />
|
||||
<Compile Include="LogOptions.vb" />
|
||||
<Compile Include="My Project\AssemblyInfo.vb" />
|
||||
|
||||
Reference in New Issue
Block a user