From 6c20cd91bba9152848d1f8a6bf60e9ea0c232c86 Mon Sep 17 00:00:00 2001 From: DanRJ Date: Tue, 4 Feb 2025 16:47:02 +0100 Subject: [PATCH] Fix account details model (#17) * Change Singleton to Transient * Update account details model Change to WhenAll for fetching account details * Remove uneccessary properties from bank models Add log text that explains which field went wrong when serializing * Refactor and enhance banking service and tests - Update `BankClient_v2.cs` to adjust JSON properties and make `CreditDebitIndicator` nullable. - Add `AccountExtensions.cs` with error logging method. - Add `HasErrors` property to `AccountV2` in `BankResponse.cs`. - Enhance `GetAccountDetailsV2` in `BankService.cs` for better error handling and logging. - Update `Altinn.Dan.Plugin.Banking.Test.csproj` to target `net8.0`, add `FakeItEasy`, and reference `Altinn.Dan.Plugin.Banking`. - Add `FakeableHttpMessageHandler.cs` for handling HTTP requests in tests and generating certificates. - Add `BankServiceTests.cs` with comprehensive unit tests for `BankService`. - Remove obsolete `UnitTest1.cs`. --- .../Clients/V2/BankClient_v2.cs | 1166 +---------------- .../Extensions/AccountExtensions.cs | 36 + .../Models/BankResponse.cs | 1 + .../Services/BankService.cs | 228 ++-- .../Altinn.Dan.Plugin.Banking.Test.csproj | 7 +- .../FakeableHttpMessageHandler.cs | 39 + .../Services/BankServiceTests.cs | 267 ++++ .../UnitTest1.cs | 13 - 8 files changed, 470 insertions(+), 1287 deletions(-) create mode 100644 src/Altinn.Dan.Plugin.Banking/Extensions/AccountExtensions.cs create mode 100644 test/Altinn.Dan.Plugin.Banking.Test/FakeableHttpMessageHandler.cs create mode 100644 test/Altinn.Dan.Plugin.Banking.Test/Services/BankServiceTests.cs delete mode 100644 test/Altinn.Dan.Plugin.Banking.Test/UnitTest1.cs diff --git a/src/Altinn.Dan.Plugin.Banking/Clients/V2/BankClient_v2.cs b/src/Altinn.Dan.Plugin.Banking/Clients/V2/BankClient_v2.cs index 9b07cfc..a2e99ba 100644 --- a/src/Altinn.Dan.Plugin.Banking/Clients/V2/BankClient_v2.cs +++ b/src/Altinn.Dan.Plugin.Banking/Clients/V2/BankClient_v2.cs @@ -722,228 +722,6 @@ public virtual async System.Threading.Tasks.Task ListTransactionsA } } - /// - /// List of cards associated with the specified account. Empty list if no hits. - /// - /// Unique reference to the account. Shall not match the account number. - /// Unique reference number / case number that follows the case throughout the different requests. - /// Correlation ID, unique identifier for the technical request - /// The Legal basis used by data consumers in order to fetch data. Should be validated by the data provider. - /// Reference ID based on AdditionalReferenceIDType. Should be validated according to the legal-mandate. - /// What type of reference to expect in AdditionalReferenceID - /// Unique identifier of the user who makes the request at the public agency. - /// From date, current date if not stated - /// To date, current date if not stated - /// Valid response - List of cards associated with an account - Not encrypted response in test (json), but encrypted response according to JWE compact serialization in production (jose) - /// A server side error occurred. - public virtual System.Threading.Tasks.Task ListCardsAsync(string accountReference, System.Guid accountInfoRequestID, System.Guid correlationID, string legal_Mandate, string additionalReferenceID, AdditionalReferenceIDType4? additionalReferenceIDType, string requesterID, System.DateTimeOffset? fromDate, System.DateTimeOffset? toDate) - { - return ListCardsAsync(accountReference, accountInfoRequestID, correlationID, legal_Mandate, additionalReferenceID, additionalReferenceIDType, requesterID, fromDate, toDate, System.Threading.CancellationToken.None); - } - - /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. - /// - /// List of cards associated with the specified account. Empty list if no hits. - /// - /// Unique reference to the account. Shall not match the account number. - /// Unique reference number / case number that follows the case throughout the different requests. - /// Correlation ID, unique identifier for the technical request - /// The Legal basis used by data consumers in order to fetch data. Should be validated by the data provider. - /// Reference ID based on AdditionalReferenceIDType. Should be validated according to the legal-mandate. - /// What type of reference to expect in AdditionalReferenceID - /// Unique identifier of the user who makes the request at the public agency. - /// From date, current date if not stated - /// To date, current date if not stated - /// Valid response - List of cards associated with an account - Not encrypted response in test (json), but encrypted response according to JWE compact serialization in production (jose) - /// A server side error occurred. - public virtual async System.Threading.Tasks.Task ListCardsAsync(string accountReference, System.Guid accountInfoRequestID, System.Guid correlationID, string legal_Mandate, string additionalReferenceID, AdditionalReferenceIDType4? additionalReferenceIDType, string requesterID, System.DateTimeOffset? fromDate, System.DateTimeOffset? toDate, System.Threading.CancellationToken cancellationToken) - { - if (accountReference == null) - throw new System.ArgumentNullException("accountReference"); - - var client_ = _httpClient; - var disposeClient_ = false; - try - { - using (var request_ = new System.Net.Http.HttpRequestMessage()) - { - - if (accountInfoRequestID == null) - throw new System.ArgumentNullException("accountInfoRequestID"); - request_.Headers.TryAddWithoutValidation("AccountInfoRequestID", ConvertToString(accountInfoRequestID, System.Globalization.CultureInfo.InvariantCulture)); - - if (correlationID == null) - throw new System.ArgumentNullException("correlationID"); - request_.Headers.TryAddWithoutValidation("CorrelationID", ConvertToString(correlationID, System.Globalization.CultureInfo.InvariantCulture)); - - if (legal_Mandate == null) - throw new System.ArgumentNullException("legal_Mandate"); - request_.Headers.TryAddWithoutValidation("Legal-Mandate", ConvertToString(legal_Mandate, System.Globalization.CultureInfo.InvariantCulture)); - - if (additionalReferenceID != null) - request_.Headers.TryAddWithoutValidation("AdditionalReferenceID", ConvertToString(additionalReferenceID, System.Globalization.CultureInfo.InvariantCulture)); - - if (additionalReferenceIDType != null) - request_.Headers.TryAddWithoutValidation("AdditionalReferenceIDType", ConvertToString(additionalReferenceIDType, System.Globalization.CultureInfo.InvariantCulture)); - - if (requesterID != null) - request_.Headers.TryAddWithoutValidation("RequesterID", ConvertToString(requesterID, System.Globalization.CultureInfo.InvariantCulture)); - request_.Method = new System.Net.Http.HttpMethod("GET"); - request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); - - var urlBuilder_ = new System.Text.StringBuilder(); - if (!string.IsNullOrEmpty(_baseUrl)) urlBuilder_.Append(_baseUrl); - // Operation Path: "accounts/{accountReference}/cards" - urlBuilder_.Append("accounts/"); - urlBuilder_.Append(System.Uri.EscapeDataString(ConvertToString(accountReference, System.Globalization.CultureInfo.InvariantCulture))); - urlBuilder_.Append("/cards"); - urlBuilder_.Append('?'); - if (fromDate != null) - { - urlBuilder_.Append(System.Uri.EscapeDataString("fromDate")).Append('=').Append(System.Uri.EscapeDataString(fromDate.Value.ToString("yyyy-MM-dd", System.Globalization.CultureInfo.InvariantCulture))).Append('&'); - } - if (toDate != null) - { - urlBuilder_.Append(System.Uri.EscapeDataString("toDate")).Append('=').Append(System.Uri.EscapeDataString(toDate.Value.ToString("yyyy-MM-dd", System.Globalization.CultureInfo.InvariantCulture))).Append('&'); - } - urlBuilder_.Length--; - - PrepareRequest(client_, request_, urlBuilder_); - - var url_ = urlBuilder_.ToString(); - request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); - - PrepareRequest(client_, request_, url_); - - var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); - var disposeResponse_ = true; - try - { - var headers_ = new System.Collections.Generic.Dictionary>(); - foreach (var item_ in response_.Headers) - headers_[item_.Key] = item_.Value; - if (response_.Content != null && response_.Content.Headers != null) - { - foreach (var item_ in response_.Content.Headers) - headers_[item_.Key] = item_.Value; - } - - await ProcessResponse(client_, response_); - - var status_ = (int)response_.StatusCode; - if (status_ == 200) - { - var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); - if (objectResponse_.Object == null) - { - throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null, correlationID.ToString()); - } - return objectResponse_.Object; - } - else - if (status_ == 400) - { - var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); - if (objectResponse_.Object == null) - { - throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null, correlationID.ToString()); - } - throw new ApiException("ACC-001 and best possible description of the error from Data Provider. See information regarding specific error situations on github under API-specification.", status_, objectResponse_.Text, headers_, objectResponse_.Object, null, correlationID.ToString()); - } - else - if (status_ == 401) - { - var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); - if (objectResponse_.Object == null) - { - throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null, correlationID.ToString()); - } - throw new ApiException("ACC-010 and the best possible description of the error from Data Provider. See information regarding specific error situations on github under API-specification.", status_, objectResponse_.Text, headers_, objectResponse_.Object, null, correlationID.ToString()); - } - else - if (status_ == 403) - { - var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); - if (objectResponse_.Object == null) - { - throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null, correlationID.ToString()); - } - throw new ApiException("ACC-011 and the best possible description of the error from Data Provider. See information regarding specific error situations on github under API-specification.", status_, objectResponse_.Text, headers_, objectResponse_.Object, null, correlationID.ToString()); - } - else - if (status_ == 404) - { - var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); - if (objectResponse_.Object == null) - { - throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null, correlationID.ToString()); - } - throw new ApiException("ACC-002 or ACC-003 and the best possible description of the error from Data Provider. See information regarding specific error situations on github under API-specification for the different ACC codes.", status_, objectResponse_.Text, headers_, objectResponse_.Object, null, correlationID.ToString()); - } - else - if (status_ == 405) - { - var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); - if (objectResponse_.Object == null) - { - throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null, correlationID.ToString()); - } - throw new ApiException("ACC-012 and the best possible description of the error from Data Provider. See information regarding specific error situations on github under API-specification.", status_, objectResponse_.Text, headers_, objectResponse_.Object, null, correlationID.ToString()); - } - else - if (status_ == 406) - { - var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); - if (objectResponse_.Object == null) - { - throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null, correlationID.ToString()); - } - throw new ApiException("ACC-013 and the best possible description of the error from Data Provider. See information regarding specific error situations on github under API-specification.", status_, objectResponse_.Text, headers_, objectResponse_.Object, null, correlationID.ToString()); - } - else - if (status_ == 429) - { - var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); - if (objectResponse_.Object == null) - { - throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null, correlationID.ToString()); - } - throw new ApiException("ACC-022 and the best possible description of the error from Data Provider. See information regarding specific error situations on github under API-specification.", status_, objectResponse_.Text, headers_, objectResponse_.Object, null, correlationID.ToString()); - } - else - if (status_ == 500) - { - var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); - if (objectResponse_.Object == null) - { - throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null, correlationID.ToString()); - } - throw new ApiException("ACC-100 or ACC-500 and the best possible description of the error from Data Provider. See information regarding specific error situations on github under API-specification for the different ACC codes.", status_, objectResponse_.Text, headers_, objectResponse_.Object, null, correlationID.ToString()); - } - else - { - var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); - if (objectResponse_.Object == null) - { - throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null, correlationID.ToString()); - } - throw new ApiException("Best possible description of the error from Data Provider", status_, objectResponse_.Text, headers_, objectResponse_.Object, null, correlationID.ToString()); - } - } - finally - { - if (disposeResponse_) - response_.Dispose(); - } - } - } - finally - { - if (disposeClient_) - client_.Dispose(); - } - } - /// /// Role holders for the specified account. Empty list if no hits. /// @@ -1281,7 +1059,7 @@ private string ConvertToString(object value, System.Globalization.CultureInfo cu [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.3.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] public partial class Account { - [Newtonsoft.Json.JsonProperty("status", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [Newtonsoft.Json.JsonProperty("status", Required = Newtonsoft.Json.Required.Always, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] public AccountStatus Status { get; set; } @@ -1296,36 +1074,18 @@ public partial class Account [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] public string AccountReference { get; set; } - [Newtonsoft.Json.JsonProperty("type", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [Newtonsoft.Json.JsonProperty("type", Required = Newtonsoft.Json.Required.Always, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] public AccountType Type { get; set; } - [Newtonsoft.Json.JsonProperty("currency", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - [System.ComponentModel.DataAnnotations.RegularExpression(@"[A-Z]{3,3}")] - public string Currency { get; set; } - [Newtonsoft.Json.JsonProperty("primaryOwner", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] public AccountRole PrimaryOwner { get; set; } - - [Newtonsoft.Json.JsonProperty("name", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - [System.ComponentModel.DataAnnotations.StringLength(70, MinimumLength = 1)] - public string Name { get; set; } - - private System.Collections.Generic.IDictionary _additionalProperties; - - [Newtonsoft.Json.JsonExtensionData] - public System.Collections.Generic.IDictionary AdditionalProperties - { - get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } - set { _additionalProperties = value; } - } - } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.3.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] public partial class AccountDetail { - [Newtonsoft.Json.JsonProperty("status", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [Newtonsoft.Json.JsonProperty("status", Required = Newtonsoft.Json.Required.Always, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] public AccountStatus Status { get; set; } @@ -1333,48 +1093,22 @@ public partial class AccountDetail public FinancialInstitution Servicer { get; set; } [Newtonsoft.Json.JsonProperty("accountIdentifier")] - [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = false)] public string AccountIdentifier { get; set; } [Newtonsoft.Json.JsonProperty("accountReference")] - [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = false)] public string AccountReference { get; set; } [Newtonsoft.Json.JsonProperty("type", NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] public AccountType Type { get; set; } - [Newtonsoft.Json.JsonProperty("currency", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - [System.ComponentModel.DataAnnotations.RegularExpression(@"[A-Z]{3,3}")] - public string Currency { get; set; } - - [Newtonsoft.Json.JsonProperty("name", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - [System.ComponentModel.DataAnnotations.StringLength(70, MinimumLength = 1)] - public string Name { get; set; } - [Newtonsoft.Json.JsonProperty("balances", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] public System.Collections.Generic.ICollection Balances { get; set; } - [Newtonsoft.Json.JsonProperty("primaryOwner", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [Newtonsoft.Json.JsonProperty("primaryOwner", NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] public AccountRole PrimaryOwner { get; set; } - - [Newtonsoft.Json.JsonProperty("startDate", NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - [Newtonsoft.Json.JsonConverter(typeof(DateFormatConverter))] - public System.DateTimeOffset? StartDate { get; set; } - - [Newtonsoft.Json.JsonProperty("endDate", NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - [Newtonsoft.Json.JsonConverter(typeof(DateFormatConverter))] - public System.DateTimeOffset? EndDate { get; set; } - - private System.Collections.Generic.IDictionary _additionalProperties; - - [Newtonsoft.Json.JsonExtensionData] - public System.Collections.Generic.IDictionary AdditionalProperties - { - get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } - set { _additionalProperties = value; } - } - } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.3.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] @@ -1386,68 +1120,17 @@ public partial class AccountDetails [Newtonsoft.Json.JsonProperty("account", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] public AccountDetail Account { get; set; } - - private System.Collections.Generic.IDictionary _additionalProperties; - - [Newtonsoft.Json.JsonExtensionData] - public System.Collections.Generic.IDictionary AdditionalProperties - { - get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } - set { _additionalProperties = value; } - } - } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.3.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] - public enum AccountPermissionType + public partial class AccountRole { - - [System.Runtime.Serialization.EnumMember(Value = @"rightToUseAlone")] - RightToUseAlone = 0, - - [System.Runtime.Serialization.EnumMember(Value = @"rightToUseWithOther")] - RightToUseWithOther = 1, - - [System.Runtime.Serialization.EnumMember(Value = @"rightToSeeOnly")] - RightToSeeOnly = 2, - + [Newtonsoft.Json.JsonProperty("identifier", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public Identifier Identifier { get; set; } } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.3.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class AccountRole - { - [Newtonsoft.Json.JsonProperty("permission", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] - public AccountPermissionType Permission { get; set; } - - [Newtonsoft.Json.JsonProperty("identifier", NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public Identifier Identifier { get; set; } - - [Newtonsoft.Json.JsonProperty("name", NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - [System.ComponentModel.DataAnnotations.StringLength(140, MinimumLength = 1)] - public string Name { get; set; } - - [Newtonsoft.Json.JsonProperty("startDate", NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - [Newtonsoft.Json.JsonConverter(typeof(DateFormatConverter))] - public System.DateTimeOffset StartDate { get; set; } - - [Newtonsoft.Json.JsonProperty("endDate", NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - [Newtonsoft.Json.JsonConverter(typeof(DateFormatConverter))] - public System.DateTimeOffset EndDate { get; set; } - - private System.Collections.Generic.IDictionary _additionalProperties; - - [Newtonsoft.Json.JsonExtensionData] - public System.Collections.Generic.IDictionary AdditionalProperties - { - get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } - set { _additionalProperties = value; } - } - - } - - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.3.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Accounts + public partial class Accounts { [Newtonsoft.Json.JsonProperty("responseDetails", Required = Newtonsoft.Json.Required.Always)] [System.ComponentModel.DataAnnotations.Required] @@ -1456,18 +1139,8 @@ public partial class Accounts [Newtonsoft.Json.JsonProperty("accounts", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] public System.Collections.Generic.ICollection Accounts1 { get; set; } - [Newtonsoft.Json.JsonProperty("links", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [Newtonsoft.Json.JsonProperty("links", NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] public System.Collections.Generic.ICollection Links { get; set; } - - private System.Collections.Generic.IDictionary _additionalProperties; - - [Newtonsoft.Json.JsonExtensionData] - public System.Collections.Generic.IDictionary AdditionalProperties - { - get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } - set { _additionalProperties = value; } - } - } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.3.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] @@ -1524,66 +1197,31 @@ public enum AccountType } - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.3.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] - public enum AddressType - { - - [System.Runtime.Serialization.EnumMember(Value = @"residential")] - Residential = 0, - - [System.Runtime.Serialization.EnumMember(Value = @"business")] - Business = 1, - - [System.Runtime.Serialization.EnumMember(Value = @"mailTo")] - MailTo = 2, - - [System.Runtime.Serialization.EnumMember(Value = @"deliveryTo")] - DeliveryTo = 3, - - } - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.3.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] public partial class Balance { - [Newtonsoft.Json.JsonProperty("creditLineIncluded", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [Newtonsoft.Json.JsonProperty("creditLineIncluded", Required = Newtonsoft.Json.Required.Always, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] public bool CreditLineIncluded { get; set; } - [Newtonsoft.Json.JsonProperty("amount", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [Newtonsoft.Json.JsonProperty("amount", Required = Newtonsoft.Json.Required.Always, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] [System.ComponentModel.DataAnnotations.Range(0D, double.MaxValue)] public decimal Amount { get; set; } - [Newtonsoft.Json.JsonProperty("creditDebitIndicator", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [Newtonsoft.Json.JsonProperty("creditDebitIndicator", NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] - public CreditOrDebit CreditDebitIndicator { get; set; } + public CreditOrDebit? CreditDebitIndicator { get; set; } - [Newtonsoft.Json.JsonProperty("registered", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public System.DateTimeOffset Registered { get; set; } - - [Newtonsoft.Json.JsonProperty("type", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [Newtonsoft.Json.JsonProperty("type", Required = Newtonsoft.Json.Required.Always, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] public BalanceType Type { get; set; } - [Newtonsoft.Json.JsonProperty("creditLineAmount", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [Newtonsoft.Json.JsonProperty("creditLineAmount", NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] [System.ComponentModel.DataAnnotations.Range(0D, double.MaxValue)] - public decimal CreditLineAmount { get; set; } - - [Newtonsoft.Json.JsonProperty("creditLineCurrency", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - [System.ComponentModel.DataAnnotations.RegularExpression(@"[A-Z]{3,3}")] - public string CreditLineCurrency { get; set; } + public decimal? CreditLineAmount { get; set; } - [Newtonsoft.Json.JsonProperty("currency", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [Newtonsoft.Json.JsonProperty("currency", Required = Newtonsoft.Json.Required.Always, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] [System.ComponentModel.DataAnnotations.RegularExpression(@"[A-Z]{3,3}")] public string Currency { get; set; } - - private System.Collections.Generic.IDictionary _additionalProperties; - - [Newtonsoft.Json.JsonExtensionData] - public System.Collections.Generic.IDictionary AdditionalProperties - { - get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } - set { _additionalProperties = value; } - } - } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.3.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] @@ -1601,126 +1239,22 @@ public enum BalanceType [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.3.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] public partial class BankTransactionCode { - [Newtonsoft.Json.JsonProperty("domain", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] - public DomainType Domain { get; set; } - - [Newtonsoft.Json.JsonProperty("family", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] - public FamilyType Family { get; set; } - - [Newtonsoft.Json.JsonProperty("subFamily", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] - public SubFamilyType SubFamily { get; set; } - - [Newtonsoft.Json.JsonProperty("freeText", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - [System.ComponentModel.DataAnnotations.StringLength(500, MinimumLength = 1)] + [Newtonsoft.Json.JsonProperty("freeText", NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.StringLength(500)] public string FreeText { get; set; } - - private System.Collections.Generic.IDictionary _additionalProperties; - - [Newtonsoft.Json.JsonExtensionData] - public System.Collections.Generic.IDictionary AdditionalProperties - { - get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } - set { _additionalProperties = value; } - } - - } - - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.3.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Cards - { - [Newtonsoft.Json.JsonProperty("responseDetails", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required] - public ResponseDetails ResponseDetails { get; set; } = new ResponseDetails(); - - [Newtonsoft.Json.JsonProperty("paymentCards", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public System.Collections.Generic.ICollection PaymentCards { get; set; } - - private System.Collections.Generic.IDictionary _additionalProperties; - - [Newtonsoft.Json.JsonExtensionData] - public System.Collections.Generic.IDictionary AdditionalProperties - { - get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } - set { _additionalProperties = value; } - } - - } - - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.3.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] - public enum CardStatus - { - - [System.Runtime.Serialization.EnumMember(Value = @"active")] - Active = 0, - - [System.Runtime.Serialization.EnumMember(Value = @"blocked")] - Blocked = 1, - - } - - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.3.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] - public enum CardType - { - - [System.Runtime.Serialization.EnumMember(Value = @"debitCard")] - DebitCard = 0, - - [System.Runtime.Serialization.EnumMember(Value = @"creditCard")] - CreditCard = 1, - } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.3.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] public partial class CounterParty { - [Newtonsoft.Json.JsonProperty("accountIdentifier", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public string AccountIdentifier { get; set; } - - [Newtonsoft.Json.JsonProperty("identifier", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [Newtonsoft.Json.JsonProperty("identifier", NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] public Identifier Identifier { get; set; } - [Newtonsoft.Json.JsonProperty("name", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - [System.ComponentModel.DataAnnotations.StringLength(140, MinimumLength = 1)] + [Newtonsoft.Json.JsonProperty("name", NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.StringLength(140)] public string Name { get; set; } - - [Newtonsoft.Json.JsonProperty("type", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] - public CounterPartyType Type { get; set; } - - [Newtonsoft.Json.JsonProperty("postalAddress", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public PostalAddress PostalAddress { get; set; } - - private System.Collections.Generic.IDictionary _additionalProperties; - - [Newtonsoft.Json.JsonExtensionData] - public System.Collections.Generic.IDictionary AdditionalProperties - { - get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } - set { _additionalProperties = value; } - } - } - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.3.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] - public enum CounterPartyType - { - - [System.Runtime.Serialization.EnumMember(Value = @"debtor")] - Debtor = 0, - - [System.Runtime.Serialization.EnumMember(Value = @"creditor")] - Creditor = 1, - - [System.Runtime.Serialization.EnumMember(Value = @"ultimateDebtor")] - UltimateDebtor = 2, - - [System.Runtime.Serialization.EnumMember(Value = @"ultimateCreditor")] - UltimateCreditor = 3, - - } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.3.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] public enum CreditOrDebit @@ -1734,147 +1268,6 @@ public enum CreditOrDebit } - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.3.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class CurrencyExchange - { - [Newtonsoft.Json.JsonProperty("originalAmount", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - [System.ComponentModel.DataAnnotations.Range(0D, double.MaxValue)] - public double OriginalAmount { get; set; } - - [Newtonsoft.Json.JsonProperty("sourceCurrency", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - [System.ComponentModel.DataAnnotations.RegularExpression(@"[A-Z]{3,3}")] - public string SourceCurrency { get; set; } - - [Newtonsoft.Json.JsonProperty("targetCurrency", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - [System.ComponentModel.DataAnnotations.RegularExpression(@"[A-Z]{3,3}")] - public string TargetCurrency { get; set; } - - [Newtonsoft.Json.JsonProperty("unitCurrency", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - [System.ComponentModel.DataAnnotations.RegularExpression(@"[A-Z]{3,3}")] - public string UnitCurrency { get; set; } - - [Newtonsoft.Json.JsonProperty("exchangeRate", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - [System.ComponentModel.DataAnnotations.Range(0D, double.MaxValue)] - public double ExchangeRate { get; set; } - - private System.Collections.Generic.IDictionary _additionalProperties; - - [Newtonsoft.Json.JsonExtensionData] - public System.Collections.Generic.IDictionary AdditionalProperties - { - get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } - set { _additionalProperties = value; } - } - - } - - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.3.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] - public enum DomainType - { - - [System.Runtime.Serialization.EnumMember(Value = @"accountManagement")] - AccountManagement = 0, - - [System.Runtime.Serialization.EnumMember(Value = @"cashManagement")] - CashManagement = 1, - - [System.Runtime.Serialization.EnumMember(Value = @"foreignExchange")] - ForeignExchange = 2, - - [System.Runtime.Serialization.EnumMember(Value = @"payments")] - Payments = 3, - - [System.Runtime.Serialization.EnumMember(Value = @"securities")] - Securities = 4, - - [System.Runtime.Serialization.EnumMember(Value = @"tradeServices")] - TradeServices = 5, - - [System.Runtime.Serialization.EnumMember(Value = @"extended")] - Extended = 6, - - } - - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.3.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] - public enum FamilyType - { - - [System.Runtime.Serialization.EnumMember(Value = @"additionalMiscellaneousCreditOperations")] - AdditionalMiscellaneousCreditOperations = 0, - - [System.Runtime.Serialization.EnumMember(Value = @"additionalMiscellaneousDebitOperations")] - AdditionalMiscellaneousDebitOperations = 1, - - [System.Runtime.Serialization.EnumMember(Value = @"miscellaneousCreditOperations")] - MiscellaneousCreditOperations = 2, - - [System.Runtime.Serialization.EnumMember(Value = @"miscellaneousDebitOperations")] - MiscellaneousDebitOperations = 3, - - [System.Runtime.Serialization.EnumMember(Value = @"openingAndClosing")] - OpeningAndClosing = 4, - - [System.Runtime.Serialization.EnumMember(Value = @"accountBalancing")] - AccountBalancing = 5, - - [System.Runtime.Serialization.EnumMember(Value = @"cashPooling")] - CashPooling = 6, - - [System.Runtime.Serialization.EnumMember(Value = @"notAvailable")] - NotAvailable = 7, - - [System.Runtime.Serialization.EnumMember(Value = @"customerCardTransactions")] - CustomerCardTransactions = 8, - - [System.Runtime.Serialization.EnumMember(Value = @"counterTransactions")] - CounterTransactions = 9, - - [System.Runtime.Serialization.EnumMember(Value = @"drafts")] - Drafts = 10, - - [System.Runtime.Serialization.EnumMember(Value = @"issuedCashConcentrationTransactions")] - IssuedCashConcentrationTransactions = 11, - - [System.Runtime.Serialization.EnumMember(Value = @"issuedCreditTransfers")] - IssuedCreditTransfers = 12, - - [System.Runtime.Serialization.EnumMember(Value = @"issuedCheques")] - IssuedCheques = 13, - - [System.Runtime.Serialization.EnumMember(Value = @"issuedDirectDebits")] - IssuedDirectDebits = 14, - - [System.Runtime.Serialization.EnumMember(Value = @"lockboxTransactions")] - LockboxTransactions = 15, - - [System.Runtime.Serialization.EnumMember(Value = @"merchantCardTransactions")] - MerchantCardTransactions = 16, - - [System.Runtime.Serialization.EnumMember(Value = @"other")] - Other = 17, - - [System.Runtime.Serialization.EnumMember(Value = @"receivedCashConcentrationTransactions")] - ReceivedCashConcentrationTransactions = 18, - - [System.Runtime.Serialization.EnumMember(Value = @"receivedCreditTransfers")] - ReceivedCreditTransfers = 19, - - [System.Runtime.Serialization.EnumMember(Value = @"receivedCheques")] - ReceivedCheques = 20, - - [System.Runtime.Serialization.EnumMember(Value = @"receivedDirectDebits")] - ReceivedDirectDebits = 21, - - [System.Runtime.Serialization.EnumMember(Value = @"corporateAction")] - CorporateAction = 22, - - [System.Runtime.Serialization.EnumMember(Value = @"documentaryCollection")] - DocumentaryCollection = 23, - - [System.Runtime.Serialization.EnumMember(Value = @"standByLetterOfCredit")] - StandByLetterOfCredit = 24, - - } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.3.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] public partial class FinancialInstitution @@ -1885,43 +1278,19 @@ public partial class FinancialInstitution [Newtonsoft.Json.JsonProperty("name", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] [System.ComponentModel.DataAnnotations.StringLength(140, MinimumLength = 1)] public string Name { get; set; } - - private System.Collections.Generic.IDictionary _additionalProperties; - - [Newtonsoft.Json.JsonExtensionData] - public System.Collections.Generic.IDictionary AdditionalProperties - { - get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } - set { _additionalProperties = value; } - } - } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.3.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] public partial class Identifier { - [Newtonsoft.Json.JsonProperty("countryOfResidence", NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - [System.ComponentModel.DataAnnotations.RegularExpression(@"[A-Z]{2,2}")] - public string CountryOfResidence { get; set; } - [Newtonsoft.Json.JsonProperty("value")] - [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = false)] public string Value { get; set; } [Newtonsoft.Json.JsonProperty("type")] [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] public IdentifierType Type { get; set; } - - private System.Collections.Generic.IDictionary _additionalProperties; - - [Newtonsoft.Json.JsonExtensionData] - public System.Collections.Generic.IDictionary AdditionalProperties - { - get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } - set { _additionalProperties = value; } - } - } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.3.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] @@ -1933,7 +1302,6 @@ public enum IdentifierType [System.Runtime.Serialization.EnumMember(Value = @"nationalIdentityNumber")] NationalIdentityNumber = 1, - } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.3.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] @@ -1948,106 +1316,6 @@ public partial class Link [System.ComponentModel.DataAnnotations.Required] [System.ComponentModel.DataAnnotations.StringLength(500, MinimumLength = 1)] public string Href { get; set; } - - private System.Collections.Generic.IDictionary _additionalProperties; - - [Newtonsoft.Json.JsonExtensionData] - public System.Collections.Generic.IDictionary AdditionalProperties - { - get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } - set { _additionalProperties = value; } - } - - } - - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.3.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class PaymentCard - { - [Newtonsoft.Json.JsonProperty("cardIdentifier")] - [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] - public string CardIdentifier { get; set; } - - [Newtonsoft.Json.JsonProperty("holderName", NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - [System.ComponentModel.DataAnnotations.StringLength(140, MinimumLength = 1)] - public string HolderName { get; set; } - - [Newtonsoft.Json.JsonProperty("startDate", NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - [System.ComponentModel.DataAnnotations.RegularExpression(@"^[0-9]+-([0][1-9]|1[0-2])$")] - public string StartDate { get; set; } - - [Newtonsoft.Json.JsonProperty("expiryDate", NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - [System.ComponentModel.DataAnnotations.RegularExpression(@"^[0-9]+-([0][1-9]|1[0-2])$")] - public string ExpiryDate { get; set; } - - [Newtonsoft.Json.JsonProperty("cardIssuerName", NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - [System.ComponentModel.DataAnnotations.StringLength(140, MinimumLength = 1)] - public string CardIssuerName { get; set; } - - [Newtonsoft.Json.JsonProperty("type", NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] - public CardType Type { get; set; } - - [Newtonsoft.Json.JsonProperty("cardStatus", NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] - public CardStatus CardStatus { get; set; } - - [Newtonsoft.Json.JsonProperty("versionNumber", NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - [System.ComponentModel.DataAnnotations.StringLength(1, MinimumLength = 1)] - public string VersionNumber { get; set; } - - [Newtonsoft.Json.JsonProperty("cardIssuerIdentifier", NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public Identifier CardIssuerIdentifier { get; set; } - - private System.Collections.Generic.IDictionary _additionalProperties; - - [Newtonsoft.Json.JsonExtensionData] - public System.Collections.Generic.IDictionary AdditionalProperties - { - get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } - set { _additionalProperties = value; } - } - - } - - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.3.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class PostalAddress - { - [Newtonsoft.Json.JsonProperty("postCode", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - [System.ComponentModel.DataAnnotations.StringLength(16, MinimumLength = 1)] - public string PostCode { get; set; } - - [Newtonsoft.Json.JsonProperty("type", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] - public AddressType Type { get; set; } - - [Newtonsoft.Json.JsonProperty("streetName", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - [System.ComponentModel.DataAnnotations.StringLength(70, MinimumLength = 1)] - public string StreetName { get; set; } - - [Newtonsoft.Json.JsonProperty("buildingNumber", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - [System.ComponentModel.DataAnnotations.StringLength(16, MinimumLength = 1)] - public string BuildingNumber { get; set; } - - [Newtonsoft.Json.JsonProperty("townName", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - [System.ComponentModel.DataAnnotations.StringLength(35, MinimumLength = 1)] - public string TownName { get; set; } - - [Newtonsoft.Json.JsonProperty("country", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - [System.ComponentModel.DataAnnotations.RegularExpression(@"[A-Z]{2,2}")] - public string Country { get; set; } - - [Newtonsoft.Json.JsonProperty("addressLines", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public System.Collections.Generic.ICollection AddressLines { get; set; } - - private System.Collections.Generic.IDictionary _additionalProperties; - - [Newtonsoft.Json.JsonExtensionData] - public System.Collections.Generic.IDictionary AdditionalProperties - { - get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } - set { _additionalProperties = value; } - } - } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.3.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] @@ -2061,16 +1329,6 @@ public partial class ResponseDetails [Newtonsoft.Json.JsonProperty("message", NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] [System.ComponentModel.DataAnnotations.StringLength(500, MinimumLength = 1)] public string Message { get; set; } - - private System.Collections.Generic.IDictionary _additionalProperties; - - [Newtonsoft.Json.JsonExtensionData] - public System.Collections.Generic.IDictionary AdditionalProperties - { - get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } - set { _additionalProperties = value; } - } - } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.3.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] @@ -2082,288 +1340,39 @@ public partial class Roles [Newtonsoft.Json.JsonProperty("roles", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] public System.Collections.Generic.ICollection Roles1 { get; set; } - - private System.Collections.Generic.IDictionary _additionalProperties; - - [Newtonsoft.Json.JsonExtensionData] - public System.Collections.Generic.IDictionary AdditionalProperties - { - get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } - set { _additionalProperties = value; } - } - - } - - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.3.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] - public enum SubFamilyType - { - - [System.Runtime.Serialization.EnumMember(Value = @"valueDate")] - ValueDate = 0, - - [System.Runtime.Serialization.EnumMember(Value = @"chargesGeneric")] - ChargesGeneric = 1, - - [System.Runtime.Serialization.EnumMember(Value = @"commissions")] - Commissions = 2, - - [System.Runtime.Serialization.EnumMember(Value = @"interestsGeneric")] - InterestsGeneric = 3, - - [System.Runtime.Serialization.EnumMember(Value = @"other")] - Other = 4, - - [System.Runtime.Serialization.EnumMember(Value = @"accountClosing")] - AccountClosing = 5, - - [System.Runtime.Serialization.EnumMember(Value = @"notAvailable")] - NotAvailable = 6, - - [System.Runtime.Serialization.EnumMember(Value = @"sweeping")] - Sweeping = 7, - - [System.Runtime.Serialization.EnumMember(Value = @"topping")] - Topping = 8, - - [System.Runtime.Serialization.EnumMember(Value = @"zeroBalancing")] - ZeroBalancing = 9, - - [System.Runtime.Serialization.EnumMember(Value = @"cashWithdrawal")] - CashWithdrawal = 10, - - [System.Runtime.Serialization.EnumMember(Value = @"debitCardPayment")] - DebitCardPayment = 11, - - [System.Runtime.Serialization.EnumMember(Value = @"crossBorderCashWithdrawal")] - CrossBorderCashWithdrawal = 12, - - [System.Runtime.Serialization.EnumMember(Value = @"cashDeposit")] - CashDeposit = 13, - - [System.Runtime.Serialization.EnumMember(Value = @"debitAdjustmentGeneric")] - DebitAdjustmentGeneric = 14, - - [System.Runtime.Serialization.EnumMember(Value = @"travellersChequesDeposit")] - TravellersChequesDeposit = 15, - - [System.Runtime.Serialization.EnumMember(Value = @"settlementAtMaturity")] - SettlementAtMaturity = 16, - - [System.Runtime.Serialization.EnumMember(Value = @"intraCompanyTransfer")] - IntraCompanyTransfer = 17, - - [System.Runtime.Serialization.EnumMember(Value = @"corporateOwnAccountTransfer")] - CorporateOwnAccountTransfer = 18, - - [System.Runtime.Serialization.EnumMember(Value = @"crossBorderIntraCompanyTransfer")] - CrossBorderIntraCompanyTransfer = 19, - - [System.Runtime.Serialization.EnumMember(Value = @"achDebit")] - AchDebit = 20, - - [System.Runtime.Serialization.EnumMember(Value = @"achReturn")] - AchReturn = 21, - - [System.Runtime.Serialization.EnumMember(Value = @"achTransactionAtxn")] - AchTransactionAtxn = 22, - - [System.Runtime.Serialization.EnumMember(Value = @"automaticTransfer")] - AutomaticTransfer = 23, - - [System.Runtime.Serialization.EnumMember(Value = @"bankCheque")] - BankCheque = 24, - - [System.Runtime.Serialization.EnumMember(Value = @"booked")] - Booked = 25, - - [System.Runtime.Serialization.EnumMember(Value = @"domesticCreditTransfer")] - DomesticCreditTransfer = 26, - - [System.Runtime.Serialization.EnumMember(Value = @"dividend")] - Dividend = 27, - - [System.Runtime.Serialization.EnumMember(Value = @"sepaCreditTransfer")] - SepaCreditTransfer = 28, - - [System.Runtime.Serialization.EnumMember(Value = @"financialInstitutionCreditTransfer")] - FinancialInstitutionCreditTransfer = 29, - - [System.Runtime.Serialization.EnumMember(Value = @"principalPayment")] - PrincipalPayment = 30, - - [System.Runtime.Serialization.EnumMember(Value = @"priorityCreditTransfer")] - PriorityCreditTransfer = 31, - - [System.Runtime.Serialization.EnumMember(Value = @"reversalDueToPaymentReturn")] - ReversalDueToPaymentReturn = 32, - - [System.Runtime.Serialization.EnumMember(Value = @"achTransactionSala")] - AchTransactionSala = 33, - - [System.Runtime.Serialization.EnumMember(Value = @"sameDayValueCreditTransfer")] - SameDayValueCreditTransfer = 34, - - [System.Runtime.Serialization.EnumMember(Value = @"standingOrder")] - StandingOrder = 35, - - [System.Runtime.Serialization.EnumMember(Value = @"taxes")] - Taxes = 36, - - [System.Runtime.Serialization.EnumMember(Value = @"creditTransferWithAgreedCommercialInformation")] - CreditTransferWithAgreedCommercialInformation = 37, - - [System.Runtime.Serialization.EnumMember(Value = @"crossBorderCreditTransfer")] - CrossBorderCreditTransfer = 38, - - [System.Runtime.Serialization.EnumMember(Value = @"cashLetter")] - CashLetter = 39, - - [System.Runtime.Serialization.EnumMember(Value = @"cheques")] - Cheques = 40, - - [System.Runtime.Serialization.EnumMember(Value = @"chequesReversal")] - ChequesReversal = 41, - - [System.Runtime.Serialization.EnumMember(Value = @"openCheque")] - OpenCheque = 42, - - [System.Runtime.Serialization.EnumMember(Value = @"unpaidCheque")] - UnpaidCheque = 43, - - [System.Runtime.Serialization.EnumMember(Value = @"crossBorderCheque")] - CrossBorderCheque = 44, - - [System.Runtime.Serialization.EnumMember(Value = @"sepaCoreDirectDebit")] - SepaCoreDirectDebit = 45, - - [System.Runtime.Serialization.EnumMember(Value = @"directDebitPayment")] - DirectDebitPayment = 46, - - [System.Runtime.Serialization.EnumMember(Value = @"reversalDueToPayment")] - ReversalDueToPayment = 47, - - [System.Runtime.Serialization.EnumMember(Value = @"reversalDueToPaymentCancellationRequest")] - ReversalDueToPaymentCancellationRequest = 48, - - [System.Runtime.Serialization.EnumMember(Value = @"reversalDueToReturnUnpaidDirectDebit")] - ReversalDueToReturnUnpaidDirectDebit = 49, - - [System.Runtime.Serialization.EnumMember(Value = @"debit")] - Debit = 50, - - [System.Runtime.Serialization.EnumMember(Value = @"deposit")] - Deposit = 51, - - [System.Runtime.Serialization.EnumMember(Value = @"adjustments")] - Adjustments = 52, - - [System.Runtime.Serialization.EnumMember(Value = @"fees")] - Fees = 53, - - [System.Runtime.Serialization.EnumMember(Value = @"creditCardPayment")] - CreditCardPayment = 54, - - [System.Runtime.Serialization.EnumMember(Value = @"pointOfSalePosPayment")] - PointOfSalePosPayment = 55, - - [System.Runtime.Serialization.EnumMember(Value = @"creditAdjustment")] - CreditAdjustment = 56, - - [System.Runtime.Serialization.EnumMember(Value = @"settlementAfterCollection")] - SettlementAfterCollection = 57, - } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.3.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] public partial class Transaction { [Newtonsoft.Json.JsonProperty("transactionIdentifier")] - [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = false)] public string TransactionIdentifier { get; set; } - [Newtonsoft.Json.JsonProperty("references", NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public System.Collections.Generic.ICollection References { get; set; } - - [Newtonsoft.Json.JsonProperty("creditDebitIndicator", NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [Newtonsoft.Json.JsonProperty("creditDebitIndicator", Required = Newtonsoft.Json.Required.Always, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] public CreditOrDebit CreditDebitIndicator { get; set; } - [Newtonsoft.Json.JsonProperty("reversalIndicator", NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public bool ReversalIndicator { get; set; } - - [Newtonsoft.Json.JsonProperty("status", NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] - public TransactionStatus Status { get; set; } - [Newtonsoft.Json.JsonProperty("transactionCode", NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] public BankTransactionCode TransactionCode { get; set; } - [Newtonsoft.Json.JsonProperty("bookingDate", NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public System.DateTimeOffset BookingDate { get; set; } - - [Newtonsoft.Json.JsonProperty("valueDate", NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public System.DateTimeOffset ValueDate { get; set; } - [Newtonsoft.Json.JsonProperty("counterParties", NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] public System.Collections.Generic.ICollection CounterParties { get; set; } [Newtonsoft.Json.JsonProperty("additionalInfo", NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - [System.ComponentModel.DataAnnotations.StringLength(500, MinimumLength = 1)] + [System.ComponentModel.DataAnnotations.StringLength(500)] public string AdditionalInfo { get; set; } - [Newtonsoft.Json.JsonProperty("currencyExchange", NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public CurrencyExchange CurrencyExchange { get; set; } - [Newtonsoft.Json.JsonProperty("merchant", NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] [System.ComponentModel.DataAnnotations.StringLength(140, MinimumLength = 1)] public string Merchant { get; set; } - [Newtonsoft.Json.JsonProperty("paymentCard", NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - public PaymentCard PaymentCard { get; set; } - - [Newtonsoft.Json.JsonProperty("registered", NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [Newtonsoft.Json.JsonProperty("registered", Required = Newtonsoft.Json.Required.Always, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] public System.DateTimeOffset Registered { get; set; } - [Newtonsoft.Json.JsonProperty("amount", NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [Newtonsoft.Json.JsonProperty("amount", Required = Newtonsoft.Json.Required.Always, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] [System.ComponentModel.DataAnnotations.Range(0D, double.MaxValue)] public double Amount { get; set; } - - [Newtonsoft.Json.JsonProperty("currency", NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] - [System.ComponentModel.DataAnnotations.RegularExpression(@"[A-Z]{3,3}")] - public string Currency { get; set; } - - private System.Collections.Generic.IDictionary _additionalProperties; - - [Newtonsoft.Json.JsonExtensionData] - public System.Collections.Generic.IDictionary AdditionalProperties - { - get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } - set { _additionalProperties = value; } - } - - } - - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.3.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class TransactionReference - { - [Newtonsoft.Json.JsonProperty("value", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] - public string Value { get; set; } - - [Newtonsoft.Json.JsonProperty("type", Required = Newtonsoft.Json.Required.Always)] - [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] - [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] - public TransactionReferenceType Type { get; set; } - - private System.Collections.Generic.IDictionary _additionalProperties; - - [Newtonsoft.Json.JsonExtensionData] - public System.Collections.Generic.IDictionary AdditionalProperties - { - get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } - set { _additionalProperties = value; } - } - } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.3.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] @@ -2405,21 +1414,6 @@ public enum TransactionReferenceType } - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.3.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] - public enum TransactionStatus - { - - [System.Runtime.Serialization.EnumMember(Value = @"booked")] - Booked = 0, - - [System.Runtime.Serialization.EnumMember(Value = @"pending")] - Pending = 1, - - [System.Runtime.Serialization.EnumMember(Value = @"info")] - Info = 2, - - } - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.3.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] public partial class Transactions { @@ -2432,16 +1426,6 @@ public partial class Transactions [Newtonsoft.Json.JsonProperty("links", NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] public System.Collections.Generic.ICollection Links { get; set; } - - private System.Collections.Generic.IDictionary _additionalProperties; - - [Newtonsoft.Json.JsonExtensionData] - public System.Collections.Generic.IDictionary AdditionalProperties - { - get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } - set { _additionalProperties = value; } - } - } /// @@ -2461,16 +1445,6 @@ public partial class Error400 /// [Newtonsoft.Json.JsonProperty("message", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] public string Message { get; set; } - - private System.Collections.Generic.IDictionary _additionalProperties; - - [Newtonsoft.Json.JsonExtensionData] - public System.Collections.Generic.IDictionary AdditionalProperties - { - get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } - set { _additionalProperties = value; } - } - } /// @@ -2490,16 +1464,6 @@ public partial class Error401 /// [Newtonsoft.Json.JsonProperty("message", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] public string Message { get; set; } - - private System.Collections.Generic.IDictionary _additionalProperties; - - [Newtonsoft.Json.JsonExtensionData] - public System.Collections.Generic.IDictionary AdditionalProperties - { - get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } - set { _additionalProperties = value; } - } - } /// @@ -2519,16 +1483,6 @@ public partial class Error403 /// [Newtonsoft.Json.JsonProperty("message", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] public string Message { get; set; } - - private System.Collections.Generic.IDictionary _additionalProperties; - - [Newtonsoft.Json.JsonExtensionData] - public System.Collections.Generic.IDictionary AdditionalProperties - { - get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } - set { _additionalProperties = value; } - } - } /// @@ -2548,16 +1502,6 @@ public partial class Error404 /// [Newtonsoft.Json.JsonProperty("message", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] public string Message { get; set; } - - private System.Collections.Generic.IDictionary _additionalProperties; - - [Newtonsoft.Json.JsonExtensionData] - public System.Collections.Generic.IDictionary AdditionalProperties - { - get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } - set { _additionalProperties = value; } - } - } /// @@ -2577,16 +1521,6 @@ public partial class Error405 /// [Newtonsoft.Json.JsonProperty("message", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] public string Message { get; set; } - - private System.Collections.Generic.IDictionary _additionalProperties; - - [Newtonsoft.Json.JsonExtensionData] - public System.Collections.Generic.IDictionary AdditionalProperties - { - get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } - set { _additionalProperties = value; } - } - } /// @@ -2606,16 +1540,6 @@ public partial class Error406 /// [Newtonsoft.Json.JsonProperty("message", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] public string Message { get; set; } - - private System.Collections.Generic.IDictionary _additionalProperties; - - [Newtonsoft.Json.JsonExtensionData] - public System.Collections.Generic.IDictionary AdditionalProperties - { - get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } - set { _additionalProperties = value; } - } - } /// @@ -2635,16 +1559,6 @@ public partial class Error429 /// [Newtonsoft.Json.JsonProperty("message", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] public string Message { get; set; } - - private System.Collections.Generic.IDictionary _additionalProperties; - - [Newtonsoft.Json.JsonExtensionData] - public System.Collections.Generic.IDictionary AdditionalProperties - { - get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } - set { _additionalProperties = value; } - } - } /// @@ -2664,16 +1578,6 @@ public partial class Error500 /// [Newtonsoft.Json.JsonProperty("message", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] public string Message { get; set; } - - private System.Collections.Generic.IDictionary _additionalProperties; - - [Newtonsoft.Json.JsonExtensionData] - public System.Collections.Generic.IDictionary AdditionalProperties - { - get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } - set { _additionalProperties = value; } - } - } /// @@ -2693,16 +1597,6 @@ public partial class Error /// [Newtonsoft.Json.JsonProperty("message", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] public string Message { get; set; } - - private System.Collections.Generic.IDictionary _additionalProperties; - - [Newtonsoft.Json.JsonExtensionData] - public System.Collections.Generic.IDictionary AdditionalProperties - { - get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary()); } - set { _additionalProperties = value; } - } - } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.3.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] diff --git a/src/Altinn.Dan.Plugin.Banking/Extensions/AccountExtensions.cs b/src/Altinn.Dan.Plugin.Banking/Extensions/AccountExtensions.cs new file mode 100644 index 0000000..fb6fd34 --- /dev/null +++ b/src/Altinn.Dan.Plugin.Banking/Extensions/AccountExtensions.cs @@ -0,0 +1,36 @@ +using Altinn.Dan.Plugin.Banking.Clients.V2; +using Altinn.Dan.Plugin.Banking.Services; +using Microsoft.Extensions.Logging; +using System; + +namespace Altinn.Dan.Plugin.Banking.Extensions +{ + public static class AccountExtensions + { + public static void LogGetAccountByIdError( + this Account account, + ILogger logger, + Exception e, + BankConfig bank, + Guid accountInfoRequestId) + { + string correlationId = null, innerExceptionMsg = null; + if (e is ApiException k) + { + correlationId = k.CorrelationId; + innerExceptionMsg = k.InnerException?.Message; + } + + logger.LogError("GetAccountById failed while processing account {Account} for {Bank} ({OrgNo}) for {Subject}, error {Error}, accountInfoRequestId: {AccountInfoRequestId}, CorrelationId: {CorrelationId}, source: {source}, innerExceptionMessage: {innerExceptionMessage}", + account.AccountReference, + bank.Name, + bank.OrgNo, + account?.PrimaryOwner?.Identifier?.Value[..6], + e.Message, + accountInfoRequestId, + correlationId, + e.Source, + innerExceptionMsg); + } + } +} diff --git a/src/Altinn.Dan.Plugin.Banking/Models/BankResponse.cs b/src/Altinn.Dan.Plugin.Banking/Models/BankResponse.cs index d68f1e3..4a4b7bd 100644 --- a/src/Altinn.Dan.Plugin.Banking/Models/BankResponse.cs +++ b/src/Altinn.Dan.Plugin.Banking/Models/BankResponse.cs @@ -52,6 +52,7 @@ public class Account public class AccountV2 { + public bool HasErrors { get; set; } public string AccountNumber { get; set; } // Seperate property by now. Copy of AccountDetail.AccountIdentifier public AccountDetailV2 AccountDetail { get; set; } // Not mapped to internal by now public ICollection Transactions { get; set; } // Not mapped to internal by now diff --git a/src/Altinn.Dan.Plugin.Banking/Services/BankService.cs b/src/Altinn.Dan.Plugin.Banking/Services/BankService.cs index 7542ce8..40aa348 100644 --- a/src/Altinn.Dan.Plugin.Banking/Services/BankService.cs +++ b/src/Altinn.Dan.Plugin.Banking/Services/BankService.cs @@ -1,6 +1,7 @@ using Altinn.ApiClients.Maskinporten.Interfaces; using Altinn.Dan.Plugin.Banking.Clients.V2; using Altinn.Dan.Plugin.Banking.Config; +using Altinn.Dan.Plugin.Banking.Extensions; using Altinn.Dan.Plugin.Banking.Models; using Altinn.Dan.Plugin.Banking.Services.Interfaces; using Microsoft.Extensions.Logging; @@ -52,13 +53,15 @@ public async Task GetAccounts(string ssn, Dictionary GetAccountDetailsV2(Bank_v2.Bank_v2 bankClient, Acc var bankInfo = new BankInfo() { Accounts = [] }; var transactions = new Transactions(); - IEnumerable> accountsDetailsTasks = accounts.Accounts1.Select(x => GetAccountById(bankClient, x, bank, accountInfoRequestId, fromDate, toDate)); - AccountDetails[] accountsDetails = await Task.WhenAll(accountsDetailsTasks); - foreach (var accountDetails in accountsDetails) + Task[] accountsDetailsTasks = accounts.Accounts1.Select(x => GetAccountById(bankClient, x, bank, accountInfoRequestId, fromDate, toDate)).ToArray(); + var results = Task.WhenAll(accountsDetailsTasks); + try { - if (accountDetails.Account == null) continue; - - var availableCredit = accountDetails.Account.Balances.FirstOrDefault(b => - b.Type == BalanceType.AvailableBalance && b.CreditDebitIndicator == CreditOrDebit.Credit) - ?.Amount ?? 0; - var availableDebit = accountDetails.Account.Balances.FirstOrDefault(b => - b.Type == BalanceType.AvailableBalance && b.CreditDebitIndicator == CreditOrDebit.Debit) - ?.Amount ?? 0; - - var bookedCredit = accountDetails.Account.Balances.FirstOrDefault(b => - b.Type == BalanceType.BookedBalance && b.CreditDebitIndicator == CreditOrDebit.Credit) - ?.Amount ?? 0; - var bookedDebit = accountDetails.Account.Balances.FirstOrDefault(b => - b.Type == BalanceType.BookedBalance && b.CreditDebitIndicator == CreditOrDebit.Debit) - ?.Amount ?? 0; - - if (includeTransactions) + AccountDetails[] accountsDetails = await results; + foreach (var accountDetails in accountsDetails) { - transactions = await ListTransactionsForAccount(bankClient, accountDetails, bank, accountInfoRequestId, fromDate, toDate); - } + if (accountDetails.Account == null) continue; + + var availableCredit = accountDetails.Account.Balances.FirstOrDefault(b => + b.Type == BalanceType.AvailableBalance && b.CreditDebitIndicator == CreditOrDebit.Credit) + ?.Amount ?? 0; + var availableDebit = accountDetails.Account.Balances.FirstOrDefault(b => + b.Type == BalanceType.AvailableBalance && b.CreditDebitIndicator == CreditOrDebit.Debit) + ?.Amount ?? 0; + + var bookedCredit = accountDetails.Account.Balances.FirstOrDefault(b => + b.Type == BalanceType.BookedBalance && b.CreditDebitIndicator == CreditOrDebit.Credit) + ?.Amount ?? 0; + var bookedDebit = accountDetails.Account.Balances.FirstOrDefault(b => + b.Type == BalanceType.BookedBalance && b.CreditDebitIndicator == CreditOrDebit.Debit) + ?.Amount ?? 0; + + if (includeTransactions) + { + transactions = await ListTransactionsForAccount(bankClient, accountDetails, bank, accountInfoRequestId, fromDate, toDate); + } - var internalAccount = MapToInternalV2(accountDetails, accountDetails.Account, transactions?.Transactions1, availableCredit - availableDebit, bookedCredit - bookedDebit); - if (internalAccount.AccountDetail != null) + var internalAccount = MapToInternalV2(accountDetails, accountDetails.Account, transactions?.Transactions1, availableCredit - availableDebit, bookedCredit - bookedDebit); + if (internalAccount.AccountDetail != null) + { + bankInfo.Accounts.Add(internalAccount); + } + } + } + catch (Exception e) + { + if (e is ApiException k && k.StatusCode >= 400) { - bankInfo.Accounts.Add(internalAccount); + var successfulTasks = accountsDetailsTasks.Where(x => x.IsCompletedSuccessfully).ToArray(); + var successfulAccounts = await Task.WhenAll(successfulTasks); + var faultedAccounts = accounts.Accounts1.Where(x => !successfulAccounts.Any(y => y.Account.AccountReference == x.AccountReference)).ToList(); + + foreach (var faultedAccount in faultedAccounts) + { + faultedAccount.LogGetAccountByIdError(_logger, k, bank, accountInfoRequestId); + bankInfo.Accounts.Add(new AccountDtoV2 + { + AccountAvailableBalance = 0, + AccountBookedBalance = 0, + AccountDetail = new AccountDetail + { + Balances = null, + PrimaryOwner = faultedAccount.PrimaryOwner, + Servicer = faultedAccount.Servicer, + Status = faultedAccount.Status, + AccountIdentifier = faultedAccount.AccountIdentifier, + AccountReference = faultedAccount.AccountReference, + Type = faultedAccount.Type + }, + AccountNumber = faultedAccount.AccountIdentifier, + Transactions = null, + HasErrors = true + }); + } } + + /* + * TODO: + * Will rethrow if a non-API exception is thrown. + * A bank returns 200 OK Internal Server Error now, which is wrong. + * It will then rethrow the exception + */ + throw; } return bankInfo; @@ -172,25 +219,6 @@ private async Task GetAccountById(Bank_v2.Bank_v2 bankClient, Ba return details; } - private async Task ListTransactionsForAccount(Bank_v2.Bank_v2 bankClient, Bank_v2.Account account, BankConfig bank, Guid accountInfoRequestId, DateTimeOffset? fromDate, DateTimeOffset? toDate) - { - 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 async Task ListTransactionsForAccount(Bank_v2.Bank_v2 bankClient, AccountDetails accountDetails, BankConfig bank, Guid accountInfoRequestId, DateTimeOffset? fromDate, DateTimeOffset? toDate) { var account = accountDetails.Account; @@ -211,96 +239,6 @@ private async Task ListTransactionsForAccount(Bank_v2.Bank_v2 bank return transactions; } - /*private AccountDto MapFromAccountDTOV2TOV1(AccountDtoV2 result) - { - var a = new AccountDto() - { - AccountAvailableBalance = result.AccountAvailableBalance, - AccountBookedBalance = result.AccountBookedBalance, - AccountDetail = new AccountDetail() - { - Name = result.AccountDetail.Name, - AccountIdentifier = result.AccountDetail.AccountIdentifier, - AccountReference = result.AccountDetail.AccountReference, - AdditionalProperties = result.AccountDetail.AdditionalProperties, - Balances = new List(), - Currency = result.AccountDetail.Currency, - EndDate = result.AccountDetail.EndDate, - PrimaryOwner = new AccountRole() - { - Name = result.AccountDetail.PrimaryOwner.Name, - StartDate = result.AccountDetail.PrimaryOwner.StartDate, - EndDate = result.AccountDetail.PrimaryOwner.EndDate, - Identifier = new Identifier() - { - Value = result.AccountDetail.PrimaryOwner.Identifier.Value, - Type = result.AccountDetail.PrimaryOwner.Identifier.Type == Bank_v2.IdentifierType.CountryIdentificationCode ? IdentifierType.CountryIdentificationCode : IdentifierType.NationalIdentityNumber, - CountryOfResidence = result.AccountDetail.PrimaryOwner.Identifier.CountryOfResidence, - AdditionalProperties = result.AccountDetail.PrimaryOwner.Identifier.AdditionalProperties - }, - AdditionalProperties = result.AccountDetail.PrimaryOwner.AdditionalProperties, - ElectronicAddresses = new List(), - PostalAddress = new PostalAddress() - }, - Servicer = new FinancialInstitution() - { - AdditionalProperties = result.AccountDetail.Servicer.AdditionalProperties, - Identifier = new Identifier() - { - Value = result.AccountDetail.Servicer.Identifier.Value, - Type = (IdentifierType) result.AccountDetail.Servicer.Identifier.Type, - CountryOfResidence = result.AccountDetail.Servicer.Identifier.CountryOfResidence, - AdditionalProperties = result.AccountDetail.Servicer.Identifier.AdditionalProperties - }, - Name = result.AccountDetail.Servicer.Name - }, - StartDate = result.AccountDetail.StartDate, - Status = (AccountStatus) result.AccountDetail.Status, - Type = (AccountType) result.AccountDetail.Type, - } - }; - - foreach (var accountDetailBalance in result.AccountDetail.Balances) - { - a.AccountDetail.Balances.Add( - new Balance() - { - Currency = accountDetailBalance.Currency, - CreditDebitIndicator = accountDetailBalance.CreditDebitIndicator == Bank_v2.CreditOrDebit.Credit ? CreditOrDebit.Credit : CreditOrDebit.Debit, - Type = accountDetailBalance.Type == Bank_v2.BalanceType.AvailableBalance ? BalanceType.AvailableBalance : BalanceType.BookedBalance, - Amount = accountDetailBalance.Amount, - AdditionalProperties = accountDetailBalance.AdditionalProperties, - CreditLineAmount = accountDetailBalance.CreditLineAmount, - Registered = accountDetailBalance.Registered, - CreditLineCurrency = accountDetailBalance.CreditLineCurrency, - CreditLineIncluded = accountDetailBalance.CreditLineIncluded - }); - } - return a; - } */ - - private AccountDtoV2 MapToInternalV2( - Bank_v2.Account account, - AccountDetail detail, - ICollection transactions, - decimal availableBalance, - decimal bookedBalance) - { - 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 - }; - } - private AccountDtoV2 MapToInternalV2( AccountDetails accountDetails, AccountDetail detail, @@ -341,7 +279,23 @@ public async Task GetTransactionsForAccount(string ssn, BankConfig BaseUrl = bankConfig.Client.BaseAddress?.ToString(), DecryptionCertificate = _settings.OedDecryptCert }; - var transactions = await bankClient.ListTransactionsAsync(accountReference, accountInfoRequestId, correlationId, "OED", null, null, null, fromDate, toDate, transactionsTimeout.Token); + Transactions transactions = null; + try + { + transactions = await bankClient.ListTransactionsAsync(accountReference, accountInfoRequestId, correlationId, "OED", null, null, null, fromDate, toDate, transactionsTimeout.Token); + } + catch (Exception e) + { + string innerExceptionMsg = string.Empty; + if (e is ApiException k) + { + innerExceptionMsg = k.InnerException?.Message; + } + _logger.LogError( + "GetTransactionsForAccount failed while processing bank {Bank} ({OrgNo}) for {Subject}, error {Error}, accountInfoRequestId: {AccountInfoRequestId}, CorrelationId: {CorrelationId}, source: {source}, innerExceptionMessage: {innerExceptionMessage})", + bankConfig.Name, bankConfig.OrgNo, ssn[..6], e.Message, accountInfoRequestId, correlationId, e.Source, innerExceptionMsg); + throw; + } _logger.LogInformation("Retrieved transactions: bank {BankName} accountrefence {AccountReference} dob {DateOfBirth} accountinforequestid {AccountInfoRequestId} correlationid {CorrelationId}", bankConfig.Name, accountReference, ssn[..6], accountInfoRequestId, correlationId); diff --git a/test/Altinn.Dan.Plugin.Banking.Test/Altinn.Dan.Plugin.Banking.Test.csproj b/test/Altinn.Dan.Plugin.Banking.Test/Altinn.Dan.Plugin.Banking.Test.csproj index 0d816ea..094a4be 100644 --- a/test/Altinn.Dan.Plugin.Banking.Test/Altinn.Dan.Plugin.Banking.Test.csproj +++ b/test/Altinn.Dan.Plugin.Banking.Test/Altinn.Dan.Plugin.Banking.Test.csproj @@ -1,13 +1,14 @@ - net6.0 + net8.0 enable false + @@ -17,4 +18,8 @@ + + + + diff --git a/test/Altinn.Dan.Plugin.Banking.Test/FakeableHttpMessageHandler.cs b/test/Altinn.Dan.Plugin.Banking.Test/FakeableHttpMessageHandler.cs new file mode 100644 index 0000000..1eaf23a --- /dev/null +++ b/test/Altinn.Dan.Plugin.Banking.Test/FakeableHttpMessageHandler.cs @@ -0,0 +1,39 @@ +using System; +using System.Net.Http; +using System.Security.Cryptography.X509Certificates; +using System.Security.Cryptography; +using System.Threading; +using System.Threading.Tasks; + +namespace Altinn.Dan.Plugin.Banking.Test +{ + public abstract class FakeableHttpMessageHandler : HttpMessageHandler + { + public abstract Task FakeSendAsync( + HttpRequestMessage request, CancellationToken cancellationToken); + + // sealed so FakeItEasy won't intercept calls to this method + protected sealed override Task SendAsync( + HttpRequestMessage request, CancellationToken cancellationToken) + => this.FakeSendAsync(request, cancellationToken); + } + + public static class CertificateGenerator + { + public static X509Certificate2 GenerateSelfSignedCertificate() + { + string subjectName = "Self-Signed-Cert-Example"; + using var rsa = RSA.Create(2048); + var certRequest = new CertificateRequest($"CN={subjectName}", rsa, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1); + + // Add extensions to the request (just as an example) + // Add keyUsage + certRequest.CertificateExtensions.Add(new X509KeyUsageExtension(X509KeyUsageFlags.DigitalSignature, true)); + X509Certificate2 generatedCert = certRequest.CreateSelfSigned(DateTimeOffset.Now.AddDays(-1), DateTimeOffset.Now.AddYears(10)); // generate the cert and sign! + + X509Certificate2 pfxGeneratedCert = new X509Certificate2(generatedCert.Export(X509ContentType.Pfx)); // has to be turned into pfx or Windows at least throws a security credentials not found during sslStream.connectAsClient or HttpClient request... + + return pfxGeneratedCert; + } + } +} diff --git a/test/Altinn.Dan.Plugin.Banking.Test/Services/BankServiceTests.cs b/test/Altinn.Dan.Plugin.Banking.Test/Services/BankServiceTests.cs new file mode 100644 index 0000000..d83f00f --- /dev/null +++ b/test/Altinn.Dan.Plugin.Banking.Test/Services/BankServiceTests.cs @@ -0,0 +1,267 @@ +using Altinn.ApiClients.Maskinporten.Interfaces; +using Altinn.ApiClients.Maskinporten.Models; +using Altinn.Dan.Plugin.Banking.Clients.V2; +using Altinn.Dan.Plugin.Banking.Config; +using Altinn.Dan.Plugin.Banking.Services; +using FakeItEasy; +using Jose; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net; +using System.Net.Http; +using System.Net.Http.Headers; +using System.Security.Cryptography.X509Certificates; +using System.Text; +using System.Threading; +using System.Threading.Tasks; + +namespace Altinn.Dan.Plugin.Banking.Test.Services +{ + [TestClass] + public class BankServiceTests + { + private readonly X509Certificate2 _certificate; + private readonly IOptions _fakeOptions; + private readonly FakeableHttpMessageHandler _handler; + private readonly HttpClient _client; + private readonly ILoggerFactory _fakeLogger; + private readonly IMaskinportenService _fakeMpService; + + public BankServiceTests() + { + _fakeLogger = A.Fake(); + _fakeMpService = A.Fake(); + _fakeOptions = A.Fake>(); + _handler = A.Fake(); + _client = new HttpClient(_handler) + { + BaseAddress = new Uri("http://test.com") + }; + + A.CallTo(() => _fakeMpService.GetToken(A._, A._, A._, A._, A._, A._, A._)).Returns(new TokenResponse { AccessToken = "321" }); + _certificate = CertificateGenerator.GenerateSelfSignedCertificate(); + A.CallTo(() => _fakeOptions.Value).Returns(new ApplicationSettings { Jwk = "321", ClientId = "54345", BankScope = "somescope", OedDecryptCert = _certificate }); + } + + [TestMethod] + public async Task GetAccounts_Ok_Accounts() + { + // Arrange + var nin = "12345678901"; + var fromDate = DateTime.Now.AddMonths(-1); + var toDate = DateTime.Now; + var bankName = "bank1"; + var orgNumber = "789"; + var bankList = GetDefaultBankConfig(bankName, orgNumber); + + var accounts = GetDefaultAccounts(bankName, orgNumber); + var account1Details = GetAccountDetails(accounts.Accounts1.ElementAt(0)); + var account2Details = GetAccountDetails(accounts.Accounts1.ElementAt(1)); + FakeGetAccounts(accounts); + FakeGetAccountDetails(account1Details); + FakeGetAccountDetails(account2Details); + + var bankService = new BankService(_fakeLogger, _fakeMpService, _fakeOptions); + + // Act + var result = await bankService.GetAccounts(nin, bankList, fromDate, toDate, Guid.NewGuid(), false); + + // Assert + Assert.IsNotNull(result); + Assert.AreEqual(1, result.BankAccounts.Count); + Assert.IsFalse(result.BankAccounts.Single().HasErrors); + Assert.AreEqual(2, result.BankAccounts.Single().Accounts.Count); + } + + [TestMethod] + public async Task GetAccounts_InternalServerError_BankHasErrors() + { + // Arrange + var nin = "12345678901"; + var fromDate = DateTime.Now.AddMonths(-1); + var toDate = DateTime.Now; + var bankName = "bank1"; + var orgNumber = "789"; + var bankList = GetDefaultBankConfig(bankName, orgNumber); + + var accounts = GetDefaultAccounts(bankName, orgNumber); + FakeGetAccounts(accounts, HttpStatusCode.InternalServerError); + + var bankService = new BankService(_fakeLogger, _fakeMpService, _fakeOptions); + + // Act + var result = await bankService.GetAccounts(nin, bankList, fromDate, toDate, Guid.NewGuid(), false); + + // Assert + Assert.IsNotNull(result); + Assert.AreEqual(1, result.BankAccounts.Count); + Assert.IsTrue(result.BankAccounts.Single().HasErrors); + Assert.AreEqual(0, result.BankAccounts.Single().Accounts.Count); + Assert.AreEqual(bankName, result.BankAccounts.Single().BankName); + } + + [TestMethod] + public async Task GetAccounts_GetAccountDetailsInternalServerError_AccountHasErrors() + { + // Arrange + var nin = "12345678901"; + var fromDate = DateTime.Now.AddMonths(-1); + var toDate = DateTime.Now; + var bankName = "bank1"; + var orgNumber = "789"; + var bankList = GetDefaultBankConfig(bankName, orgNumber); + + var accounts = GetDefaultAccounts(bankName, orgNumber); + accounts.Accounts1.Add(GetAccount(bankName, orgNumber, "3")); + var account1Details = GetAccountDetails(accounts.Accounts1.ElementAt(0)); + var account2Details = GetAccountDetails(accounts.Accounts1.ElementAt(1)); + var account3Details = GetAccountDetails(accounts.Accounts1.ElementAt(2)); + FakeGetAccounts(accounts); + FakeGetAccountDetails(account1Details); + FakeGetAccountDetails(account2Details, HttpStatusCode.InternalServerError); + FakeGetAccountDetails(account3Details, HttpStatusCode.InternalServerError); + + var bankService = new BankService(_fakeLogger, _fakeMpService, _fakeOptions); + + // Act + var result = await bankService.GetAccounts(nin, bankList, fromDate, toDate, Guid.NewGuid(), false); + + // Assert + Assert.IsNotNull(result); + Assert.AreEqual(1, result.BankAccounts.Count); + Assert.IsFalse(result.BankAccounts.Single().HasErrors); + Assert.AreEqual(2, result.BankAccounts.Single().Accounts.Count); + Assert.IsTrue(result.BankAccounts.Single().Accounts.Any(x => x.HasErrors)); + } + + private Dictionary GetDefaultBankConfig(string bankName, string orgNumber) + { + return new Dictionary + { + { + orgNumber, + new BankConfig + { + Name = bankName, + Client = _client, + MaskinportenEnv = "test1", + BankAudience = "someaudience" + } + } + }; + } + + private void FakeGetAccountDetails(AccountDetails accountDetails, HttpStatusCode httpStatusCode = HttpStatusCode.OK) + { + A.CallTo(() => _handler.FakeSendAsync(A.That.Matches(x => x.RequestUri != null && x.RequestUri.AbsoluteUri.Contains($"accounts/{accountDetails.Account.AccountReference}")), A._)) + .Returns(Task.FromResult(new HttpResponseMessage + { + StatusCode = httpStatusCode, + Content = new StringContent(JWT.Encode(JsonConvert.SerializeObject(accountDetails), _certificate.GetRSAPublicKey(), JweAlgorithm.RSA_OAEP_256, JweEncryption.A128CBC_HS256), Encoding.UTF8, new MediaTypeHeaderValue("application/json")) + })); + } + + private void FakeGetAccounts(Accounts accounts, HttpStatusCode httpStatusCode = HttpStatusCode.OK) + { + A.CallTo(() => _handler.FakeSendAsync(A._, A._)) + .Returns(Task.FromResult(new HttpResponseMessage + { + StatusCode = httpStatusCode, + Content = new StringContent(JWT.Encode(JsonConvert.SerializeObject(accounts), _certificate.GetRSAPublicKey(), JweAlgorithm.RSA_OAEP_256, JweEncryption.A128CBC_HS256), Encoding.UTF8, new MediaTypeHeaderValue("application/json")) + })) + .NumberOfTimes(1); + } + + private static AccountDetails GetAccountDetails(Account account) + { + return new AccountDetails + { + ResponseDetails = new ResponseDetails + { + Message = "OK", + Status = ResponseDetailsStatus.Complete, + }, + Account = new AccountDetail + { + AccountIdentifier = account.AccountIdentifier, + AccountReference = account.AccountReference, + PrimaryOwner = account.PrimaryOwner, + Status = account.Status, + Servicer = account.Servicer, + Type = account.Type, + Balances = new List + { + new Balance + { + CreditDebitIndicator = CreditOrDebit.Credit, + CreditLineAmount = 100, + CreditLineIncluded = true, + Amount = 100, + Currency = "NOK", + Type = BalanceType.AvailableBalance + }, + new Balance + { + CreditDebitIndicator = CreditOrDebit.Credit, + CreditLineAmount = 100, + CreditLineIncluded = true, + Amount = 100, + Currency = "NOK", + Type = BalanceType.AvailableBalance + } + } + }, + }; + } + + private static Accounts GetDefaultAccounts(string bankName, string orgNumber) + { + return new Accounts + { + ResponseDetails = new ResponseDetails + { + Message = "OK", + Status = ResponseDetailsStatus.Complete + }, + Accounts1 = + [ + GetAccount(bankName, orgNumber, "1"), + GetAccount(bankName, orgNumber, "2"), + ] + }; + } + + private static Account GetAccount(string bankName, string orgNumber, string accRef) + { + return new Account + { + AccountReference = accRef, + AccountIdentifier = "asdasdasd", + Type = AccountType.LoanAccount, + Status = AccountStatus.Enabled, + Servicer = new FinancialInstitution + { + Identifier = new Identifier + { + Type = IdentifierType.NationalIdentityNumber, + Value = orgNumber + }, + Name = bankName + }, + PrimaryOwner = new AccountRole + { + Identifier = new Identifier + { + Type = IdentifierType.NationalIdentityNumber, + Value = "12345678910" + } + } + }; + } + } +} diff --git a/test/Altinn.Dan.Plugin.Banking.Test/UnitTest1.cs b/test/Altinn.Dan.Plugin.Banking.Test/UnitTest1.cs deleted file mode 100644 index a6c2939..0000000 --- a/test/Altinn.Dan.Plugin.Banking.Test/UnitTest1.cs +++ /dev/null @@ -1,13 +0,0 @@ -using Microsoft.VisualStudio.TestTools.UnitTesting; - -namespace Altinn.Dan.Plugin.Banking.Test -{ - [TestClass] - public class UnitTest1 - { - [TestMethod] - public void TestMethod1() - { - } - } -}