feat(api): support passing and persistenting currency code for balances

This commit is contained in:
Stevan Freeborn
2026-02-14 06:44:37 -06:00
parent 15f05fc607
commit 5d65c25379
4 changed files with 21 additions and 6 deletions
+1 -4
View File
@@ -42,12 +42,9 @@ internal static class Endpoint
return Results.Conflict(); return Results.Conflict();
} }
// TODO: We need to get the initial balance
// of the account
var accountMetadata = PlaidAccountMetadata.From(request.PlaidAccountId, request.PlaidAccountName); var accountMetadata = PlaidAccountMetadata.From(request.PlaidAccountId, request.PlaidAccountName);
var account = Account.From(user.Institutions.First().Id, request.PlaidAccountName, accountMetadata); var account = Account.From(user.Institutions.First().Id, request.PlaidAccountName, accountMetadata);
var balance = Balance.From(request.AccountCurrentBalance, request.AccountAvailableBalance); var balance = Balance.From(request.AccountCurrentBalance, request.AccountAvailableBalance, request.AccountCurrencyCode);
account.AddBalance(balance); account.AddBalance(balance);
user.AddAccount(account); user.AddAccount(account);
+7
View File
@@ -7,6 +7,7 @@ public record Request : IValidatableObject
public string PlaidAccountName { get; init; } = string.Empty; public string PlaidAccountName { get; init; } = string.Empty;
public decimal AccountCurrentBalance { get; init; } public decimal AccountCurrentBalance { get; init; }
public decimal AccountAvailableBalance { get; init; } public decimal AccountAvailableBalance { get; init; }
public string AccountCurrencyCode { get; init; } = string.Empty;
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext) public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{ {
@@ -27,5 +28,11 @@ public record Request : IValidatableObject
var fieldName = nameof(PlaidAccountName); var fieldName = nameof(PlaidAccountName);
yield return new($"The {fieldName} field is required.", [fieldName]); yield return new($"The {fieldName} field is required.", [fieldName]);
} }
if (string.IsNullOrWhiteSpace(AccountCurrencyCode))
{
var fieldName = nameof(AccountCurrencyCode);
yield return new($"The {fieldName} field is required.", [fieldName]);
}
} }
} }
@@ -16,7 +16,7 @@ public class AddTests(TestApi testApi) : IntegrationTest(testApi)
} }
[Fact] [Fact]
public async Task Add_WhenCalledWithoutInstitutionIdOrAccountIdOrAccountName_ItShouldReturn400WithProblemDetails() public async Task Add_WhenCalledWithoutRequiredInformation_ItShouldReturn400WithProblemDetails()
{ {
using var request = HttpRequestBuilder.New() using var request = HttpRequestBuilder.New()
.Post(AddUri) .Post(AddUri)
@@ -31,6 +31,7 @@ public class AddTests(TestApi testApi) : IntegrationTest(testApi)
["PlaidInstitutionId"] = ["The PlaidInstitutionId field is required."], ["PlaidInstitutionId"] = ["The PlaidInstitutionId field is required."],
["PlaidAccountId"] = ["The PlaidAccountId field is required."], ["PlaidAccountId"] = ["The PlaidAccountId field is required."],
["PlaidAccountName"] = ["The PlaidAccountName field is required."], ["PlaidAccountName"] = ["The PlaidAccountName field is required."],
["AccountCurrencyCode"] = ["The AccountCurrencyCode field is required."],
}); });
} }
@@ -44,6 +45,7 @@ public class AddTests(TestApi testApi) : IntegrationTest(testApi)
{ {
plaidAccountId = "accountId", plaidAccountId = "accountId",
plaidAccountName = "Some Account", plaidAccountName = "Some Account",
accountCurrencyCode = "USD",
}) })
.Build(); .Build();
@@ -65,6 +67,7 @@ public class AddTests(TestApi testApi) : IntegrationTest(testApi)
{ {
plaidInstitutionId = "institutionId", plaidInstitutionId = "institutionId",
plaidAccountName = "Some Account", plaidAccountName = "Some Account",
accountCurrencyCode = "USD",
}) })
.Build(); .Build();
@@ -86,6 +89,7 @@ public class AddTests(TestApi testApi) : IntegrationTest(testApi)
{ {
plaidInstitutionId = "institutionId", plaidInstitutionId = "institutionId",
plaidAccountId = "accountId", plaidAccountId = "accountId",
accountCurrencyCode = "USD",
}) })
.Build(); .Build();
@@ -108,6 +112,7 @@ public class AddTests(TestApi testApi) : IntegrationTest(testApi)
plaidInstitutionId = "id", plaidInstitutionId = "id",
plaidAccountId = "id", plaidAccountId = "id",
plaidAccountName = "Some Account", plaidAccountName = "Some Account",
accountCurrencyCode = "USD",
}) })
.Build(); .Build();
@@ -141,6 +146,7 @@ public class AddTests(TestApi testApi) : IntegrationTest(testApi)
plaidInstitutionId = "id", plaidInstitutionId = "id",
plaidAccountId = "id", plaidAccountId = "id",
plaidAccountName = "Some Account", plaidAccountName = "Some Account",
accountCurrencyCode = "USD",
}) })
.Build(); .Build();
@@ -189,6 +195,7 @@ public class AddTests(TestApi testApi) : IntegrationTest(testApi)
plaidInstitutionId = ((PlaidMetadata)institution.Metadata!).PlaidId, plaidInstitutionId = ((PlaidMetadata)institution.Metadata!).PlaidId,
plaidAccountId = ((PlaidAccountMetadata)account.Metadata!).PlaidId, plaidAccountId = ((PlaidAccountMetadata)account.Metadata!).PlaidId,
plaidAccountName = ((PlaidAccountMetadata)account.Metadata).PlaidName, plaidAccountName = ((PlaidAccountMetadata)account.Metadata).PlaidName,
accountCurrencyCode = "USD",
}) })
.Build(); .Build();
@@ -223,6 +230,7 @@ public class AddTests(TestApi testApi) : IntegrationTest(testApi)
var newAccountId = "newAccountId"; var newAccountId = "newAccountId";
var newAccountName = "New Account"; var newAccountName = "New Account";
var expectedBalance = 100; var expectedBalance = 100;
var expectedCurrencyCode = "USD";
using var request = HttpRequestBuilder.New() using var request = HttpRequestBuilder.New()
.Post(AddUri) .Post(AddUri)
@@ -234,6 +242,7 @@ public class AddTests(TestApi testApi) : IntegrationTest(testApi)
plaidAccountName = newAccountName, plaidAccountName = newAccountName,
accountCurrentBalance = expectedBalance, accountCurrentBalance = expectedBalance,
accountAvailableBalance = expectedBalance, accountAvailableBalance = expectedBalance,
accountCurrencyCode = expectedCurrencyCode,
}) })
.Build(); .Build();
@@ -264,7 +273,8 @@ public class AddTests(TestApi testApi) : IntegrationTest(testApi)
.Balances.Should().ContainSingle( .Balances.Should().ContainSingle(
b => b.AccountId == updatedUser.Accounts.First().Id && b => b.AccountId == updatedUser.Accounts.First().Id &&
b.Current == expectedBalance && b.Current == expectedBalance &&
b.Available == expectedBalance b.Available == expectedBalance &&
b.CurrencyCode == expectedCurrencyCode
); );
} }
} }
@@ -10,6 +10,7 @@ public class GetAvailableTests(TestApi testApi) : IntegrationTest(testApi)
{ {
return new($"/institutions/{id}/available", UriKind.Relative); return new($"/institutions/{id}/available", UriKind.Relative);
} }
[Fact] [Fact]
public async Task GetAvailable_WhenCalledAndUnauthenticated_ItShouldReturn401WithProblemDetails() public async Task GetAvailable_WhenCalledAndUnauthenticated_ItShouldReturn401WithProblemDetails()
{ {