Persist invoice validation reports as JSON blobs
This commit is contained in:
1 parent
2075bcb2c3
commit
bb9b20cc25
3 files changed
+93
-38
No files matched your search
@@ -0,0 +1,19 @@
|
||||
namespace ImportAssist.Core;
|
||||
|
||||
public sealed record InvoiceCheckResult(
|
||||
int LineNumber,
|
||||
string InvoiceId,
|
||||
bool IsValid,
|
||||
IReadOnlyList<string> Errors);
|
||||
|
||||
public sealed record ImportReport(
|
||||
string SourceBlob,
|
||||
DateTimeOffset CheckedAtUtc,
|
||||
string Status,
|
||||
IReadOnlyList<InvoiceCheckResult> Rows,
|
||||
IReadOnlyList<string> FileErrors)
|
||||
{
|
||||
public int TotalCount => Rows.Count;
|
||||
public int ValidCount => Rows.Count(row => row.IsValid);
|
||||
public int InvalidCount => TotalCount - ValidCount;
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
using System.Text.Json;
|
||||
using ImportAssist.Core;
|
||||
using Microsoft.Azure.Functions.Worker;
|
||||
using Microsoft.Extensions.Logging;
|
||||
@@ -7,60 +8,69 @@ namespace ImportAssist_Functions;
|
||||
public sealed class InvoiceBlobTrigger(
|
||||
ILogger<InvoiceBlobTrigger> logger)
|
||||
{
|
||||
private static readonly JsonSerializerOptions JsonOptions =
|
||||
new(JsonSerializerDefaults.Web)
|
||||
{
|
||||
WriteIndented = true
|
||||
};
|
||||
|
||||
[Function("InvoiceBlobTrigger")]
|
||||
public void Run(
|
||||
[BlobOutput(
|
||||
"results/{name}.json",
|
||||
Connection = "AzureWebJobsStorage")]
|
||||
public string Run(
|
||||
[BlobTrigger(
|
||||
"imports/{name}",
|
||||
Connection = "AzureWebJobsStorage")]
|
||||
string content,
|
||||
string name)
|
||||
{
|
||||
IReadOnlyList<InvoiceRow> rows;
|
||||
ImportReport report;
|
||||
|
||||
try
|
||||
{
|
||||
rows = InvoiceCsvParser.Parse(content);
|
||||
var rows = InvoiceCsvParser.Parse(content);
|
||||
var results = new List<InvoiceCheckResult>();
|
||||
|
||||
for (var index = 0; index < rows.Count; index++)
|
||||
{
|
||||
var row = rows[index];
|
||||
var errors = InvoiceValidator.Validate(row);
|
||||
|
||||
results.Add(new InvoiceCheckResult(
|
||||
LineNumber: index + 2,
|
||||
InvoiceId: row.InvoiceId,
|
||||
IsValid: errors.Count == 0,
|
||||
Errors: errors));
|
||||
}
|
||||
|
||||
report = new ImportReport(
|
||||
SourceBlob: name,
|
||||
CheckedAtUtc: DateTimeOffset.UtcNow,
|
||||
Status: "Completed",
|
||||
Rows: results,
|
||||
FileErrors: []);
|
||||
}
|
||||
catch (FormatException exception)
|
||||
{
|
||||
logger.LogWarning(
|
||||
"Datei {BlobName} wegen CSV-Formatfehler abgewiesen: {Reason}",
|
||||
name,
|
||||
exception.Message);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
var validCount = 0;
|
||||
|
||||
foreach (var row in rows)
|
||||
{
|
||||
var errors = InvoiceValidator.Validate(row);
|
||||
|
||||
if (errors.Count == 0)
|
||||
{
|
||||
validCount++;
|
||||
}
|
||||
|
||||
var invoiceId = string.IsNullOrWhiteSpace(row.InvoiceId)
|
||||
? "(ohne Rechnungsnummer)"
|
||||
: row.InvoiceId;
|
||||
|
||||
logger.LogInformation(
|
||||
"{BlobName}: {InvoiceId}: {Result}",
|
||||
name,
|
||||
invoiceId,
|
||||
errors.Count == 0
|
||||
? "Gültig"
|
||||
: string.Join("; ", errors));
|
||||
report = new ImportReport(
|
||||
SourceBlob: name,
|
||||
CheckedAtUtc: DateTimeOffset.UtcNow,
|
||||
Status: "Rejected",
|
||||
Rows: [],
|
||||
FileErrors: [exception.Message]);
|
||||
}
|
||||
|
||||
logger.LogInformation(
|
||||
"Dateiprüfung abgeschlossen: {BlobName}, " +
|
||||
"{TotalCount} Rechnungen, {ValidCount} gültig, {InvalidCount} fehlerhaft.",
|
||||
"Prüfbericht erstellt: {BlobName}, Status {Status}, " +
|
||||
"{TotalCount} Rechnungen, {ValidCount} gültig, " +
|
||||
"{InvalidCount} fehlerhaft.",
|
||||
name,
|
||||
rows.Count,
|
||||
validCount,
|
||||
rows.Count - validCount);
|
||||
report.Status,
|
||||
report.TotalCount,
|
||||
report.ValidCount,
|
||||
report.InvalidCount);
|
||||
|
||||
return JsonSerializer.Serialize(report, JsonOptions);
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user