Add ZIP-wrapped CAMT parsing and real bank file tests
Playwright Tests / test (push) Has been cancelled

- Support parsing camt.052 ZIP archives in CamtParser and BankingService
- Add CamtZipParserTests for ZIP parsing (single/multi/malformed/empty cases)
- Add CamtRealFileTests: integration tests for real bank exports (ZIP, XML, CAMT, MT940, STA) in git-ignored test data dir
- Update .gitignore and add README.md for test data usage
- Copy test data files in Fuchs.Tests.csproj; add .gitkeep
- Refactor BankingService CAMT mapping logic
- Overhaul connection string config: use {username}/{password} tokens, resolve from secrets at runtime, update appsettings and Key Vault keys
This commit is contained in:
Stefan
2026-07-01 22:06:29 +02:00
parent 8ecf97ed29
commit 3035ef1719
11 changed files with 507 additions and 45 deletions
+43 -1
View File
@@ -1,4 +1,5 @@
using System.Globalization;
using System.Globalization;
using System.IO.Compression;
using System.Text;
using System.Xml.Linq;
@@ -32,6 +33,14 @@ public sealed class CamtParser
xml.Contains("camt.05", StringComparison.OrdinalIgnoreCase) ||
xml.Contains("BkToCstmr", StringComparison.OrdinalIgnoreCase);
/// <summary>
/// Cheap content sniff: is this payload a ZIP archive? Some banks deliver
/// camt.052 intraday reports wrapped in a ZIP containing one or more XML files.
/// Checks for the universal PK magic bytes (0x50 0x4B).
/// </summary>
public static bool LooksLikeZip(ReadOnlySpan<byte> bytes) =>
bytes.Length >= 2 && bytes[0] == 0x50 && bytes[1] == 0x4B;
public List<CamtStatement> Parse(Stream stream)
{
using var reader = new StreamReader(stream, Encoding.UTF8, detectEncodingFromByteOrderMarks: true, leaveOpen: true);
@@ -40,6 +49,39 @@ public sealed class CamtParser
public List<CamtStatement> Parse(byte[] bytes) => Parse(Encoding.UTF8.GetString(bytes));
/// <summary>
/// Parses all CAMT XML files found inside a ZIP archive and returns
/// the combined list of statements. Non-XML entries and malformed XML
/// entries are silently skipped. Used for camt.052 deliveries where the
/// bank wraps one or more intraday reports in a single ZIP file.
/// </summary>
public List<CamtStatement> ParseZip(byte[] bytes)
{
using var ms = new MemoryStream(bytes);
return ParseZip(ms);
}
/// <inheritdoc cref="ParseZip(byte[])"/>
public List<CamtStatement> ParseZip(Stream stream)
{
var result = new List<CamtStatement>();
using var archive = new ZipArchive(stream, ZipArchiveMode.Read, leaveOpen: true);
foreach (var entry in archive.Entries)
{
if (!entry.Name.EndsWith(".xml", StringComparison.OrdinalIgnoreCase))
continue;
using var entryStream = entry.Open();
using var buffer = new MemoryStream();
entryStream.CopyTo(buffer);
var entryBytes = buffer.ToArray();
if (!LooksLikeXml(entryBytes))
continue;
try { result.AddRange(Parse(entryBytes)); }
catch (FormatException) { /* skip malformed XML entries */ }
}
return result;
}
public List<CamtStatement> Parse(string xml)
{
var result = new List<CamtStatement>();