From 3d3a491744a2e65b06f8fdf1badf5a0293d576db Mon Sep 17 00:00:00 2001
From: Jonathan Jenne
Date: Fri, 20 Mar 2020 13:47:36 +0100
Subject: [PATCH] big refactor, move most zugferd processing into
Modules.Interfaces
---
GUIs.Test.ZUGFeRDTest/Form1.vb | 4 +-
Modules.Interfaces/ZUGFeRDInterface.vb | 72 ++++-
.../ZUGFeRDInterface/PDFAttachments.vb | 67 ++---
.../ZUGFeRDInterface/PropertyValues.vb | 4 +-
Modules.Jobs/EDMI/ZUGFeRD/EmailFunctions.vb | 197 +++++++++++++
Modules.Jobs/EDMI/ZUGFeRD/EmailStrings.vb | 18 ++
.../EDMI/ZUGFeRD/ImportZUGFeRDFiles.vb | 275 +++---------------
Modules.Jobs/Jobs.vbproj | 2 +
8 files changed, 355 insertions(+), 284 deletions(-)
create mode 100644 Modules.Jobs/EDMI/ZUGFeRD/EmailFunctions.vb
create mode 100644 Modules.Jobs/EDMI/ZUGFeRD/EmailStrings.vb
diff --git a/GUIs.Test.ZUGFeRDTest/Form1.vb b/GUIs.Test.ZUGFeRDTest/Form1.vb
index 0a680b35..fb8d9661 100644
--- a/GUIs.Test.ZUGFeRDTest/Form1.vb
+++ b/GUIs.Test.ZUGFeRDTest/Form1.vb
@@ -25,7 +25,7 @@ Public Class Form1
_firebird = New Firebird(_logConfig, My.Settings.FB_DATASOURCE, My.Settings.FB_DATABASE, My.Settings.FB_USER, My.Settings.FB_PASS)
_mssql = New MSSQLServer(_logConfig, My.Settings.MSSQL_CONNECTIONSTRING)
- _zugferd = New ZUGFeRDInterface(_logConfig)
+ _zugferd = New ZUGFeRDInterface(_logConfig, "")
End Sub
Private Function LoadFolderConfig(args As WorkerArgs)
@@ -164,7 +164,7 @@ Public Class Form1
End Sub
Private Sub Button7_Click(sender As Object, e As EventArgs) Handles Button7.Click
- Dim oExtractor = New Jobs.PDFAttachments(_logConfig)
+ Dim oExtractor = New PDFAttachments(_logConfig)
Dim oResult = OpenFileDialog1.ShowDialog()
If oResult = DialogResult.OK Then
diff --git a/Modules.Interfaces/ZUGFeRDInterface.vb b/Modules.Interfaces/ZUGFeRDInterface.vb
index 11ed3baf..d324fa15 100644
--- a/Modules.Interfaces/ZUGFeRDInterface.vb
+++ b/Modules.Interfaces/ZUGFeRDInterface.vb
@@ -1,9 +1,11 @@
-Imports System.Xml
+Imports System.IO
+Imports System.Xml
Imports System.Xml.Serialization
Imports System.Xml.XPath
Imports System.Xml.Xsl
Imports DigitalData.Modules.Interfaces.Exceptions
Imports DigitalData.Modules.Logging
+Imports GdPicture14
Public Class ZUGFeRDInterface
Private _logConfig As LogConfig
@@ -21,13 +23,23 @@ Public Class ZUGFeRDInterface
Public ReadOnly Property FileGroup As FileGroups
Public ReadOnly Property PropertyValues As PropertyValues
- Public Sub New(LogConfig As LogConfig)
+ Public Sub New(LogConfig As LogConfig, GDPictureKey As String)
_logConfig = LogConfig
_logger = _logConfig.GetLogger()
+
FileGroup = New FileGroups(_logConfig)
PropertyValues = New PropertyValues(_logConfig)
+
+ Try
+ Dim oLicenseManager As New LicenseManager
+ oLicenseManager.RegisterKEY(GDPictureKey)
+ Catch ex As Exception
+ _logger.Warn("GDPicture License could not be registered!")
+ _logger.Error(ex)
+ End Try
End Sub
+
'''
''' Validates a ZUGFeRD File and extracts the XML Document from it
'''
@@ -35,7 +47,6 @@ Public Class ZUGFeRDInterface
'''
'''
Public Function ExtractZUGFeRDFile(Path As String) As CrossIndustryDocumentType
- Dim oException As New Exception
Dim oXmlDocument = ValidateZUGFeRDFile(Path)
If IsNothing(oXmlDocument) Then
@@ -45,6 +56,15 @@ Public Class ZUGFeRDInterface
Return SerializeZUGFeRDDocument(oXmlDocument)
End Function
+ Public Function ExtractZUGFeRDFileWithGDPicture(Path As String) As CrossIndustryDocumentType
+ Dim oXmlDocument = ValidateZUGFeRDFileWithGDPicture(Path)
+
+ If IsNothing(oXmlDocument) Then
+ Throw New ZUGFeRDExecption(ErrorType.NoZugferd, "Datei ist keine ZUGFeRD Datei.")
+ End If
+
+ Return SerializeZUGFeRDDocument(oXmlDocument)
+ End Function
Public Function ValidateZUGFeRDFile(Path As String) As XPathDocument
Dim oProcessOutput, oProcessError As String
@@ -90,6 +110,52 @@ Public Class ZUGFeRDInterface
Return oXmlDocument
End Function
+ Public Function ValidateZUGFeRDFileWithGDPicture(Path As String) As XPathDocument
+ Dim oAttachmentExtractor = New PDFAttachments(_logConfig)
+ Dim oAllowedExtensions = New List(Of String) From {"xml"}
+ Dim oXmlDocument As XPathDocument
+
+ Try
+ Dim oResults = oAttachmentExtractor.Extract(Path, oAllowedExtensions)
+
+ If oResults Is Nothing Then
+ Throw New ZUGFeRDExecption(ErrorType.NoZugferd, "Datei ist keine ZUGFeRD Datei.")
+ End If
+
+ If oResults.Count = 0 Then
+ Throw New ZUGFeRDExecption(ErrorType.NoZugferd, "Datei ist keine ZUGFeRD Datei.")
+ End If
+
+ Dim oFound As Boolean = False
+ Dim oFoundResult As PDFAttachments.AttachmentResult = Nothing
+
+ For Each oResult In oResults
+ If oResult.FileName = PDFAttachments.ZUGFERD_XML_FILENAME Then
+ oFound = True
+ oFoundResult = oResult
+ End If
+ Next
+
+ If Not oFound Then
+ Throw New ZUGFeRDExecption(ErrorType.NoZugferd, "Datei ist keine ZUGFeRD Datei.")
+ End If
+
+ Try
+ Using oStream As New MemoryStream(oFoundResult.FileContents)
+ oXmlDocument = New XPathDocument(oStream)
+ End Using
+
+ Return oXmlDocument
+ Catch ex As Exception
+ _logger.Error(ex)
+ Throw ex
+ End Try
+ Catch ex As Exception
+ _logger.Error(ex)
+ Throw ex
+ End Try
+ End Function
+
Public Function SerializeZUGFeRDDocument(Document As XPathDocument) As CrossIndustryDocumentType
Try
Dim oNavigator As XPathNavigator = Document.CreateNavigator()
diff --git a/Modules.Interfaces/ZUGFeRDInterface/PDFAttachments.vb b/Modules.Interfaces/ZUGFeRDInterface/PDFAttachments.vb
index 3f170017..bf9d7c61 100644
--- a/Modules.Interfaces/ZUGFeRDInterface/PDFAttachments.vb
+++ b/Modules.Interfaces/ZUGFeRDInterface/PDFAttachments.vb
@@ -4,9 +4,9 @@ Imports DigitalData.Modules.Logging
Imports GdPicture14
Public Class PDFAttachments
- Private Logger As Logger
+ Private ReadOnly Logger As Logger
- Private Const ZUGFERD_XML_FILENAME = "ZUGFeRD-invoice.xml"
+ Public Const ZUGFERD_XML_FILENAME = "ZUGFeRD-invoice.xml"
Public Class AttachmentResult
Public FileName As String
@@ -17,61 +17,50 @@ Public Class PDFAttachments
Logger = LogConfig.GetLogger
End Sub
+ '''
+ ''' Extracts all embedded files from a PDF file.
+ ''' Note: This does NOT filter out `ZUGFeRD-invoice.xml` anymore to allow for a more generic use.
+ '''
+ '''
+ '''
+ '''
Public Function Extract(FileName As String, AllowedExtensions As List(Of String)) As List(Of AttachmentResult)
Dim oResults As New List(Of AttachmentResult)
- Dim oExtensions = AllowedExtensions.ConvertAll(Of String)(New Converter(Of String, String)(Function(ext) ext.ToUpper))
+ Dim oExtensions = AllowedExtensions.ConvertAll(New Converter(Of String, String)(Function(ext) ext.ToUpper))
Try
Using oGDPicturePDF As New GdPicturePDF()
If oGDPicturePDF.LoadFromFile(FileName, False) = GdPictureStatus.OK Then
Dim oEmbeddedFileCount As Integer = oGDPicturePDF.GetEmbeddedFileCount()
If oGDPicturePDF.GetStat() = GdPictureStatus.OK Then
- If oEmbeddedFileCount > 1 Then
+ If oEmbeddedFileCount > 0 Then
For index = 0 To oEmbeddedFileCount - 1
Dim oFileName As String = oGDPicturePDF.GetEmbeddedFileName(index)
If oGDPicturePDF.GetStat() = GdPictureStatus.OK Then
Dim oExtension = New FileInfo(oFileName).Extension.ToUpper.Substring(1)
- If oFileName.ToUpper <> ZUGFERD_XML_FILENAME.ToUpper Then
- If oExtensions.Contains(oExtension) Then
- Dim FileSize As Integer = oGDPicturePDF.GetEmbeddedFileSize(index)
+ If oExtensions.Contains(oExtension) Then
+ Dim FileSize As Integer = oGDPicturePDF.GetEmbeddedFileSize(index)
- If oGDPicturePDF.GetStat() = GdPictureStatus.OK Then
- Dim oFileData As Byte() = New Byte(FileSize) {}
- Dim status As GdPictureStatus = oGDPicturePDF.ExtractEmbeddedFile(index, oFileData)
+ If oGDPicturePDF.GetStat() = GdPictureStatus.OK Then
+ Dim oFileData As Byte() = New Byte(FileSize) {}
+ Dim status As GdPictureStatus = oGDPicturePDF.ExtractEmbeddedFile(index, oFileData)
- If status = GdPictureStatus.OK Then
- oResults.Add(New AttachmentResult() With {
- .FileContents = oFileData,
- .FileName = oFileName
- })
- Else
- Logger.Error("The embedded file [{0}] has failed to extract. Status: {1}", oFileName, oGDPicturePDF.GetStat().ToString())
- Continue For
- End If
-
- 'If status = GdPictureStatus.OK Then
- ' Dim oVersionedName = Filesystem.GetVersionedFilename(oFileName)
- ' Dim oTempName As String = Path.Combine(Path.GetTempPath(), oVersionedName)
- ' Using oFileStream As New FileStream(oTempName, FileMode.OpenOrCreate)
- ' oFileStream.Write(oFileData, 0, oFileData.Length)
- ' End Using
-
- ' oResults.Add(New FileInfo(oTempName))
- 'Else
- ' Logger.Error("The embedded file [{0}] has failed to extract. Status: {1}", oFileName, oGDPicturePDF.GetStat().ToString())
- ' Continue For
- 'End If
+ If status = GdPictureStatus.OK Then
+ oResults.Add(New AttachmentResult() With {
+ .FileContents = oFileData,
+ .FileName = oFileName
+ })
Else
- Logger.Error("An error occurred getting the file size for [{0}]. Status: {1}", oFileName, oGDPicturePDF.GetStat().ToString())
+ Logger.Error("The embedded file [{0}] has failed to extract. Status: {1}", oFileName, oGDPicturePDF.GetStat().ToString())
Continue For
End If
Else
- Logger.Warn("File [{0}] was skipped because its extension [{1}] is not allowed.", oFileName, oExtension)
+ Logger.Error("An error occurred getting the file size for [{0}]. Status: {1}", oFileName, oGDPicturePDF.GetStat().ToString())
Continue For
End If
Else
- Logger.Debug("File [{0}] was skipped because its name indicates the invoice data file.", oFileName)
+ Logger.Warn("File [{0}] was skipped because its extension [{1}] is not allowed.", oFileName, oExtension)
Continue For
End If
Else
@@ -81,12 +70,12 @@ Public Class PDFAttachments
Next
End If
Else
- Logger.Error("An error occurred getting the number of embedded files. Status: {0}", oGDPicturePDF.GetStat().ToString())
- Return Nothing
+ Dim oMessage = String.Format("An error occurred getting the number of embedded files. Status: {0}", oGDPicturePDF.GetStat().ToString())
+ Throw New ApplicationException(oMessage)
End If
Else
- Logger.Error("The file [{0}] can't be loaded.", FileName)
- Return Nothing
+ Dim oMessage = String.Format("The file [{0}] can't be loaded. Status: [{1}]", FileName, oGDPicturePDF.GetStat().ToString())
+ Throw New ApplicationException(oMessage)
End If
End Using
diff --git a/Modules.Interfaces/ZUGFeRDInterface/PropertyValues.vb b/Modules.Interfaces/ZUGFeRDInterface/PropertyValues.vb
index c56aa5f0..db526ffc 100644
--- a/Modules.Interfaces/ZUGFeRDInterface/PropertyValues.vb
+++ b/Modules.Interfaces/ZUGFeRDInterface/PropertyValues.vb
@@ -16,7 +16,7 @@ Public Class PropertyValues
Public Class CheckPropertyValuesResult
Public MissingProperties As New List(Of String)
- Public ValidProperties As List(Of ValidProperty)
+ Public ValidProperties As New List(Of ValidProperty)
End Class
Public Class ValidProperty
@@ -36,7 +36,7 @@ Public Class PropertyValues
' PropertyMap items with `IsGrouped = False` are handled normally
Dim oDefaultProperties As Dictionary(Of String, XmlItemProperty) = PropertyMap.
- Where(Function(Item) Item.Value.IsGrouped = True).
+ Where(Function(Item) Item.Value.IsGrouped = False).
ToDictionary(Function(Item) Item.Key,
Function(Item) Item.Value)
diff --git a/Modules.Jobs/EDMI/ZUGFeRD/EmailFunctions.vb b/Modules.Jobs/EDMI/ZUGFeRD/EmailFunctions.vb
new file mode 100644
index 00000000..45c844aa
--- /dev/null
+++ b/Modules.Jobs/EDMI/ZUGFeRD/EmailFunctions.vb
@@ -0,0 +1,197 @@
+Imports DigitalData.Modules.Logging
+Imports DigitalData.Modules.Database
+Imports System.Data
+Imports System.IO
+
+Public Class EmailFunctions
+ Private ReadOnly _logConfig As LogConfig
+ Private ReadOnly _logger As Logger
+ Private ReadOnly _mssql As MSSQLServer
+ Private ReadOnly _firebird As Firebird
+
+ Public Sub New(LogConfig As LogConfig, MSSQL As MSSQLServer, Firebird As Firebird)
+ _logConfig = LogConfig
+ _logger = _logConfig.GetLogger()
+ _mssql = MSSQL
+ _firebird = Firebird
+ End Sub
+
+ Public Sub AddToEmailQueueFB(MessageId As String, BodyText As String, EmailData As EmailData)
+ If EmailData Is Nothing Then
+ _logger.Warn("EmailData is empty. Email will not be sent!")
+ Exit Sub
+ End If
+
+ Try
+ Dim oJobId = RandomValue(1, 10000)
+ Dim oReference = MessageId
+ Dim oEmailTo = ""
+ Dim oSubject = EmailStrings.EMAIL_SUBJECT
+ Dim oAccountId = 1
+ Dim oCreatedWho = "ZUGFeRD Service"
+ Dim oFinalBodyText = String.Format(EmailStrings.EMAIL_WRAPPING_TEXT, BodyText)
+
+ Dim oEmailAddress = EmailData.From
+ Dim oAttachment = EmailData.Attachment
+
+ If IsNothing(oEmailAddress) OrElse String.IsNullOrWhiteSpace(oEmailAddress) Then
+ _logger.Warn("Could not find email-address for MessageId {0}", MessageId)
+ oEmailTo = String.Empty
+ Else
+ oEmailTo = oEmailAddress
+ End If
+
+ _logger.Debug("Generated Email:")
+ _logger.Debug("To: {0}", oEmailTo)
+ _logger.Debug("Subject: {0}", oSubject)
+ _logger.Debug("Body {0}", oFinalBodyText)
+ Dim osql = $"select * from TBEDM_EMAIL_QUEUE where REFERENCE1 = '{oReference} and EMAIL_TO = ''{oEmailTo}' and EMAIL_SUBJ = '{oSubject}'"
+
+ Dim oDTResult As DataTable = _firebird.GetDatatable(osql)
+
+ If oDTResult.Rows.Count = 0 Then
+ Dim oSQLInsert = $"INSERT INTO TBEDM_EMAIL_QUEUE "
+ oSQLInsert &= "(JOB_ID, REFERENCE1, EMAIL_ACCOUNT_ID, EMAIL_TO, EMAIL_SUBJ, EMAIL_BODY, CREATEDWHO, EMAIL_ATTMT1) VALUES "
+ oSQLInsert &= $"({oJobId}, '{oReference}', {oAccountId}, '{oEmailTo}', '{oSubject}', '{oFinalBodyText.Replace("'", "''")}', '{oCreatedWho}', '{oAttachment}')"
+ _firebird.ExecuteNonQuery(oSQLInsert)
+ _logger.Debug("Email Queue updated for MessageId {0}.", MessageId, oEmailTo)
+ Else
+ _logger.Debug("Email has already been sent!!")
+ End If
+ Catch ex As Exception
+ _logger.Error(ex)
+ End Try
+ End Sub
+ Public Sub AddToEmailQueueMSSQL(MessageId As String, BodyText As String, pEmailData As EmailData, SourceProcedure As String)
+ If pEmailData Is Nothing Then
+ _logger.Warn("EmailData is empty. Email will not be sent!")
+ Exit Sub
+ End If
+
+ Try
+ Dim oJobId = RandomValue(1, 10000)
+ Dim oReference = MessageId
+ Dim oEmailTo = ""
+ Dim oSubject = EmailStrings.EMAIL_SUBJECT
+ Dim oAccountId = 1
+ Dim oCreatedWho = "ZUGFeRD Service"
+ Dim oFinalBodyText = String.Format(EmailStrings.EMAIL_WRAPPING_TEXT, BodyText)
+
+ Dim oEmailAddress = pEmailData.From
+ Dim oAttachment = pEmailData.Attachment
+ If oAttachment <> String.Empty Then
+ _logger.Debug($"Attachment_String [{oAttachment}]!")
+ If IO.File.Exists(oAttachment) = False Then
+ _logger.Info($"Attachment.File [{oAttachment}] is not existing!!!")
+ End If
+ End If
+
+ If IsNothing(oEmailAddress) OrElse String.IsNullOrWhiteSpace(oEmailAddress) Then
+ _logger.Warn("Could not find email-address for MessageId {0}", MessageId)
+ oEmailTo = String.Empty
+ Else
+ oEmailTo = oEmailAddress
+ End If
+
+ _logger.Debug("Generated Email:")
+ _logger.Debug("To: {0}", oEmailTo)
+ _logger.Debug("Subject: {0}", oSubject)
+ _logger.Debug("Body {0}", oFinalBodyText)
+ Dim osql = $"Select MAX(GUID) FROM TBEMLP_HISTORY WHERE EMAIL_MSGID = '{MessageId}'"
+ Dim oHistoryID = _mssql.GetScalarValue(osql)
+
+ 'osql = $"select * from TBEMLP_EMAIL_OUT where REFERENCE_ID = {oHistoryID} and EMAIL_ADRESS = '{oEmailTo}' and EMAIL_SUBJ = '{oSubject}'"
+
+ 'Dim oDTResult As DataTable = _mssql.GetDatatable(osql)
+
+ If IsNumeric(oHistoryID) Then
+ Dim oInsert = $"INSERT INTO [dbo].[TBEMLP_EMAIL_OUT] (
+ [REMINDER_TYPE_ID]
+ ,[SENDING_PROFILE]
+ ,[REFERENCE_ID]
+ ,[REFERENCE_STRING]
+ ,[WF_ID]
+ ,[EMAIL_ADRESS]
+ ,[EMAIL_SUBJ]
+ ,[EMAIL_BODY]
+ ,[COMMENT]
+ ,[ADDED_WHO]
+ ,EMAIL_ATTMT1)
+ VALUES
+ (77
+ ,{oAccountId}
+ ,{oHistoryID}
+ ,'{MessageId}'
+ ,77
+ ,'{oEmailTo}'
+ ,'{oSubject}'
+ ,'{oFinalBodyText}'
+ ,'{SourceProcedure}'
+ ,'{oCreatedWho}'
+ ,'{oAttachment}')"
+ _mssql.ExecuteNonQuery(oInsert)
+ Else
+ 'If oDTResult.Rows.Count = 0 Then
+ ' _logger.Debug("Email has already been sent!!")
+ 'Else
+ _logger.Warn("Could not get oHistoryID in AddToEmailQueueMSSQL!!")
+ ' End If
+ End If
+ Catch ex As Exception
+ _logger.Error(ex)
+ End Try
+ End Sub
+
+ Public Function GetEmailDataForMessageId(MessageId As String) As EmailData
+ Dim oSQL = $"SELECT EMAIL_FROM, EMAIL_SUBJECT, EMAIL_ATTMT1 FROM TBEDM_EMAIL_PROFILER_HISTORY WHERE EMAIL_MSGID = '{MessageId}'"
+ Try
+ Dim oDatatable = _firebird.GetDatatable(oSQL)
+ Dim oRow As DataRow
+
+ If oDatatable.Rows.Count = 0 Then
+ _logger.Warn("Got no results for MessageId {0}", MessageId)
+ Return Nothing
+ ElseIf oDatatable.Rows.Count > 1 Then
+ _logger.Warn("Got too many results for MessageId {0}. Using last row.", MessageId)
+ End If
+
+ _logger.Debug("Got Email Data for FileId {0}", MessageId)
+ oRow = oDatatable.Rows.Item(oDatatable.Rows.Count - 1)
+
+ Return New EmailData() With {
+ .From = oRow.Item("EMAIL_FROM"),
+ .Attachment = oRow.Item("EMAIL_ATTMT1"),
+ .Subject = oRow.Item("EMAIL_SUBJECT")
+ }
+ Catch ex As Exception
+ _logger.Warn("Could not fetch Email Data for FileId {0}", MessageId)
+ Return Nothing
+ End Try
+ End Function
+
+ Public Function GetOriginalEmailPath(OriginalEmailDirectory As String, MessageId As String) As String
+ Dim oAttachmentDirectory = OriginalEmailDirectory
+ Dim oAttachmentFile = MessageId & ".eml"
+ Dim oAttachmentPath = Path.Combine(oAttachmentDirectory, oAttachmentFile)
+
+ If IO.File.Exists(oAttachmentPath) Then
+ Return oAttachmentPath
+ Else
+ Return String.Empty
+ End If
+ End Function
+
+ Public Function GetEmailPathWithSubjectAsName(RejectedEmailDirectory As String, UncleanedSubject As String) As String
+ Dim oCleanSubject = String.Join("", UncleanedSubject.Split(Path.GetInvalidPathChars()))
+ Dim oAttachmentDirectory = RejectedEmailDirectory
+ Dim oAttachmentFile = oCleanSubject & ".eml"
+ Dim oAttachmentPath = Path.Combine(oAttachmentDirectory, oAttachmentFile)
+
+ Return oAttachmentPath
+ End Function
+
+ Private Function RandomValue(lowerBound As Integer, upperBound As Integer) As Integer
+ Dim oRandomValue = CInt(Math.Floor((upperBound - lowerBound + 1) * Rnd())) + lowerBound
+ Return oRandomValue
+ End Function
+End Class
diff --git a/Modules.Jobs/EDMI/ZUGFeRD/EmailStrings.vb b/Modules.Jobs/EDMI/ZUGFeRD/EmailStrings.vb
new file mode 100644
index 00000000..9e23ef5f
--- /dev/null
+++ b/Modules.Jobs/EDMI/ZUGFeRD/EmailStrings.vb
@@ -0,0 +1,18 @@
+Public Class EmailStrings
+ Public Const EMAIL_WRAPPING_TEXT = "Sehr geehrte Damen und Herren,
+ das WISAG-Portal zur Verarbeitung der Eingangsrechnungen im ZUGFeRD-Format konnte die von Ihnen gesandte Rechnung
+ leider nicht verarbeiten!
Grund: {0}Bitte prüfen Sie die Datei und nehmen Sie bei Bedarf mit uns Kontakt auf.
+ Vielen Dank für Ihr Verständnis.
Mit freundlichen Grüßen
Ihre IT-Abteilung"
+ Public Const EMAIL_SUBJECT = "WISAG ZUGFeRD Portal: Beleg abgelehnt"
+ Public Const EMAIL_MISSINGPROPERTIES_1 = "
Die angehängte Datei entspricht nicht dem WISAG ZUGFeRD-Format: {0}
"
+ Public Const EMAIL_MISSINGPROPERTIES_2 = "Die folgenden Eigenschaften wurden als ERFORDERLICH eingestuft, wurden aber nicht gefunden:
"
+ Public Const EMAIL_MD5_ERROR = "Die von Ihnen gesendete Rechnung wurde bereits von unserem System verarbeitet.
"
+ Public Const EMAIL_TOO_MUCH_FERDS = "Ihre Email enthielt mehr als ein ZUGFeRD-Dokument.
"
+ Public Const EMAIL_NO_FERDS = "Ihre Email enthielt keine ZUGFeRD-Dokumente.
"
+ Public Const EMAIL_INVALID_DOCUMENT = """
+ Ihre Email enthielt ein ZUGFeRD Dokument, welches aber inkorrekt formatiert wurde.
+ Mögliche Gründe für ein inkorrektes Format:
+ - Betrags-Werte weisen ungültiges Format auf (25,01 anstatt 25.01)
+
+ """
+End Class
diff --git a/Modules.Jobs/EDMI/ZUGFeRD/ImportZUGFeRDFiles.vb b/Modules.Jobs/EDMI/ZUGFeRD/ImportZUGFeRDFiles.vb
index edb5c686..0ebbc5a4 100644
--- a/Modules.Jobs/EDMI/ZUGFeRD/ImportZUGFeRDFiles.vb
+++ b/Modules.Jobs/EDMI/ZUGFeRD/ImportZUGFeRDFiles.vb
@@ -26,106 +26,47 @@ Public Class ImportZUGFeRDFiles
Public Const ZUGFERD_ATTACHMENTS = "ZUGFeRD Attachments"
Public HISTORY_ID As Integer
- Private Const EMAIL_WRAPPING_TEXT = "Sehr geehrte Damen und Herren,
- das WISAG-Portal zur Verarbeitung der Eingangsrechnungen im ZUGFeRD-Format konnte die von Ihnen gesandte Rechnung
- leider nicht verarbeiten!
Grund: {0}Bitte prüfen Sie die Datei und nehmen Sie bei Bedarf mit uns Kontakt auf.
- Vielen Dank für Ihr Verständnis.
Mit freundlichen Grüßen
Ihre IT-Abteilung"
- Private Const EMAIL_SUBJECT = "WISAG ZUGFeRD Portal: Beleg abgelehnt"
- Private Const EMAIL_MISSINGPROPERTIES_1 = "
Die angehängte Datei entspricht nicht dem WISAG ZUGFeRD-Format: {0}
"
- Private Const EMAIL_MISSINGPROPERTIES_2 = "Die folgenden Eigenschaften wurden als ERFORDERLICH eingestuft, wurden aber nicht gefunden:
"
- Private Const EMAIL_MD5_ERROR = "Die von Ihnen gesendete Rechnung wurde bereits von unserem System verarbeitet.
"
- Private Const EMAIL_TOO_MUCH_FERDS = "Ihre Email enthielt mehr als ein ZUGFeRD-Dokument.
"
- Private Const EMAIL_NO_FERDS = "Ihre Email enthielt keine ZUGFeRD-Dokumente.
"
- Private Const EMAIL_INVALID_DOCUMENT = """
- Ihre Email enthielt ein ZUGFeRD Dokument, welches aber inkorrekt formatiert wurde.
- Mögliche Gründe für ein inkorrektes Format:
- - Betrags-Werte weisen ungültiges Format auf (25,01 anstatt 25.01)
-
- """
-
' List of allowed extensions for PDF/A Attachments
- Private AllowedExtensions = New List(Of String) From {"docx", "doc", "pdf", "xls", "xlsx", "ppt", "pptx", "txt"}
+ Private ReadOnly AllowedExtensions As List(Of String) = New List(Of String) From {"docx", "doc", "pdf", "xls", "xlsx", "ppt", "pptx", "txt"}
- Private _logger As Logger
- Private _logConfig As LogConfig
- Private _zugferd As ZUGFeRDInterface
- Private _firebird As Firebird
- Private _filesystem As Filesystem.File
- Private _mssql As MSSQLServer
+ Private ReadOnly _logger As Logger
+ Private ReadOnly _logConfig As LogConfig
+ Private ReadOnly _zugferd As ZUGFeRDInterface
+ Private ReadOnly _firebird As Firebird
+ Private ReadOnly _filesystem As Filesystem.File
+ Private ReadOnly _mssql As MSSQLServer
+ Private ReadOnly _email As EmailFunctions
Public Sub New(LogConfig As LogConfig, Firebird As Firebird, Optional MSSQL As MSSQLServer = Nothing)
_logConfig = LogConfig
_logger = LogConfig.GetLogger()
_firebird = Firebird
_filesystem = New Filesystem.File(_logConfig)
- _zugferd = New ZUGFeRDInterface(_logConfig)
_mssql = MSSQL
- End Sub
-
- Private Function RandomValue(lowerBound As Integer, upperBound As Integer) As Integer
- Dim oRandomValue = CInt(Math.Floor((upperBound - lowerBound + 1) * Rnd())) + lowerBound
- Return oRandomValue
- End Function
-
- Private Function GetEmailDataForMessageId(MessageId As String) As EmailData
- Dim oSQL = $"SELECT EMAIL_FROM, EMAIL_SUBJECT, EMAIL_ATTMT1 FROM TBEDM_EMAIL_PROFILER_HISTORY WHERE EMAIL_MSGID = '{MessageId}'"
- Try
- Dim oDatatable = _firebird.GetDatatable(oSQL)
- Dim oRow As DataRow
-
- If oDatatable.Rows.Count = 0 Then
- _logger.Warn("Got no results for MessageId {0}", MessageId)
- Return Nothing
- ElseIf oDatatable.Rows.Count > 1 Then
- _logger.Warn("Got too many results for MessageId {0}. Using last row.", MessageId)
- End If
-
- _logger.Debug("Got Email Data for FileId {0}", MessageId)
- oRow = oDatatable.Rows.Item(oDatatable.Rows.Count - 1)
-
- Return New EmailData() With {
- .From = oRow.Item("EMAIL_FROM"),
- .Attachment = oRow.Item("EMAIL_ATTMT1"),
- .Subject = oRow.Item("EMAIL_SUBJECT")
- }
- Catch ex As Exception
- _logger.Warn("Could not fetch Email Data for FileId {0}", MessageId)
- Return Nothing
- End Try
- End Function
-
- Private Function GetOriginalEmailPath(OriginalEmailDirectory As String, MessageId As String) As String
- Dim oAttachmentDirectory = OriginalEmailDirectory
- Dim oAttachmentFile = MessageId & ".eml"
- Dim oAttachmentPath = Path.Combine(oAttachmentDirectory, oAttachmentFile)
+ _email = New EmailFunctions(LogConfig, _mssql, _firebird)
- If IO.File.Exists(oAttachmentPath) Then
- Return oAttachmentPath
+ _logger.Debug("Registering GDPicture License")
+ If _mssql IsNot Nothing Then
+ Dim oSQL = "SELECT LICENSE FROM TBDD_3RD_PARTY_MODULES WHERE NAME = 'GDPICTURE'"
+ Dim oLicenseKey As String = _mssql.GetScalarValue(oSQL)
+ _zugferd = New ZUGFeRDInterface(_logConfig, oLicenseKey)
Else
- Return String.Empty
+ _logger.Warn("GDPicture License could not be registered! MSSQL is not enabled!")
+ Throw New ArgumentNullException("MSSQL")
End If
- End Function
-
- Private Function GetEmailPathWithSubjectAsName(RejectedEmailDirectory As String, UncleanedSubject As String) As String
- Dim oCleanSubject = String.Join("", UncleanedSubject.Split(Path.GetInvalidPathChars()))
- Dim oAttachmentDirectory = RejectedEmailDirectory
- Dim oAttachmentFile = oCleanSubject & ".eml"
- Dim oAttachmentPath = Path.Combine(oAttachmentDirectory, oAttachmentFile)
-
- Return oAttachmentPath
- End Function
+ End Sub
Private Function MoveAndRenameEmailToRejected(Args As WorkerArgs, MessageId As String) As EmailData
- Dim oEmailData = GetEmailDataForMessageId(MessageId)
- Dim oSource = GetOriginalEmailPath(Args.OriginalEmailDirectory, MessageId)
+ Dim oEmailData = _email.GetEmailDataForMessageId(MessageId)
+ Dim oSource = _email.GetOriginalEmailPath(Args.OriginalEmailDirectory, MessageId)
Dim oDestination As String
' 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 = GetEmailPathWithSubjectAsName(Args.RejectedEmailDirectory, MessageId)
+ oDestination = _email.GetEmailPathWithSubjectAsName(Args.RejectedEmailDirectory, MessageId)
Else
- oDestination = GetEmailPathWithSubjectAsName(Args.RejectedEmailDirectory, oEmailData.Subject)
+ oDestination = _email.GetEmailPathWithSubjectAsName(Args.RejectedEmailDirectory, oEmailData.Subject)
End If
_logger.Debug("Destination for eml file is {0}", oDestination)
@@ -154,135 +95,9 @@ Public Class ImportZUGFeRDFiles
Private Sub AddRejectedState(oMessageID As String, oTitle As String, oTitle1 As String, oComment As String)
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}'"
_mssql.NewExecutenonQuery(oSQL)
- '@MessageID VARCHAR(250), @TITLE1 VARCHAR(250), @TITLE2 VARCHAR(250)
- Catch ex As Exception
- _logger.Error(ex)
- End Try
- End Sub
-
- Private Sub AddToEmailQueueFB(MessageId As String, BodyText As String, EmailData As EmailData)
- If EmailData Is Nothing Then
- _logger.Warn("EmailData is empty. Email will not be sent!")
- Exit Sub
- End If
-
- Try
- Dim oJobId = RandomValue(1, 10000)
- Dim oReference = MessageId
- Dim oEmailTo = ""
- Dim oSubject = EMAIL_SUBJECT
- Dim oAccountId = 1
- Dim oCreatedWho = "ZUGFeRD Service"
- Dim oFinalBodyText = String.Format(EMAIL_WRAPPING_TEXT, BodyText)
-
- Dim oEmailAddress = EmailData.From
- Dim oAttachment = EmailData.Attachment
-
- If IsNothing(oEmailAddress) OrElse String.IsNullOrWhiteSpace(oEmailAddress) Then
- _logger.Warn("Could not find email-address for MessageId {0}", MessageId)
- oEmailTo = String.Empty
- Else
- oEmailTo = oEmailAddress
- End If
-
- _logger.Debug("Generated Email:")
- _logger.Debug("To: {0}", oEmailTo)
- _logger.Debug("Subject: {0}", oSubject)
- _logger.Debug("Body {0}", oFinalBodyText)
- Dim osql = $"select * from TBEDM_EMAIL_QUEUE where REFERENCE1 = '{oReference} and EMAIL_TO = ''{oEmailTo}' and EMAIL_SUBJ = '{oSubject}'"
-
- Dim oDTResult As DataTable = _firebird.GetDatatable(osql)
-
- If oDTResult.Rows.Count = 0 Then
- Dim oSQLInsert = $"INSERT INTO TBEDM_EMAIL_QUEUE "
- oSQLInsert &= "(JOB_ID, REFERENCE1, EMAIL_ACCOUNT_ID, EMAIL_TO, EMAIL_SUBJ, EMAIL_BODY, CREATEDWHO, EMAIL_ATTMT1) VALUES "
- oSQLInsert &= $"({oJobId}, '{oReference}', {oAccountId}, '{oEmailTo}', '{oSubject}', '{oFinalBodyText.Replace("'", "''")}', '{oCreatedWho}', '{oAttachment}')"
- _firebird.ExecuteNonQuery(oSQLInsert)
- _logger.Debug("Email Queue updated for MessageId {0}.", MessageId, oEmailTo)
- Else
- _logger.Debug("Email has already been sent!!")
- End If
- Catch ex As Exception
- _logger.Error(ex)
- End Try
- End Sub
- Private Sub AddToEmailQueueMSSQL(MessageId As String, BodyText As String, pEmailData As EmailData, SourceProcedure As String)
- If pEmailData Is Nothing Then
- _logger.Warn("EmailData is empty. Email will not be sent!")
- Exit Sub
- End If
-
- Try
- Dim oJobId = RandomValue(1, 10000)
- Dim oReference = MessageId
- Dim oEmailTo = ""
- Dim oSubject = EMAIL_SUBJECT
- Dim oAccountId = 1
- Dim oCreatedWho = "ZUGFeRD Service"
- Dim oFinalBodyText = String.Format(EMAIL_WRAPPING_TEXT, BodyText)
-
- Dim oEmailAddress = pEmailData.From
- Dim oAttachment = pEmailData.Attachment
- If oAttachment <> String.Empty Then
- _logger.Debug($"Attachment_String [{oAttachment}]!")
- If IO.File.Exists(oAttachment) = False Then
- _logger.Info($"Attachment.File [{oAttachment}] is not existing!!!")
- End If
- End If
-
- If IsNothing(oEmailAddress) OrElse String.IsNullOrWhiteSpace(oEmailAddress) Then
- _logger.Warn("Could not find email-address for MessageId {0}", MessageId)
- oEmailTo = String.Empty
- Else
- oEmailTo = oEmailAddress
- End If
-
- _logger.Debug("Generated Email:")
- _logger.Debug("To: {0}", oEmailTo)
- _logger.Debug("Subject: {0}", oSubject)
- _logger.Debug("Body {0}", oFinalBodyText)
- Dim osql = $"Select MAX(GUID) FROM TBEMLP_HISTORY WHERE EMAIL_MSGID = '{MessageId}'"
- Dim oHistoryID = _mssql.GetScalarValue(osql)
-
- 'osql = $"select * from TBEMLP_EMAIL_OUT where REFERENCE_ID = {oHistoryID} and EMAIL_ADRESS = '{oEmailTo}' and EMAIL_SUBJ = '{oSubject}'"
-
- 'Dim oDTResult As DataTable = _mssql.GetDatatable(osql)
-
- If IsNumeric(oHistoryID) Then
- Dim oInsert = $"INSERT INTO [dbo].[TBEMLP_EMAIL_OUT] (
- [REMINDER_TYPE_ID]
- ,[SENDING_PROFILE]
- ,[REFERENCE_ID]
- ,[REFERENCE_STRING]
- ,[WF_ID]
- ,[EMAIL_ADRESS]
- ,[EMAIL_SUBJ]
- ,[EMAIL_BODY]
- ,[COMMENT]
- ,[ADDED_WHO]
- ,EMAIL_ATTMT1)
- VALUES
- (77
- ,{oAccountId}
- ,{oHistoryID}
- ,'{MessageId}'
- ,77
- ,'{oEmailTo}'
- ,'{oSubject}'
- ,'{oFinalBodyText}'
- ,'{SourceProcedure}'
- ,'{oCreatedWho}'
- ,'{oAttachment}')"
- _mssql.ExecuteNonQuery(oInsert)
- Else
- 'If oDTResult.Rows.Count = 0 Then
- ' _logger.Debug("Email has already been sent!!")
- 'Else
- _logger.Warn("Could not get oHistoryID in AddToEmailQueueMSSQL!!")
- ' End If
- End If
Catch ex As Exception
_logger.Error(ex)
End Try
@@ -295,23 +110,6 @@ Public Class ImportZUGFeRDFiles
_logger.Debug("Starting Job {0}", [GetType].Name)
- _logger.Debug("Registering GDPicture License")
- If _mssql IsNot Nothing Then
- Try
- Dim oSQL = "SELECT LICENSE FROM TBDD_3RD_PARTY_MODULES WHERE NAME = 'GDPICTURE'"
- Dim oLicenseKey As String = _mssql.GetScalarValue(oSQL)
- Dim oLicenseManager As New LicenseManager
- oLicenseManager.RegisterKEY(oLicenseKey)
- Catch ex As Exception
- _logger.Error(ex)
- _logger.Warn("GDPicture License could not be retrieved! Query failed! Exiting job.")
- Exit Sub
- End Try
- Else
- _logger.Warn("GDPicture License could not be retrieved! MSSQL is not enabled! Exiting job.")
- Exit Sub
- End If
-
Try
For Each oPath As String In oArgs.WatchDirectories
Dim oDirInfo As New DirectoryInfo(oPath)
@@ -398,7 +196,8 @@ Public Class ImportZUGFeRDFiles
End Select
End Try
- ' Extract all attachments other than the zugferd-invoice.xml
+ ' 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.
Dim oAttachments = oAttachmentExtractor.Extract(oFile.FullName, AllowedExtensions)
If oAttachments Is Nothing Then
_logger.Warn("Attachments for file [{0}] could not be extracted", oFile.FullName)
@@ -440,7 +239,7 @@ Public Class ImportZUGFeRDFiles
' Since extraction went well, increase the amount of ZUGFeRD files
oZUGFeRDCount += 1
-
+#Region "Check Property Values"
' --- BEGIN Check Property Values
'' PropertyMap items with `IsGrouped = False` are handled normally
@@ -607,7 +406,7 @@ Public Class ImportZUGFeRDFiles
'Next
'--- END Check Property Values
-
+#End Region
' Check the document against the configured property map and return:
' - a List of valid properties
' - a List of missing properties
@@ -666,9 +465,9 @@ Public Class ImportZUGFeRDFiles
Dim oSQL = $"UPDATE TBEDM_ZUGFERD_HISTORY_IN SET COMMENT = 'REJECTED - Already processed (MD5Hash)' WHERE GUID = '{HISTORY_ID}'"
_firebird.ExecuteNonQuery(oSQL)
- Dim oBody = EMAIL_MD5_ERROR
+ Dim oBody = EmailStrings.EMAIL_MD5_ERROR
Dim oEmailData = MoveAndRenameEmailToRejected(oArgs, oMessageId)
- AddToEmailQueueMSSQL(oMessageId, oBody, oEmailData, "MD5HashException")
+ _email.AddToEmailQueueMSSQL(oMessageId, oBody, oEmailData, "MD5HashException")
AddRejectedState(oMessageId, "MD5HashException", "Die gesendete Rechnung wurde bereits verarbeitet!", "")
Catch ex As InvalidFerdException
_logger.Error(ex)
@@ -676,9 +475,9 @@ Public Class ImportZUGFeRDFiles
oMoveDirectory = oArgs.ErrorDirectory
Dim oSQL = $"UPDATE TBEDM_ZUGFERD_HISTORY_IN SET COMMENT = 'REJECTED - ZUGFeRD yes but incorrect format' WHERE GUID = '{HISTORY_ID}'"
_firebird.ExecuteNonQuery(oSQL)
- Dim oBody = EMAIL_INVALID_DOCUMENT
+ Dim oBody = EmailStrings.EMAIL_INVALID_DOCUMENT
Dim oEmailData = MoveAndRenameEmailToRejected(oArgs, oMessageId)
- AddToEmailQueueMSSQL(oMessageId, oBody, oEmailData, "InvalidFerdException")
+ _email.AddToEmailQueueMSSQL(oMessageId, oBody, oEmailData, "InvalidFerdException")
AddRejectedState(oMessageId, "InvalidFerdException", "Inkorrekte Formate", "")
Catch ex As TooMuchFerdsException
_logger.Error(ex)
@@ -686,9 +485,9 @@ Public Class ImportZUGFeRDFiles
oMoveDirectory = oArgs.ErrorDirectory
Dim oSQL = $"UPDATE TBEDM_ZUGFERD_HISTORY_IN SET COMMENT = 'REJECTED - More than one ZUGFeRD-document in email' WHERE GUID = '{HISTORY_ID}'"
_firebird.ExecuteNonQuery(oSQL)
- Dim oBody = EMAIL_TOO_MUCH_FERDS
+ Dim oBody = EmailStrings.EMAIL_TOO_MUCH_FERDS
Dim oEmailData = MoveAndRenameEmailToRejected(oArgs, oMessageId)
- AddToEmailQueueMSSQL(oMessageId, oBody, oEmailData, "TooMuchFerdsException")
+ _email.AddToEmailQueueMSSQL(oMessageId, oBody, oEmailData, "TooMuchFerdsException")
AddRejectedState(oMessageId, "TooMuchFerdsException", "Email enthielt mehr als ein ZUGFeRD-Dokument", "")
Catch ex As NoFerdsException
_logger.Error(ex)
@@ -696,9 +495,9 @@ Public Class ImportZUGFeRDFiles
oMoveDirectory = oArgs.ErrorDirectory
Dim oSQL = $"UPDATE TBEDM_ZUGFERD_HISTORY_IN SET COMMENT = 'REJECTED - no ZUGFeRD-Document in email' WHERE GUID = '{HISTORY_ID}'"
_firebird.ExecuteNonQuery(oSQL)
- Dim oBody = EMAIL_NO_FERDS
+ Dim oBody = EmailStrings.EMAIL_NO_FERDS
Dim oEmailData = MoveAndRenameEmailToRejected(oArgs, oMessageId)
- AddToEmailQueueMSSQL(oMessageId, oBody, oEmailData, "NoFerdsException")
+ _email.AddToEmailQueueMSSQL(oMessageId, oBody, oEmailData, "NoFerdsException")
AddRejectedState(oMessageId, "NoFerdsException", " Email enthielt keine ZUGFeRD-Dokumente", "")
Catch ex As MissingValueException
_logger.Error(ex)
@@ -713,7 +512,7 @@ Public Class ImportZUGFeRDFiles
Dim oBody = CreateBodyForMissingProperties(ex.File.Name, oMissingProperties)
Dim oEmailData = MoveAndRenameEmailToRejected(oArgs, oMessageId)
- AddToEmailQueueMSSQL(oMessageId, oBody, oEmailData, "MissingValueException")
+ _email.AddToEmailQueueMSSQL(oMessageId, oBody, oEmailData, "MissingValueException")
AddRejectedState(oMessageId, "MissingValueException", "Es fehlten ZugferdSpezifikationen", oMessage)
Catch ex As Exception
@@ -821,11 +620,11 @@ Public Class ImportZUGFeRDFiles
Private Function CreateBodyForMissingProperties(OriginalFilename As String, MissingProperties As List(Of String))
- Dim oBody = String.Format(EMAIL_MISSINGPROPERTIES_1, OriginalFilename)
+ Dim oBody = String.Format(EmailStrings.EMAIL_MISSINGPROPERTIES_1, OriginalFilename)
If MissingProperties.Count > 0 Then
oBody &= $"{vbNewLine}{vbNewLine}"
- oBody &= EMAIL_MISSINGPROPERTIES_2
+ oBody &= EmailStrings.EMAIL_MISSINGPROPERTIES_2
oBody &= $"{vbNewLine}{vbNewLine}"
For Each prop In MissingProperties
diff --git a/Modules.Jobs/Jobs.vbproj b/Modules.Jobs/Jobs.vbproj
index 979ebe93..735498cd 100644
--- a/Modules.Jobs/Jobs.vbproj
+++ b/Modules.Jobs/Jobs.vbproj
@@ -87,6 +87,8 @@
+
+