Files
baya-monorepo/server/src/Infrastructure/Baya.Infrastructure.CrossCutting/Seams/Real/FinnotechBankAccountOwnershipVerifier.cs
T
2026-07-13 21:49:50 +03:30

49 lines
2.3 KiB
C#

#nullable enable
using System.Text.Json;
using Baya.Application.Contracts.Common;
namespace Baya.Infrastructure.CrossCutting.Seams.Real;
/// <summary>
/// Real <see cref="IBankAccountOwnershipVerifier"/> over the Finnotech استعلام شبا owner ↔ national-id inquiry
/// (refinement-phase-8, 5.3 — the b13 first-payout money-mule gate). Selected by
/// <c>Seams:BankOwnership:Provider = finnotech</c>. Resolves the IBAN's registered owner and matches it against
/// the nurse's national id; persists the vendor track id.
/// </summary>
public sealed class FinnotechBankAccountOwnershipVerifier(FinnotechClient client) : IBankAccountOwnershipVerifier
{
public async Task<OwnershipInquiryResult> VerifyOwnershipAsync(string iban, string? nurseNationalId, CancellationToken cancellationToken = default)
{
var trackId = FinnotechClient.NewTrackId();
var vendorRef = $"FINNOTECH-SHEBA-{trackId}";
var path = $"oak/v2/clients/{client.ClientId}/ibanToNid" +
$"?iban={Uri.EscapeDataString(Normalize(iban))}&trackId={trackId}";
var (document, _) = await client.GetAsync(path, cancellationToken);
using var _doc = document;
var root = document.RootElement;
string ownerName = string.Empty;
string? ownerNid = null;
if (root.TryGetProperty("result", out var result))
{
if (result.TryGetProperty("name", out var name) && name.ValueKind == JsonValueKind.String)
ownerName = name.GetString() ?? string.Empty;
if (result.TryGetProperty("nationalCode", out var nid) && nid.ValueKind == JsonValueKind.String)
ownerNid = nid.GetString();
}
// Ownership matches when the account's registered national code equals the nurse's. If the vendor did not
// return a national code we cannot assert a match — fail closed (matched = false), since this is the gate.
var matched = !string.IsNullOrEmpty(ownerNid)
&& !string.IsNullOrEmpty(nurseNationalId)
&& string.Equals(ownerNid, nurseNationalId, StringComparison.Ordinal);
return new OwnershipInquiryResult(matched, ownerName, vendorRef);
}
private static string Normalize(string iban)
=> string.IsNullOrEmpty(iban) ? string.Empty : iban.Replace(" ", string.Empty).ToUpperInvariant();
}