Skip to content

Commit

Permalink
Fix account details model (#16)
Browse files Browse the repository at this point in the history
* Change Singleton to Transient

* Update account details model
Change to WhenAll for fetching account details
  • Loading branch information
DanRJ authored Jan 15, 2025
1 parent bf65c0b commit 9bbdff9
Show file tree
Hide file tree
Showing 2 changed files with 59 additions and 22 deletions.
9 changes: 4 additions & 5 deletions src/Altinn.Dan.Plugin.Banking/Clients/V2/BankClient_v2.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
//----------------------

using Altinn.Dan.Plugin.Banking.Config;
using Microsoft.Extensions.Options;

#pragma warning disable 108 // Disable "CS0108 '{derivedDto}.ToJson()' hides inherited member '{dtoBase}.ToJson()'. Use the new keyword if hiding was intended."
#pragma warning disable 114 // Disable "CS0114 '{derivedDto}.RaisePropertyChanged(String)' hides inherited member 'dtoBase.RaisePropertyChanged(String)'. To make the current member override that implementation, add the override keyword. Otherwise add the new keyword."
Expand Down Expand Up @@ -1359,13 +1358,13 @@ public partial class AccountDetail
[Newtonsoft.Json.JsonProperty("primaryOwner", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)]
public AccountRole PrimaryOwner { get; set; }

[Newtonsoft.Json.JsonProperty("startDate", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)]
[Newtonsoft.Json.JsonProperty("startDate", NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)]
[Newtonsoft.Json.JsonConverter(typeof(DateFormatConverter))]
public System.DateTimeOffset StartDate { get; set; }
public System.DateTimeOffset? StartDate { get; set; }

[Newtonsoft.Json.JsonProperty("endDate", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)]
[Newtonsoft.Json.JsonProperty("endDate", NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)]
[Newtonsoft.Json.JsonConverter(typeof(DateFormatConverter))]
public System.DateTimeOffset EndDate { get; set; }
public System.DateTimeOffset? EndDate { get; set; }

private System.Collections.Generic.IDictionary<string, object> _additionalProperties;

Expand Down
72 changes: 55 additions & 17 deletions src/Altinn.Dan.Plugin.Banking/Services/BankService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -97,45 +97,40 @@ private async Task<BankInfo> InvokeBank(string ssn, BankConfig bank, DateTimeOff
};
var accountListTimeout = new CancellationTokenSource(TimeSpan.FromSeconds(AccountListRequestTimeoutSecs));
var accounts = await GetAllAccounts(bankClient, bank, accountInfoRequestId, ssn, fromDate, toDate);
var x = await GetAccountDetailsV2(bankClient, accounts, bank, accountInfoRequestId, fromDate, toDate, includeTransactions);
return x;
return await GetAccountDetailsV2(bankClient, accounts, bank, accountInfoRequestId, fromDate, toDate, includeTransactions);
}

