Add support for invoice attachments

Introduced the `InvoiceAttachment` entity and its relationship with `ZugferdInvoice` to manage extracted invoice attachments. Updated `AppDbContext` and added a migration to create the `InvoiceAttachments` table with cascading delete behavior and an index for optimized queries.

Enhanced the UI to display attachments in `Details.cshtml`, including file type icons, file size, and extraction date. Added a new `ViewAttachment` page to render or download attachments based on their type, with support for XML, plain text, images, and downloads.

Implemented `AttachmentViewerService` to determine viewer types and MIME types for attachments. Registered the service in the DI container. Updated `Upload.cshtml.cs` to save extracted attachments to the database.

Improved user experience with syntax highlighting for XML files and appropriate messages for unsupported file types.
This commit is contained in:
OlgunR
2026-06-02 15:03:37 +02:00
parent 43d63e975d
commit 920dce13d5
13 changed files with 536 additions and 2 deletions

View File

@@ -0,0 +1,88 @@
@page
@using DXApp.TemplateKitProject.Services
@model DXApp.TemplateKitProject.Pages.Invoices.ViewAttachmentModel
@{
ViewData["Title"] = $"Attachment: {Model.FileName}";
}
<h2>?? Attachment: @Model.FileName</h2>
<div class="mb-3">
<a href="/Invoices/Details" class="btn btn-secondary">? Zurück</a>
<a href="?handler=Download&filePath=@Request.Query["filePath"]"
class="btn btn-primary">
?? Download
</a>
</div>
@switch (Model.ViewerType)
{
case AttachmentViewerType.Pdf:
<div class="alert alert-info">
PDF-Dateien können Sie über die Result-PDF-Funktion anzeigen.
</div>
break;
case AttachmentViewerType.Xml:
<div class="card">
<div class="card-header bg-primary text-white">
<strong>XML-Inhalt</strong> (ZUGFeRD/Factur-X)
</div>
<div class="card-body p-0">
<textarea id="xml-viewer" style="display:none;">@Model.TextContent</textarea>
<div id="xml-rendered"></div>
</div>
</div>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.16/codemirror.min.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.16/theme/monokai.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.16/codemirror.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.16/mode/xml/xml.min.js"></script>
<script>
var editor = CodeMirror(document.getElementById('xml-rendered'), {
value: document.getElementById('xml-viewer').value,
mode: 'xml',
lineNumbers: true,
readOnly: true,
theme: 'monokai',
lineWrapping: true
});
</script>
break;
case AttachmentViewerType.Text:
<div class="card">
<div class="card-header bg-secondary text-white">
<strong>Text-Inhalt</strong>
</div>
<div class="card-body">
<pre style="background-color: #f5f5f5; padding: 15px; border-radius: 5px; max-height: 600px; overflow: auto;">@Model.TextContent</pre>
</div>
</div>
break;
case AttachmentViewerType.Image:
<div class="card">
<div class="card-body text-center">
<img src="?handler=Download&filePath=@Request.Query["filePath"]"
alt="@Model.FileName"
class="img-fluid"
style="max-height: 800px;">
</div>
</div>
break;
case AttachmentViewerType.Word:
<div class="alert alert-warning">
<strong>Word-Dokumente können nicht direkt angezeigt werden.</strong>
<p>Bitte laden Sie die Datei herunter oder implementieren Sie eine Konvertierung zu PDF.</p>
</div>
break;
default:
<div class="alert alert-warning">
<strong>Dieser Dateityp kann nicht angezeigt werden.</strong>
<p>Bitte laden Sie die Datei herunter.</p>
</div>
break;
}