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
+39 -37
View File
@@ -1,4 +1,4 @@
using System.Data;
using System.Data;
using System.Diagnostics;
using CAMTParser;
using Fuchs.Observability;
@@ -45,10 +45,17 @@ public class BankingService : IBankingService
}
string format;
if (CamtParser.LooksLikeXml(bytes))
if (CamtParser.LooksLikeZip(bytes))
{
format = "camt.zip";
try { MapCamtEntries(tbl, new CamtParser().ParseZip(bytes)); }
catch (Exception ex) { _logger.LogError(ex, "CAMT ZIP statement parse failed."); }
}
else if (CamtParser.LooksLikeXml(bytes))
{
format = "camt";
FillFromCamt(tbl, bytes);
try { MapCamtEntries(tbl, new CamtParser().Parse(bytes)); }
catch (Exception ex) { _logger.LogError(ex, "CAMT statement parse failed."); }
}
else
{
@@ -129,53 +136,48 @@ public class BankingService : IBankingService
}
// ── CAMT (ISO 20022) ───────────────────────────────────────────────────────
private void FillFromCamt(DataTable tbl, byte[] bytes)
private void MapCamtEntries(DataTable tbl, List<CamtStatement> statements)
{
void SetNfo(DataRow nr, string key, object? value)
{
if (tbl.Columns.Contains(key) && value != null) nr[key] = value;
}
try
foreach (var stmt in statements)
{
var statements = new CamtParser().Parse(bytes);
foreach (var stmt in statements)
if (string.IsNullOrEmpty(stmt.AccountIdentification)) continue;
foreach (var e in stmt.Entries)
{
if (string.IsNullOrEmpty(stmt.AccountIdentification)) continue;
foreach (var e in stmt.Entries)
try
{
try
{
var nr = tbl.NewRow();
SetNfo(nr, "AccountIdentification", stmt.AccountIdentification);
if (e.Amount.HasValue) SetNfo(nr, "Amount", e.Amount);
if (e.EntryDate.HasValue) SetNfo(nr, "EntryDate", e.EntryDate);
if (e.ValueDate.HasValue) SetNfo(nr, "ValueDate", e.ValueDate);
SetNfo(nr, "FundsCode", e.Currency);
SetNfo(nr, "DebitCreditMark", e.MarkAbbreviation);
SetNfo(nr, "BankReference", e.BankReference);
SetNfo(nr, "EndToEndReference", e.EndToEndReference);
SetNfo(nr, "MandateReference", e.MandateReference);
SetNfo(nr, "CustomerReference", e.CustomerReference);
SetNfo(nr, "CreditorReference", e.CreditorReference);
SetNfo(nr, "AccountNumberOfPayer", e.CounterpartyIban);
SetNfo(nr, "BankCodeOfPayer", e.CounterpartyBic);
SetNfo(nr, "NameOfPayer", e.CounterpartyName);
SetNfo(nr, "PostingText", e.AdditionalInfo);
SetNfo(nr, "TransactionTypeIdCode",e.BankTransactionCode);
SetNfo(nr, "SepaRemittanceInformation",
string.IsNullOrEmpty(e.RemittanceUnstructured) ? e.RemittanceStructured : e.RemittanceUnstructured);
SetNfo(nr, "UnstructuredRemittanceInformation", e.RemittanceUnstructured);
SetNfo(nr, "UnstructuredData", e.RemittanceUnstructured);
SetNfo(nr, "IsUnstructuredData", e.IsUnstructuredData);
var nr = tbl.NewRow();
SetNfo(nr, "AccountIdentification", stmt.AccountIdentification);
if (e.Amount.HasValue) SetNfo(nr, "Amount", e.Amount);
if (e.EntryDate.HasValue) SetNfo(nr, "EntryDate", e.EntryDate);
if (e.ValueDate.HasValue) SetNfo(nr, "ValueDate", e.ValueDate);
SetNfo(nr, "FundsCode", e.Currency);
SetNfo(nr, "DebitCreditMark", e.MarkAbbreviation);
SetNfo(nr, "BankReference", e.BankReference);
SetNfo(nr, "EndToEndReference", e.EndToEndReference);
SetNfo(nr, "MandateReference", e.MandateReference);
SetNfo(nr, "CustomerReference", e.CustomerReference);
SetNfo(nr, "CreditorReference", e.CreditorReference);
SetNfo(nr, "AccountNumberOfPayer", e.CounterpartyIban);
SetNfo(nr, "BankCodeOfPayer", e.CounterpartyBic);
SetNfo(nr, "NameOfPayer", e.CounterpartyName);
SetNfo(nr, "PostingText", e.AdditionalInfo);
SetNfo(nr, "TransactionTypeIdCode",e.BankTransactionCode);
SetNfo(nr, "SepaRemittanceInformation",
string.IsNullOrEmpty(e.RemittanceUnstructured) ? e.RemittanceStructured : e.RemittanceUnstructured);
SetNfo(nr, "UnstructuredRemittanceInformation", e.RemittanceUnstructured);
SetNfo(nr, "UnstructuredData", e.RemittanceUnstructured);
SetNfo(nr, "IsUnstructuredData", e.IsUnstructuredData);
tbl.Rows.Add(nr);
}
catch (Exception ex) { _logger.LogWarning(ex, "CAMT entry parse error — account={Account}", stmt.AccountIdentification); }
tbl.Rows.Add(nr);
}
catch (Exception ex) { _logger.LogWarning(ex, "CAMT entry parse error — account={Account}", stmt.AccountIdentification); }
}
}
catch (Exception ex) { _logger.LogError(ex, "CAMT statement parse failed."); }
}
private static DataTable BuildDefaultSchema()