private async Task<BankInfo> GetAccountDetailsV2(Bank_v2.Bank_v2 bankClient, Accounts accounts, BankConfig bank, Guid accountInfoRequestId, DateTimeOffset? fromDate, DateTimeOffset? toDate, bool includeTransactions = true)
{
var bankInfo = new BankInfo() { Accounts = [] };
var transactions = new Transactions();
foreach (Bank_v2.Account account in accounts.Accounts1)
{
var details = await GetAccountById(bankClient, account, bank, accountInfoRequestId, fromDate, toDate);

if (details.Account == null)
{
// Some test accounts come up with an empty response from the bank here (just '{ "responseStatus": "complete" }'.
// We skip those by returning an empty AccountDto.
continue;
}
IEnumerable<Task<AccountDetails>> accountsDetailsTasks = accounts.Accounts1.Select(x => GetAccountById(bankClient, x, bank, accountInfoRequestId, fromDate, toDate));
AccountDetails[] accountsDetails = await Task.WhenAll(accountsDetailsTasks);
foreach (var accountDetails in accountsDetails)
{
if (accountDetails.Account == null) continue;

var availableCredit = details.Account.Balances.FirstOrDefault(b =>
var availableCredit = accountDetails.Account.Balances.FirstOrDefault(b =>
b.Type == BalanceType.AvailableBalance && b.CreditDebitIndicator == CreditOrDebit.Credit)
?.Amount ?? 0;
var availableDebit = details.Account.Balances.FirstOrDefault(b =>
var availableDebit = accountDetails.Account.Balances.FirstOrDefault(b =>
b.Type == BalanceType.AvailableBalance && b.CreditDebitIndicator == CreditOrDebit.Debit)
?.Amount ?? 0;

var bookedCredit = details.Account.Balances.FirstOrDefault(b =>
var bookedCredit = accountDetails.Account.Balances.FirstOrDefault(b =>
b.Type == BalanceType.BookedBalance && b.CreditDebitIndicator == CreditOrDebit.Credit)
?.Amount ?? 0;
var bookedDebit = details.Account.Balances.FirstOrDefault(b =>
var bookedDebit = accountDetails.Account.Balances.FirstOrDefault(b =>
b.Type == BalanceType.BookedBalance && b.CreditDebitIndicator == CreditOrDebit.Debit)
?.Amount ?? 0;

if (includeTransactions)
{
transactions = await ListTransactionsForAccount(bankClient, account, bank, accountInfoRequestId, fromDate, toDate);
transactions = await ListTransactionsForAccount(bankClient, accountDetails, bank, accountInfoRequestId, fromDate, toDate);
}

var internalAccount = MapToInternalV2(account, details.Account, transactions?.Transactions1, availableCredit - availableDebit, bookedCredit - bookedDebit);
var internalAccount = MapToInternalV2(accountDetails, accountDetails.Account, transactions?.Transactions1, availableCredit - availableDebit, bookedCredit - bookedDebit);
if (internalAccount.AccountDetail != null)
{
bankInfo.Accounts.Add(internalAccount);
Expand Down Expand Up @@ -196,6 +191,26 @@ private async Task<Transactions> ListTransactionsForAccount(Bank_v2.Bank_v2 bank
return transactions;
}

private async Task<Transactions> ListTransactionsForAccount(Bank_v2.Bank_v2 bankClient, AccountDetails accountDetails, BankConfig bank, Guid accountInfoRequestId, DateTimeOffset? fromDate, DateTimeOffset? toDate)
{
var account = accountDetails.Account;
Guid correlationIdTransactions = Guid.NewGuid();

// Start fetching transactions concurrently
var transactionsTimeout = new CancellationTokenSource(TimeSpan.FromSeconds(TransactionRequestTimeoutSecs));

_logger.LogInformation("Getting transactions: bank {BankName} accountreference {AccountReference} dob {DateOfBirth} accountinforequestid {AccountInfoRequestId} correlationid {CorrelationId}",
bank.Name, account.AccountReference, account.PrimaryOwner?.Identifier?.Value?[..6], accountInfoRequestId, correlationIdTransactions);

var transactions = await bankClient.ListTransactionsAsync(account.AccountReference, accountInfoRequestId,
correlationIdTransactions, "OED", null, null, null, fromDate, toDate, transactionsTimeout.Token);

_logger.LogInformation("Retrieved transactions: bank {BankName} accountreference {AccountReference} dob {DateOfBirth} transaction count {NumberOfTransactions} accountinforequestid {AccountInfoRequestId} correlationid {CorrelationId}",
bank.Name, account.AccountIdentifier, account.PrimaryOwner?.Identifier?.Value?.Substring(0, 6), transactions.Transactions1?.Count, accountInfoRequestId, correlationIdTransactions);

return transactions;
}

/*private AccountDto MapFromAccountDTOV2TOV1(AccountDtoV2 result)
{
var a = new AccountDto()
Expand Down Expand Up @@ -286,6 +301,29 @@ private AccountDtoV2 MapToInternalV2(
};
}

private AccountDtoV2 MapToInternalV2(
AccountDetails accountDetails,
AccountDetail detail,
ICollection<Transaction> transactions,
decimal availableBalance,
decimal bookedBalance)
{
var account = accountDetails.Account;
detail.Type = account.Type;
detail.AccountIdentifier = account.AccountIdentifier;
detail.AccountReference = account.AccountReference;

// P.t. almost passthrough mapping
return new AccountDtoV2
{
AccountNumber = account.AccountIdentifier,
AccountDetail = detail,
Transactions = transactions,
AccountAvailableBalance = availableBalance,
AccountBookedBalance = bookedBalance
};
}

public async Task<Transactions> GetTransactionsForAccount(string ssn, BankConfig bankConfig, DateTime fromDate, DateTime toDate, Guid accountInfoRequestId, string accountReference)
{
var correlationId = Guid.NewGuid();
Expand Down

0 comments on commit 9bbdff9

Please sign in to comment.