Add duplicate invoice detection and warning message

Added a warning message in `Upload.cshtml` to notify users when a duplicate invoice is detected. Introduced the `IsDuplicate` property in `UploadModel` to track duplicates and updated the `OnPostAsync` method to set this property based on the `ImportedAt` timestamp.

Enhanced the `ImportAsync` method in `ZugferdImportService` to include duplicate detection by checking the database for invoices with the same `InvoiceNumber` and `SellerTaxId`. If a duplicate is found, it logs a warning and returns the existing invoice.

Updated `ImportAsync` to accept an optional `guidelineId` parameter and added logging for duplicate detection and successful imports.
This commit is contained in:
OlgunR
2026-05-28 08:35:01 +02:00
parent 6582370c08
commit 245f7a8268
3 changed files with 37 additions and 4 deletions

View File

@@ -104,5 +104,12 @@
<tr><th>Importiert am</th><td>@Model.ImportedInvoice.ImportedAt.ToString("dd.MM.yyyy HH:mm")</td></tr> <tr><th>Importiert am</th><td>@Model.ImportedInvoice.ImportedAt.ToString("dd.MM.yyyy HH:mm")</td></tr>
</table> </table>
<div class="alert alert-success mt-2">✔ Rechnung wurde in der Datenbank gespeichert (ID: @Model.ImportedInvoice.Id)</div> <div class="alert alert-success mt-2">✔ Rechnung wurde in der Datenbank gespeichert (ID: @Model.ImportedInvoice.Id)</div>
@if (Model.IsDuplicate)
{
<div class="alert alert-warning mt-2">
⚠️ <strong>Duplikat:</strong> Diese Rechnung wurde bereits importiert (ID: @Model.ImportedInvoice!.Id).
Es wurde kein neuer Eintrag angelegt.
</div>
}
} }
} }

View File

@@ -21,6 +21,7 @@ public class UploadModel(
public string? ErrorMessage { get; private set; } public string? ErrorMessage { get; private set; }
public ZugferdInvoice? ImportedInvoice { get; private set; } public ZugferdInvoice? ImportedInvoice { get; private set; }
public string? ResultFilePath { get; private set; } public string? ResultFilePath { get; private set; }
public bool IsDuplicate { get; private set; }
public void OnGet() public void OnGet()
{ } { }
@@ -56,10 +57,14 @@ public class UploadModel(
if (Result.HasZugferdXml) if (Result.HasZugferdXml)
{ {
memStream.Position = 0; memStream.Position = 0;
ImportedInvoice = await zugferdImportService.ImportAsync(memStream, "Upload"); ImportedInvoice = await zugferdImportService.ImportAsync(memStream, "Upload", Result.ZugferdGuidelineId);
// 3. Result-Package erstellen (nur wenn Import erfolgreich) // Duplikat erkennen: vorhandener Eintrag hat ImportedAt von früher
if (ImportedInvoice is not null) if (ImportedInvoice is not null && ImportedInvoice.ImportedAt < DateTime.UtcNow.AddSeconds(-5))
IsDuplicate = true;
// 3. Result-Package erstellen (nur wenn Import erfolgreich UND kein Duplikat)
if (ImportedInvoice is not null && !IsDuplicate)
{ {
ResultFilePath = await resultPackageService.CreateResultPackageAsync( ResultFilePath = await resultPackageService.CreateResultPackageAsync(
originalBytes, PdfFile.FileName, ImportedInvoice); originalBytes, PdfFile.FileName, ImportedInvoice);

View File

@@ -1,5 +1,6 @@
using DXApp.TemplateKitProject.Data; using DXApp.TemplateKitProject.Data;
using DXApp.TemplateKitProject.Models; using DXApp.TemplateKitProject.Models;
using Microsoft.EntityFrameworkCore;
namespace DXApp.TemplateKitProject.Services; namespace DXApp.TemplateKitProject.Services;
@@ -9,7 +10,7 @@ public class ZugferdImportService(
AppDbContext db, AppDbContext db,
ILogger<ZugferdImportService> logger) ILogger<ZugferdImportService> logger)
{ {
public async Task<ZugferdInvoice?> ImportAsync(Stream pdfStream, string sourceType) public async Task<ZugferdInvoice?> ImportAsync(Stream pdfStream, string sourceType, string guidelineId = "")
{ {
var xml = extractor.ExtractXml(pdfStream); var xml = extractor.ExtractXml(pdfStream);
@@ -20,11 +21,31 @@ public class ZugferdImportService(
} }
var invoice = parser.Parse(xml); var invoice = parser.Parse(xml);
// Duplikatprüfung
var duplicate = await db.ZugferdInvoices.FirstOrDefaultAsync(i =>
i.InvoiceNumber == invoice.InvoiceNumber &&
i.SellerTaxId == invoice.SellerTaxId);
if (duplicate is not null)
{
logger.LogWarning(
"Duplikat erkannt: Rechnung '{Number}' von '{Seller}' existiert bereits (ID: {Id}).",
invoice.InvoiceNumber, invoice.SellerName, duplicate.Id);
return duplicate;
}
invoice.SourceType = sourceType; invoice.SourceType = sourceType;
invoice.GuidelineId = guidelineId;
invoice.ImportedAt = DateTime.UtcNow;
db.ZugferdInvoices.Add(invoice); db.ZugferdInvoices.Add(invoice);
await db.SaveChangesAsync(); await db.SaveChangesAsync();
logger.LogInformation(
"Rechnung '{Number}' von '{Seller}' importiert (ID: {Id}).",
invoice.InvoiceNumber, invoice.SellerName, invoice.Id);
return invoice; return invoice;
} }
} }