("SellerName")
.HasColumnType("nvarchar(max)");
diff --git a/DXApp.TemplateKitProject/Models/ZugferdInvoice.cs b/DXApp.TemplateKitProject/Models/ZugferdInvoice.cs
index 3fa808f..0da23fb 100644
--- a/DXApp.TemplateKitProject/Models/ZugferdInvoice.cs
+++ b/DXApp.TemplateKitProject/Models/ZugferdInvoice.cs
@@ -15,5 +15,6 @@
public string RawXml { get; set; } = string.Empty; // Original-XML zur Sicherheit
public DateTime ImportedAt { get; set; }
public string SourceType { get; set; } = string.Empty; // "Upload" oder "Email"
+ public string ResultFilePath { get; set; } = string.Empty; // Pfad der Result-PDF
}
}
\ No newline at end of file
diff --git a/DXApp.TemplateKitProject/Pages/Invoices/Upload.cshtml b/DXApp.TemplateKitProject/Pages/Invoices/Upload.cshtml
index 7552eef..2fca806 100644
--- a/DXApp.TemplateKitProject/Pages/Invoices/Upload.cshtml
+++ b/DXApp.TemplateKitProject/Pages/Invoices/Upload.cshtml
@@ -40,6 +40,13 @@
{
⚠ Kein ZUGFeRD-XML gefunden.
}
+ @if (!string.IsNullOrEmpty(Model.ResultFilePath))
+ {
+
+ 📦 Result-PDF erstellt:
+ @Model.ResultFilePath
+
+ }
@* PDF/A-Konformitätsstufe anzeigen *@
diff --git a/DXApp.TemplateKitProject/Pages/Invoices/Upload.cshtml.cs b/DXApp.TemplateKitProject/Pages/Invoices/Upload.cshtml.cs
index 3e5cf8b..759bb6f 100644
--- a/DXApp.TemplateKitProject/Pages/Invoices/Upload.cshtml.cs
+++ b/DXApp.TemplateKitProject/Pages/Invoices/Upload.cshtml.cs
@@ -1,4 +1,5 @@
-using DXApp.TemplateKitProject.Models;
+using DXApp.TemplateKitProject.Data;
+using DXApp.TemplateKitProject.Models;
using DXApp.TemplateKitProject.Services;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
@@ -8,6 +9,8 @@ namespace DXApp.TemplateKitProject.Pages.Invoices;
public class UploadModel(
PdfAttachmentExtractorService extractor,
ZugferdImportService zugferdImportService,
+ PdfResultPackageService resultPackageService,
+ AppDbContext db,
ILogger logger) : PageModel
{
[BindProperty]
@@ -17,6 +20,7 @@ public class UploadModel(
public bool ExtractionDone { get; private set; }
public string? ErrorMessage { get; private set; }
public ZugferdInvoice? ImportedInvoice { get; private set; }
+ public string? ResultFilePath { get; private set; }
public void OnGet()
{ }
@@ -42,8 +46,9 @@ public class UploadModel(
// Stream in MemoryStream puffern → kann zweimal gelesen werden
using var memStream = new MemoryStream();
await PdfFile.CopyToAsync(memStream);
+ var originalBytes = memStream.ToArray(); // ← neu: als byte[] merken
- // 1. Anhänge extrahieren und auf Disk speichern
+ // 1. Anhänge extrahieren
memStream.Position = 0;
Result = extractor.ExtractAttachments(memStream, PdfFile.FileName);
@@ -52,6 +57,20 @@ public class UploadModel(
{
memStream.Position = 0;
ImportedInvoice = await zugferdImportService.ImportAsync(memStream, "Upload");
+
+ // 3. Result-Package erstellen (nur wenn Import erfolgreich)
+ if (ImportedInvoice is not null)
+ {
+ ResultFilePath = await resultPackageService.CreateResultPackageAsync(
+ originalBytes, PdfFile.FileName, ImportedInvoice);
+
+ // ResultFilePath in DB aktualisieren
+ if (ResultFilePath is not null)
+ {
+ ImportedInvoice.ResultFilePath = ResultFilePath;
+ await db.SaveChangesAsync();
+ }
+ }
}
}
catch (Exception ex)
diff --git a/DXApp.TemplateKitProject/Program.cs b/DXApp.TemplateKitProject/Program.cs
index ad43148..47fd9b4 100644
--- a/DXApp.TemplateKitProject/Program.cs
+++ b/DXApp.TemplateKitProject/Program.cs
@@ -14,6 +14,7 @@ builder.Services.AddDbContext(options =>
// Services
builder.Services.AddScoped();
+builder.Services.AddScoped();
builder.Services.AddScoped();
builder.Services.AddScoped();
builder.Services.AddScoped();
diff --git a/DXApp.TemplateKitProject/Services/PdfResultPackageService.cs b/DXApp.TemplateKitProject/Services/PdfResultPackageService.cs
new file mode 100644
index 0000000..c9b0898
--- /dev/null
+++ b/DXApp.TemplateKitProject/Services/PdfResultPackageService.cs
@@ -0,0 +1,93 @@
+using DevExpress.Pdf;
+using DXApp.TemplateKitProject.Models;
+
+namespace DXApp.TemplateKitProject.Services;
+
+public class PdfResultPackageService(
+ IConfiguration configuration,
+ ILogger logger)
+{
+ public async Task CreateResultPackageAsync(
+ byte[] originalPdfBytes,
+ string originalFileName,
+ ZugferdInvoice invoice)
+ {
+ // 1. Bericht-PDF suchen
+ var reportPath = FindReportFile(originalFileName);
+ if (reportPath is null)
+ {
+ logger.LogWarning(
+ "Kein Ergebnisbericht gefunden für '{FileName}'.", originalFileName);
+ return null;
+ }
+
+ logger.LogInformation(
+ "Ergebnisbericht gefunden: '{ReportPath}'.", reportPath);
+
+ // 2. Ausgabepfad bestimmen
+ var outputDir = configuration["PdfResults:OutputDirectory"]
+ ?? Path.Combine(Path.GetTempPath(), "PdfResults");
+ Directory.CreateDirectory(outputDir);
+
+ var baseName = Path.GetFileNameWithoutExtension(originalFileName);
+ var outputPath = Path.Combine(outputDir, $"{baseName}_result.pdf");
+
+ // 3. Original auf PDF/A-3b hochstufen + Bericht anhängen
+ await Task.Run(() =>
+ {
+ // Original in MemoryStream laden
+ using var inputStream = new MemoryStream(originalPdfBytes);
+ using var outputStream = new MemoryStream();
+
+ // PDF/A-3b Konvertierung
+ var converter = new PdfDocumentConverter(inputStream);
+ converter.Convert(PdfCompatibility.PdfA3b);
+
+ // Konvertiertes PDF in MemoryStream speichern
+ using var convertedStream = new MemoryStream();
+ converter.SaveDocument(convertedStream);
+ convertedStream.Position = 0;
+
+ // Bericht als Anhang einbetten
+ using var processor = new PdfDocumentProcessor();
+ processor.LoadDocument(convertedStream);
+
+ processor.AttachFile(new PdfFileAttachment
+ {
+ FileName = Path.GetFileName(reportPath),
+ Description = "Ergebnisbericht",
+ MimeType = "application/pdf",
+ Relationship = PdfAssociatedFileRelationship.Supplement,
+ CreationDate = DateTime.Now,
+ Data = File.ReadAllBytes(reportPath)
+ });
+
+ // Speichern
+ processor.SaveDocument(outputPath);
+ });
+
+ logger.LogInformation(
+ "Result-PDF gespeichert: '{OutputPath}'.", outputPath);
+
+ return outputPath;
+ }
+
+ private string? FindReportFile(string originalFileName)
+ {
+ var inputDir = configuration["PdfResultReports:InputDirectory"]
+ ?? Path.Combine(Path.GetTempPath(), "PdfResultReports");
+
+ if (!Directory.Exists(inputDir))
+ {
+ logger.LogWarning("Berichtsverzeichnis nicht gefunden: '{Dir}'.", inputDir);
+ return null;
+ }
+
+ // Konvention Option A: {originalname}_report.pdf
+ var baseName = Path.GetFileNameWithoutExtension(originalFileName);
+ var reportName = $"{baseName}_report.pdf";
+ var reportPath = Path.Combine(inputDir, reportName);
+
+ return File.Exists(reportPath) ? reportPath : null;
+ }
+}
\ No newline at end of file
diff --git a/DXApp.TemplateKitProject/appsettings.json b/DXApp.TemplateKitProject/appsettings.json
index 93808b8..8fb61d4 100644
--- a/DXApp.TemplateKitProject/appsettings.json
+++ b/DXApp.TemplateKitProject/appsettings.json
@@ -11,5 +11,11 @@
},
"PdfExtraction": {
"OutputDirectory": "C:\\PdfExtractions"
+ },
+ "PdfResultReports": {
+ "InputDirectory": "C:\\PdfResultReports"
+ },
+ "PdfResults": {
+ "OutputDirectory": "C:\\PdfResults"
}
}
\ No newline at end of file