From 6515e1811bd6d474dba7e4d38277af608f52968b Mon Sep 17 00:00:00 2001 From: Developer01 Date: Fri, 7 Feb 2025 14:42:54 +0100 Subject: [PATCH] MS Sichtbeleg --- Jobs/Jobs.vbproj | 13 ++ Jobs/My Project/AssemblyInfo.vb | 4 +- Jobs/ZUGFeRD/ImportZUGFeRDFiles.vb | 54 ++++-- Jobs/ZUGFeRD/XRechnungStrings.vb | 7 + Jobs/ZUGFeRD/XRechnungViewDocument.vb | 248 +++++++++++++++++++++++++- Jobs/packages.config | 2 + 6 files changed, 315 insertions(+), 13 deletions(-) create mode 100644 Jobs/ZUGFeRD/XRechnungStrings.vb diff --git a/Jobs/Jobs.vbproj b/Jobs/Jobs.vbproj index cf0838a5..a9c4900e 100644 --- a/Jobs/Jobs.vbproj +++ b/Jobs/Jobs.vbproj @@ -14,6 +14,8 @@ 42016,41999,42017,42018,42019,42032,42036,42020,42021,42022 true + + AnyCPU @@ -116,12 +118,16 @@ True Settings.settings + ..\packages\FirebirdSql.Data.FirebirdClient.7.5.0\lib\net452\FirebirdSql.Data.FirebirdClient.dll + + ..\packages\GdPicture.14.2.90\lib\net462\GdPicture.NET.14.dll + ..\packages\Newtonsoft.Json.12.0.3\lib\net45\Newtonsoft.Json.dll @@ -143,4 +149,11 @@ powershell.exe -command "& { &'$(SolutionDir)copy-binary.ps1' '$(TargetPath)' '$(TargetFileName)' '$(ConfigurationName)' '$(ProjectName)' }" + + + + Dieses Projekt verweist auf mindestens ein NuGet-Paket, das auf diesem Computer fehlt. Verwenden Sie die Wiederherstellung von NuGet-Paketen, um die fehlenden Dateien herunterzuladen. Weitere Informationen finden Sie unter "http://go.microsoft.com/fwlink/?LinkID=322105". Die fehlende Datei ist "{0}". + + + \ No newline at end of file diff --git a/Jobs/My Project/AssemblyInfo.vb b/Jobs/My Project/AssemblyInfo.vb index 644ecb87..5c21ef84 100644 --- a/Jobs/My Project/AssemblyInfo.vb +++ b/Jobs/My Project/AssemblyInfo.vb @@ -30,5 +30,5 @@ Imports System.Runtime.InteropServices ' Sie können alle Werte angeben oder die standardmäßigen Build- und Revisionsnummern ' übernehmen, indem Sie "*" eingeben: - - + + diff --git a/Jobs/ZUGFeRD/ImportZUGFeRDFiles.vb b/Jobs/ZUGFeRD/ImportZUGFeRDFiles.vb index 06a0ea4b..6dbadc87 100644 --- a/Jobs/ZUGFeRD/ImportZUGFeRDFiles.vb +++ b/Jobs/ZUGFeRD/ImportZUGFeRDFiles.vb @@ -40,11 +40,15 @@ Public Class ImportZUGFeRDFiles Private ReadOnly _hash As HashFunctions Private ReadOnly _embeds As PDFEmbeds - Private ReadOnly _gdpictureLicenseKey As String + Private SQL_xRechnung_ItemTemplate As String = "" + Private ReadOnly _gdpictureLicenseKey As String + Private _xRechnungCreator As XRechnungViewDocument Private _zugferd As ZUGFeRDInterface Private _EmailOutAccountId As Integer + Private MyTemplateValues_xInvDT As DataTable + Private Class ProcessFileResult Public ZugferdFileFound As Boolean = False @@ -70,7 +74,7 @@ Public Class ImportZUGFeRDFiles _history = New ZUGFeRD.HistoryFunctions(LogConfig, _mssql) _embeds = New PDFEmbeds(LogConfig) _hash = New HashFunctions(_logConfig, _mssql) - + _xRechnungCreator = New XRechnungViewDocument(_logConfig, _mssql, _gdpictureLicenseKey) _logger.Debug("Registering GDPicture License") If _mssql IsNot Nothing Then _gdpictureLicenseKey = ConfigDbFunct.GetProductLicense("GDPICTURE", "11.2024", _logConfig, _mssql.CurrentConnectionString) @@ -92,6 +96,11 @@ Public Class ImportZUGFeRDFiles }) _logger.Debug("Starting Job {0}", [GetType].Name) + If oArgs.AllowXRechnung Then + Dim oSQL = "Select SQL_COMMAND from TBDD_SQL_COMMANDS WHERE TITLE = 'VWDD_ZUGFERD_VIEW_RECEIPT_TEMPLATE_ITEMS'" + SQL_xRechnung_ItemTemplate = _mssql.GetScalarValue(oSQL) + End If + Try 'For Each oPath As String In oArgs.WatchDirectory @@ -123,12 +132,23 @@ Public Class ImportZUGFeRDFiles _logger.Info("Found {0} file groups", oGrouped.Count) - ' Process each file group together + 'Process each file group together + 'oGrouped equals one e-invoice For Each oFileGroup In oGrouped ' Start a new transaction for each file group. ' This way we can rollback database changes for the whole filegroup in case something goes wrong. - Dim oSQLConnection As SqlConnection = _mssql.GetConnection() + + If oArgs.AllowXRechnung Then + 'but before we need to get all Data we need + MyTemplateValues_xInvDT = Nothing + Dim oSQL_MsgIDReplacec = SQL_xRechnung_ItemTemplate + oSQL_MsgIDReplacec = oSQL_MsgIDReplacec.Replace("@MSG_ID", oFileGroup.Key) + MyTemplateValues_xInvDT = _mssql.GetDatatable(oSQL_MsgIDReplacec) + End If + + + Dim oSQLTransaction As SqlTransaction = oSQLConnection?.BeginTransaction() Dim oConnections As New DatabaseConnections() With { @@ -151,7 +171,7 @@ Public Class ImportZUGFeRDFiles Dim oExpectedError As Boolean = True ' Create file lists - Dim oFileGroupFiles As List(Of FileInfo) = oFileGroup.Value + Dim oEInvoiceFileGroup As List(Of FileInfo) = oFileGroup.Value Dim oEmailAttachmentFiles As New List(Of FileInfo) Dim oEmbeddedAttachmentFiles As New List(Of PDFEmbeds.EmbeddedFile) @@ -160,7 +180,7 @@ Public Class ImportZUGFeRDFiles _logger.Info("START processing file group {0}", oMessageId) - If _file.CheckFileAge(oFileGroupFiles, oArgs.MinFileAgeInMinutes) Then + If _file.CheckFileAge(oEInvoiceFileGroup, oArgs.MinFileAgeInMinutes) Then _logger.Info("At least one file was created less than [{0}] minutes ago. Skipping file group.", oArgs.MinFileAgeInMinutes) Continue For End If @@ -169,7 +189,8 @@ Public Class ImportZUGFeRDFiles Dim oFileCounter As Integer = 0 Try - For Each oFile In oFileGroupFiles + + For Each oFile In oEInvoiceFileGroup oFileCounter += 1 Dim oResult As ProcessFileResult @@ -395,15 +416,28 @@ Public Class ImportZUGFeRDFiles Finally Try + Dim oxRechnungHandle As Boolean = False + Dim oRegularMove As Boolean = False ' If an application error occurred, dont move files so they will be processed again later If oMoveDirectory = DIRECTORY_DONT_MOVE Then _logger.Info("Application Error occurred. Files for message Id {0} will not be moved.", oMessageId) - - ElseIf (1 = 0) Then + ElseIf oArgs.AllowXRechnung And oIsSuccess And oEInvoiceFileGroup.Item(0).Extension = ".xml" Then + oxRechnungHandle = True ' Hier das neue PDF erzeugen + If Not IsNothing(MyTemplateValues_xInvDT) Then + Dim oViewReceiptFileInfo As FileInfo = _xRechnungCreator.Create_PDFfromXML(oEInvoiceFileGroup.Item(0), MyTemplateValues_xInvDT) + If Not IsNothing(oViewReceiptFileInfo) Then + oEInvoiceFileGroup.Item(0) = oViewReceiptFileInfo + oRegularMove = True + End If + End If + Else + oRegularMove = True + End If + If oRegularMove Then ' Move all files of the current group - _file.MoveFiles(oArgs, oMessageId, oFileGroupFiles, oEmailAttachmentFiles, oEmbeddedAttachmentFiles, oMoveDirectory, oIsSuccess) + _file.MoveFiles(oArgs, oMessageId, oEInvoiceFileGroup, oEmailAttachmentFiles, oEmbeddedAttachmentFiles, oMoveDirectory, oIsSuccess) End If _logger.Info("END processing file group {0}", oMessageId) Catch ex As Exception diff --git a/Jobs/ZUGFeRD/XRechnungStrings.vb b/Jobs/ZUGFeRD/XRechnungStrings.vb new file mode 100644 index 00000000..7137f4eb --- /dev/null +++ b/Jobs/ZUGFeRD/XRechnungStrings.vb @@ -0,0 +1,7 @@ +Public Class XRechnungStrings + Public Const CommentSichtbeleg_DE_Row1 = "Achtung: dies ist ein technisch erstelltes Abbild einer digitalen Rechnung." + Public Const CommentSichtbeleg_DE_Row2 = "Die Darstellung basiert auf den Inhalten der xml-Datei, welche als Anhang in diese PDF integriert wurde!" + Public Const CommentSichtbeleg_EN_Row1 = "Please note: this is a technically created image of a digital invoice." + Public Const CommentSichtbeleg_EN_Row2 = "The representation is based on the contents of the xml file, which has been integrated into this PDF as an attachment!" + Public Const Seperator_Line = "-------------------------------------------------------------------------" +End Class diff --git a/Jobs/ZUGFeRD/XRechnungViewDocument.vb b/Jobs/ZUGFeRD/XRechnungViewDocument.vb index c2ae9d69..1a57fdfb 100644 --- a/Jobs/ZUGFeRD/XRechnungViewDocument.vb +++ b/Jobs/ZUGFeRD/XRechnungViewDocument.vb @@ -1,3 +1,249 @@ -Public Class XRechnungViewDocument +Imports System.Data +Imports System.Data.SqlClient +Imports System.IO +Imports DigitalData.Modules.Base +Imports DigitalData.Modules.Database +Imports DigitalData.Modules.Logging +Imports FirebirdSql.Data +Imports GdPicture14 + +Public Class XRechnungViewDocument + Private ReadOnly _logger As Logger + Private ReadOnly _logConfig As LogConfig + Private ReadOnly _filesystem As FilesystemEx + 'Private ReadOnly _mssql As MSSQLServer + Private ReadOnly _file As ZUGFeRD.FileFunctions + Private ReadOnly _gdpictureLicenseKey As String + + Public Sub New(LogConfig As LogConfig, MSSQL As MSSQLServer, GDPictureLicenseKey As String) + _logConfig = LogConfig + _logger = LogConfig.GetLogger() + _filesystem = New FilesystemEx(_logConfig) + _file = New ZUGFeRD.FileFunctions(LogConfig, MSSQL) + _gdpictureLicenseKey = GDPictureLicenseKey + End Sub + Public Function Create_PDFfromXML(oxmlFile As FileInfo, pDTItemValues As DataTable) As FileInfo + Try + Dim oXRechnungFile = oxmlFile.FullName + Dim oNewFileinfo As FileInfo + Dim oxmlFilePath = oxmlFile.FullName + Dim oViewRecieptFilename = oxmlFile.Name + Dim oTempFilePath = Path.GetDirectoryName(oxmlFilePath) + "\Temp" + If Not Directory.Exists(oTempFilePath) Then + Directory.CreateDirectory(oTempFilePath) + End If + + oTempFilePath = oTempFilePath + "\xrechnung.xml" + If File.Exists(oTempFilePath) Then + File.Delete(oTempFilePath) + End If + File.Move(oxmlFilePath, oTempFilePath) + oxmlFile = New FileInfo(oTempFilePath) + oViewRecieptFilename = oViewRecieptFilename.Replace("xml", "pdf") + Dim oOutputPath = Path.GetDirectoryName(oxmlFilePath) + "\" + oViewRecieptFilename + If File.Exists(oOutputPath) Then + File.Delete(oOutputPath) + End If + + Dim gdpicturePDF As GdPicturePDF = New GdPicturePDF() + gdpicturePDF.NewPDF(PdfConformance.PDF_A_2a) + Dim ostatus As GdPictureStatus = gdpicturePDF.NewPDF() + If ostatus <> GdPictureStatus.OK Then + _logger.Warn($"Error initializing PDF: {ostatus}") + Return Nothing + End If + gdpicturePDF.SetOrigin(PdfOrigin.PdfOriginTopLeft) + gdpicturePDF.SetMeasurementUnit(PdfMeasurementUnit.PdfMeasurementUnitMillimeter) + gdpicturePDF.SetLineWidth(1) + Dim fontResName = gdpicturePDF.AddStandardFont(PdfStandardFont.PdfStandardFontHelvetica) + Dim fontResNameBold = gdpicturePDF.AddStandardFont(PdfStandardFont.PdfStandardFontHelveticaBold) + Dim fontResNameItalic = gdpicturePDF.AddStandardFont(PdfStandardFont.PdfStandardFontHelveticaBoldOblique) + gdpicturePDF.SetTitle("xInvoice VisualReceipt") + gdpicturePDF.SetAuthor("Digital Data GmbH, Heuchelheim") + 'Create a New page + gdpicturePDF.NewPage(PdfPageSizes.PdfPageSizeA4) + 'Draw content on the PDF + Dim yPosition As Integer = 20 + gdpicturePDF.SetTextSize(18) + gdpicturePDF.DrawText(fontResName, 10, yPosition, "xRechnung Sichtbeleg - xInvoice Visual Receipt") + yPosition += 10 + gdpicturePDF.SetTextSize(10) + gdpicturePDF.DrawText(fontResNameItalic, 10, yPosition, XRechnungStrings.CommentSichtbeleg_DE_Row1) + yPosition += 5 + gdpicturePDF.DrawText(fontResNameItalic, 10, yPosition, XRechnungStrings.CommentSichtbeleg_DE_Row2) + yPosition += 5 + gdpicturePDF.DrawText(fontResNameItalic, 10, yPosition, XRechnungStrings.CommentSichtbeleg_EN_Row1) + yPosition += 5 + gdpicturePDF.DrawText(fontResNameItalic, 10, yPosition, XRechnungStrings.CommentSichtbeleg_EN_Row2) + Dim oArea As String = "" + Dim oIsPosition As Boolean = False + Dim oPosCount = 0 + Dim oPosTerm As String = "" + Dim oCurrencySymbol = "€" + yPosition += 5 + Dim oIndex As Integer = 0 + For Each oRow As DataRow In pDTItemValues.Rows + Dim Y_eq_lastrow As Boolean = CBool(oRow.Item("Y_eq_lastrow")) + Dim oRowCaption As String = oRow.Item("Row_Caption") + Dim oItemSPECNAME As String = oRow.Item("SPEC_NAME") + Dim oItemValue As String = oRow.Item("ITEM_VALUE") + Dim oDisplay As Boolean = oRow.Item("Display") + Dim oRowGUID As String = oRow.Item("GUID") + Dim oAreaSwitch As Boolean = False + _logger.Debug($"Working on SPEC_NAME: {oItemSPECNAME}") + + If oArea <> oRow.Item("Area") Then + '########## AREA WECHSEL ########### + oAreaSwitch = True + oArea = oRow.Item("Area") + Dim oAREACaption As String + If oArea = "TYPE" Then + oAREACaption = $"{Return_InvType(oItemValue)} [{oItemValue}]" + ElseIf oArea = "SELLER" Then + oAREACaption = "Verkäufer / Seller:" + ElseIf oArea = "BUYER" Then + oAREACaption = "Käufer / Buyer:" + ElseIf oArea = "POSITION" Then + oAREACaption = "Positionen / Positions:" + oIsPosition = True + ElseIf oArea = "AMOUNT" Then + oAREACaption = "Steuern / Taxes:" + ElseIf oArea = "PAYMENT" Then + oAREACaption = "Zahlungsinformationen / Payment details:" + Else + oAREACaption = String.Empty + End If + + If Not oAREACaption = String.Empty Then + 'erste Area-Linie + yPosition += 8 + gdpicturePDF.DrawLine(10, yPosition, 125, yPosition) + 'gdpicturePDF.DrawText(fontResName, 10, yPosition, XRechnungStrings.Seperator_Line) + yPosition += 5 + 'Area caption + gdpicturePDF.DrawText(fontResNameBold, 10, yPosition, oAREACaption) + yPosition += 5 + If oArea = "TYPE" Then + gdpicturePDF.DrawLine(10, yPosition, 125, yPosition) + ' gdpicturePDF.DrawText(fontResName, 10, yPosition, XRechnungStrings.Seperator_Line) + yPosition += 5 + End If + End If + If oArea = "TYPE" Then + If oItemSPECNAME = "INVOICE_CURRENCY" Then + If oItemValue <> "EUR" Then + oCurrencySymbol = oItemValue + End If + End If + End If + If oArea = "POSITION" Then + oIsPosition = True + If oItemSPECNAME = "INVOICE_POSITION_AMOUNT" Then + oPosCount += 1 + oPosTerm = $"{oPosCount}. {oItemValue} * " + End If + End If + Else + 'INDIVIDUELLES VERHALTEN BEI Folge-ITEMS + If oArea = "POSITION" Then + oIsPosition = True + If oItemSPECNAME = "INVOICE_POSITION_AMOUNT" Then + oPosCount += 1 + oPosTerm = $"{oPosCount}. {oItemValue} * " + ElseIf oItemSPECNAME = "INVOICE_POSITION_ARTICLE" Then + oPosTerm += $" {oItemValue}" + ElseIf oItemSPECNAME = "INVOICE_TAXPOS_TAX_RATE" Or oItemSPECNAME = "INVOICE_TAXPOS_RATE" Then + oPosTerm += $" - ({oItemValue} %)" + End If + oItemValue = oPosTerm + If oPosCount >= 9 Then + oDisplay = False + End If + ElseIf oArea = "AMOUNT" Then + If oItemSPECNAME = "INVOICE_TOTAL_NET" Or oItemSPECNAME = "INVOICE_TOTAL_TAX" Then + oItemValue += $" {oCurrencySymbol}" + End If + ElseIf oArea = "HEAD" Then + If oItemSPECNAME = "INVOICE_DATE" Or oItemSPECNAME = "INVOICE_SERVICE_DATE" Then + Dim oDateString As String = oItemValue + Dim oParsedDate As DateTime = DateTime.ParseExact(oDateString, "yyyyMMdd", System.Globalization.CultureInfo.InvariantCulture) + oItemValue = oParsedDate.ToString("dd.MM.yyyy") + End If + End If + End If + + If oDisplay = True Then + If Y_eq_lastrow = False And oAreaSwitch = False Then + yPosition += 5 + End If + If oRowCaption <> String.Empty Then + gdpicturePDF.DrawText(fontResName, 10, yPosition, oRowCaption) + gdpicturePDF.DrawText(fontResName, 70, yPosition, oItemValue) + Else + If Y_eq_lastrow = True Then + If oIsPosition = True And oPosCount = 9 Then + gdpicturePDF.DrawText(fontResName, 10, yPosition, "...es gibt noch mehr Positionen, diese werden aber aus Layoutgründen nicht dargestellt.") + gdpicturePDF.DrawText(fontResName, 10, yPosition, "...There are more positions, but these are not shown for layout reasons.") + Else + gdpicturePDF.DrawText(fontResName, oRow.Item("xPosition"), yPosition, oItemValue) + End If + Else + gdpicturePDF.DrawText(fontResName, 10, yPosition, oItemValue) + End If + End If + End If + oIndex += 1 + Next + Dim oCreated = Now.ToString + + gdpicturePDF.DrawLine(10, 280, 200, 280) + 'gdpicturePDF.DrawText(fontResName, 10, 285, XRechnungStrings.Seperator_Line) + Dim oCreatedString = $"Maschinell erstellt durch/Automatically created by Digital Data E-Rechnung Parser: {oCreated}" + gdpicturePDF.DrawText(fontResName, 10, 285, oCreatedString) + Dim oeinv_Format As PdfInvoiceDataFormat = PdfInvoiceDataFormat.ZUGFeRD_2_0 + gdpicturePDF.EmbedFile(oTempFilePath, "Rechnungsdaten im ZUGFeRD-XML-Format") + 'Finalize And save the PDF + ostatus = gdpicturePDF.SaveToFile(oOutputPath) + If ostatus = GdPictureStatus.OK Then + _logger.Info("PDF VisualReceipt generated successfully!") + Else + _logger.Warn($"Error generating PDF VisualReceipt: {ostatus}") + End If + + 'Release resources + gdpicturePDF.CloseDocument() + If ostatus = GdPictureStatus.OK Then + File.Delete(oXRechnungFile) + oNewFileinfo = New FileInfo(oOutputPath) + Return oNewFileinfo + Else + Return Nothing + End If + + Catch ex As Exception + _logger.Error(ex) + Return Nothing + End Try + End Function + Private Function Return_InvType(pType As String) As String + Dim oReturn As String = "Rechnung/invoice" + If pType = "380" Then + oReturn = "Handelsrechnung/Commercial invoice" + ElseIf pType = "381" Then + oReturn = "Gutschriftanzeige/Credit advice" + ElseIf pType = "384" Then + oReturn = "Rechnungskorrektur/Invoice correction" + ElseIf pType = "386" Then + oReturn = "Vorauszahlungsrechnung/Prepayment invoice" + ElseIf pType = "326" Then + oReturn = "Teilrechnung/Partial invoice" + ElseIf pType = "84" Then + oReturn = "Gutschrift/Credit note" + ElseIf pType = "389" Then + oReturn = "Gutschriftsverfahren/Credit note procedure" + End If + Return oReturn + End Function + End Class diff --git a/Jobs/packages.config b/Jobs/packages.config index 91d16086..a70f210b 100644 --- a/Jobs/packages.config +++ b/Jobs/packages.config @@ -1,6 +1,8 @@  + + \ No newline at end of file