diff --git a/TransactionProcessor.BusinessLogic.Tests/Services/TransactionValidationServiceTests.cs b/TransactionProcessor.BusinessLogic.Tests/Services/TransactionValidationServiceTests.cs index 2048559..c57b2e2 100644 --- a/TransactionProcessor.BusinessLogic.Tests/Services/TransactionValidationServiceTests.cs +++ b/TransactionProcessor.BusinessLogic.Tests/Services/TransactionValidationServiceTests.cs @@ -26,7 +26,6 @@ namespace TransactionProcessor.BusinessLogic.Tests.Services; public class TransactionValidationServiceTests { private readonly TransactionValidationService TransactionValidationService; private readonly Mock SecurityServiceClient; - private readonly Mock EventStoreContext; private readonly Mock AggregateService; public TransactionValidationServiceTests() { IConfigurationRoot configurationRoot = new ConfigurationBuilder().AddInMemoryCollection(TestData.DefaultAppSettings).Build(); @@ -35,12 +34,11 @@ public TransactionValidationServiceTests() { Logger.Initialise(NullLogger.Instance); this.SecurityServiceClient = new Mock(); - this.EventStoreContext = new Mock(); this.AggregateService = new Mock(); this.SecurityServiceClient.Setup(s => s.GetToken(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(Result.Success(TestData.TokenResponse())); - this.TransactionValidationService = new TransactionValidationService(this.EventStoreContext.Object, this.AggregateService.Object); + this.TransactionValidationService = new TransactionValidationService(this.AggregateService.Object); } [Fact] @@ -403,9 +401,6 @@ public async Task TransactionValidationService_ValidateSaleTransaction_InvalidCo this.AggregateService.Setup(e => e.Get(It.IsAny(), It.IsAny())) .ReturnsAsync(TestData.Aggregates.MerchantAggregateWithEverything(SettlementSchedule.Immediate)); - this.EventStoreContext.Setup(e => e.GetPartitionStateFromProjection(It.IsAny(), It.IsAny(), It.IsAny())) - .ReturnsAsync(JsonConvert.SerializeObject(TestData.MerchantBalanceProjectionState)); - var result = await this.TransactionValidationService.ValidateSaleTransaction(TestData.EstateId, TestData.MerchantId, Guid.Empty, @@ -428,9 +423,6 @@ public async Task TransactionValidationService_ValidateSaleTransaction_InvalidPr .ReturnsAsync(Result.Success(TestData.Aggregates.EstateAggregateWithOperator())); this.AggregateService.Setup(e => e.Get(It.IsAny(), It.IsAny())).ReturnsAsync(TestData.Aggregates.MerchantAggregateWithEverything(SettlementSchedule.Immediate)); - this.EventStoreContext.Setup(e => e.GetPartitionStateFromProjection(It.IsAny(), It.IsAny(), It.IsAny())) - .ReturnsAsync(JsonConvert.SerializeObject(TestData.MerchantBalanceProjectionState)); - var result = await this.TransactionValidationService.ValidateSaleTransaction(TestData.EstateId, TestData.MerchantId, TestData.ContractId, @@ -499,10 +491,7 @@ public async Task TransactionValidationService_ValidateSaleTransaction_MerchantD this.AggregateService.Setup(e => e.Get(It.IsAny(), It.IsAny())) .ReturnsAsync(Result.Success(TestData.Aggregates.EstateAggregateWithOperator())); this.AggregateService.Setup(e => e.Get(It.IsAny(), It.IsAny())).ReturnsAsync(TestData.Aggregates.MerchantAggregateWithEverything(SettlementSchedule.Immediate)); - - this.EventStoreContext.Setup(e => e.GetPartitionStateFromProjection(It.IsAny(), It.IsAny(), It.IsAny())) - .ReturnsAsync(JsonConvert.SerializeObject(TestData.MerchantBalanceProjectionState)); - + var result = await this.TransactionValidationService.ValidateSaleTransaction(TestData.EstateId, TestData.MerchantId, TestData.ContractId1, @@ -525,11 +514,6 @@ public async Task TransactionValidationService_ValidateSaleTransaction_MerchantH .ReturnsAsync(Result.Success(TestData.Aggregates.EstateAggregateWithOperator())); this.AggregateService.Setup(e => e.Get(It.IsAny(), It.IsAny())).ReturnsAsync(TestData.Aggregates.MerchantAggregateWithNoContracts(SettlementSchedule.Immediate)); - - - this.EventStoreContext.Setup(e => e.GetPartitionStateFromProjection(It.IsAny(), It.IsAny(), It.IsAny())) - .ReturnsAsync(JsonConvert.SerializeObject(TestData.MerchantBalanceProjectionState)); - var result = await this.TransactionValidationService.ValidateSaleTransaction(TestData.EstateId, TestData.MerchantId, TestData.ContractId, @@ -551,9 +535,7 @@ public async Task TransactionValidationService_ValidateSaleTransaction_MerchantN this.AggregateService.Setup(e => e.Get(It.IsAny(), It.IsAny())) .ReturnsAsync(Result.Success(TestData.Aggregates.EstateAggregateWithOperator())); this.AggregateService.Setup(m => m.Get(It.IsAny(), It.IsAny())).ReturnsAsync(TestData.Aggregates.MerchantAggregateWithEverything(SettlementSchedule.Immediate)); - this.EventStoreContext.Setup(e => e.GetPartitionStateFromProjection(It.IsAny(), It.IsAny(), It.IsAny())) - .ReturnsAsync(JsonConvert.SerializeObject(TestData.MerchantBalanceProjectionStateNoCredit)); - + this.AggregateService.Setup(e => e.GetLatest(It.IsAny(), It.IsAny())).ReturnsAsync(TestData.Aggregates.EmptyMerchantBalanceAggregate()); var result = await this.TransactionValidationService.ValidateSaleTransaction(TestData.EstateId, TestData.MerchantId, TestData.ContractId, @@ -576,8 +558,7 @@ public async Task TransactionValidationService_ValidateSaleTransaction_MerchantN .ReturnsAsync(Result.Success(TestData.Aggregates.EstateAggregateWithOperator())); this.AggregateService.Setup(e => e.Get(It.IsAny(), It.IsAny())) .ReturnsAsync(Result.NotFound("Merchant not found")); - - + var result = await this.TransactionValidationService.ValidateSaleTransaction(TestData.EstateId, TestData.MerchantId, TestData.ContractId, @@ -626,9 +607,6 @@ public async Task TransactionValidationService_ValidateSaleTransaction_MerchantN .ReturnsAsync(Result.Success(TestData.Aggregates.MerchantAggregateWithEverything(SettlementSchedule.Immediate))) .ReturnsAsync(Result.NotFound()); - this.EventStoreContext.Setup(e => e.GetPartitionStateFromProjection(It.IsAny(), It.IsAny(), It.IsAny())) - .ReturnsAsync(JsonConvert.SerializeObject(TestData.MerchantBalanceProjectionState)); - var result = await this.TransactionValidationService.ValidateSaleTransaction(TestData.EstateId, TestData.MerchantId, TestData.ContractId, @@ -652,10 +630,7 @@ public async Task TransactionValidationService_ValidateSaleTransaction_FailedGet this.AggregateService.SetupSequence(m => m.Get(It.IsAny(), It.IsAny())) .ReturnsAsync(Result.Success(TestData.Aggregates.MerchantAggregateWithEverything(SettlementSchedule.Immediate))) .ReturnsAsync(Result.NotFound()); - - this.EventStoreContext.Setup(e => e.GetPartitionStateFromProjection(It.IsAny(), It.IsAny(), It.IsAny())) - .ReturnsAsync(JsonConvert.SerializeObject(TestData.MerchantBalanceProjectionState)); - + var result = await this.TransactionValidationService.ValidateSaleTransaction(TestData.EstateId, TestData.MerchantId, TestData.ContractId, @@ -747,10 +722,7 @@ public async Task TransactionValidationService_ValidateSaleTransaction_ProductId this.AggregateService.Setup(e => e.Get(It.IsAny(), It.IsAny())) .ReturnsAsync(Result.Success(TestData.Aggregates.EstateAggregateWithOperator())); this.AggregateService.Setup(e => e.Get(It.IsAny(), It.IsAny())).ReturnsAsync(TestData.Aggregates.MerchantAggregateWithEverything(SettlementSchedule.Immediate)); - - this.EventStoreContext.Setup(e => e.GetPartitionStateFromProjection(It.IsAny(), It.IsAny(), It.IsAny())) - .ReturnsAsync(JsonConvert.SerializeObject(TestData.MerchantBalanceProjectionState)); - + var result = await this.TransactionValidationService.ValidateSaleTransaction(TestData.EstateId, TestData.MerchantId, TestData.ContractId, @@ -772,10 +744,7 @@ public async Task TransactionValidationService_ValidateSaleTransaction_Successfu this.AggregateService.Setup(e => e.Get(It.IsAny(), It.IsAny())) .ReturnsAsync(Result.Success(TestData.Aggregates.EstateAggregateWithOperator())); this.AggregateService.SetupSequence(m => m.Get(It.IsAny(), It.IsAny())).ReturnsAsync(TestData.Aggregates.MerchantAggregateWithEverything(SettlementSchedule.Immediate)); - - this.EventStoreContext.Setup(e => e.GetPartitionStateFromProjection(It.IsAny(), It.IsAny(), It.IsAny())) - .ReturnsAsync(JsonConvert.SerializeObject(TestData.MerchantBalanceProjectionState)); - + this.AggregateService.Setup(e => e.GetLatest(It.IsAny(), It.IsAny())).ReturnsAsync(TestData.Aggregates.MerchantBalanceAggregateWithCredit()); var result = await this.TransactionValidationService.ValidateSaleTransaction(TestData.EstateId, TestData.MerchantId, TestData.ContractId, @@ -789,7 +758,7 @@ public async Task TransactionValidationService_ValidateSaleTransaction_Successfu } [Fact] - public async Task TransactionValidationService_ValidateSaleTransaction_FailedGettingMerchantBalance_ResponseIsInvalidMerchantId() + public async Task TransactionValidationService_ValidateSaleTransaction_FailedGettingMerchantBalance_ResponseIsErrorGettingMerchantBalance() { this.SecurityServiceClient.Setup(s => s.GetToken(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(Result.Success(TestData.TokenResponse())); @@ -797,11 +766,8 @@ public async Task TransactionValidationService_ValidateSaleTransaction_FailedGet .ReturnsAsync(Result.Success(TestData.Aggregates.EstateAggregateWithOperator())); this.AggregateService.Setup(e => e.Get(It.IsAny(), It.IsAny())) .ReturnsAsync(TestData.Aggregates.MerchantAggregateWithEverything(SettlementSchedule.Immediate)); - - this.EventStoreContext.Setup(e => e.GetPartitionStateFromProjection(It.IsAny(), It.IsAny(), It.IsAny())) - .ReturnsAsync(Result.Failure()); - - var result = await this.TransactionValidationService.ValidateSaleTransaction(TestData.EstateId, + this.AggregateService.Setup(e => e.GetLatest(It.IsAny(), It.IsAny())).ReturnsAsync(Result.Failure()); + Result result = await this.TransactionValidationService.ValidateSaleTransaction(TestData.EstateId, TestData.MerchantId, TestData.ContractId, TestData.ProductId, @@ -811,7 +777,7 @@ public async Task TransactionValidationService_ValidateSaleTransaction_FailedGet CancellationToken.None); result.IsFailed.ShouldBeTrue(); - result.Data.ResponseCode.ShouldBe(TransactionResponseCode.UnknownFailure); + result.Data.ResponseCode.ShouldBe(TransactionResponseCode.ErrorGettingMerchantBalance); } } diff --git a/TransactionProcessor.BusinessLogic/Services/TransactionResponseCode.cs b/TransactionProcessor.BusinessLogic/Services/TransactionResponseCode.cs index 9feb7bc..09b0efb 100644 --- a/TransactionProcessor.BusinessLogic/Services/TransactionResponseCode.cs +++ b/TransactionProcessor.BusinessLogic/Services/TransactionResponseCode.cs @@ -24,6 +24,7 @@ public enum TransactionResponseCode ProductNotValidForMerchant = 1016, OperatorNotEnabledForEstate = 1017, OperatorNotEnabledForMerchant = 1018, + ErrorGettingMerchantBalance = 1019, // A Catch All generic Error where reason has not been identified UnknownFailure = 9999 diff --git a/TransactionProcessor.BusinessLogic/Services/TransactionValidationService.cs b/TransactionProcessor.BusinessLogic/Services/TransactionValidationService.cs index a682901..f2c5b36 100644 --- a/TransactionProcessor.BusinessLogic/Services/TransactionValidationService.cs +++ b/TransactionProcessor.BusinessLogic/Services/TransactionValidationService.cs @@ -42,15 +42,11 @@ Task> ValidateSaleTransaction(Guid estateId, } public class TransactionValidationService : ITransactionValidationService{ - #region Fields - private readonly IEventStoreContext EventStoreContext; + private readonly IAggregateService AggregateService; - #endregion - public TransactionValidationService(IEventStoreContext eventStoreContext, - IAggregateService aggregateService) + public TransactionValidationService(IAggregateService aggregateService) { - this.EventStoreContext = eventStoreContext; this.AggregateService = aggregateService; } @@ -297,16 +293,17 @@ private async Task> ValidateTransactionAmoun return CreateFailedResult(new TransactionValidationResult(TransactionResponseCode.InvalidSaleTransactionAmount, "Transaction Amount must be greater than 0")); } - Result getBalanceResult = await this.EventStoreContext.GetPartitionStateFromProjection("MerchantBalanceProjection", $"MerchantBalance-{merchantId:N}", cancellationToken); + Result getBalanceResult = await this.AggregateService.GetLatest(merchantId, cancellationToken); if (getBalanceResult.IsFailed) { - return CreateFailedResult(new TransactionValidationResult(TransactionResponseCode.UnknownFailure, $"Error getting balance for Merchant [{merchantName}]")); + return CreateFailedResult(new TransactionValidationResult(TransactionResponseCode.ErrorGettingMerchantBalance, $"Error getting balance for Merchant [{merchantName}]")); } - MerchantBalanceProjectionState1 projectionState = JsonConvert.DeserializeObject(getBalanceResult.Data); - if (projectionState.merchant.balance < transactionAmount) + MerchantBalanceAggregate aggregate = getBalanceResult.Data; + + if (aggregate.Balance < transactionAmount) { - return CreateFailedResult(new TransactionValidationResult(TransactionResponseCode.MerchantDoesNotHaveEnoughCredit, $"Merchant [{merchantName}] does not have enough credit available [{projectionState.merchant.balance:0.00}] to perform transaction amount [{transactionAmount}]")); + return CreateFailedResult(new TransactionValidationResult(TransactionResponseCode.MerchantDoesNotHaveEnoughCredit, $"Merchant [{merchantName}] does not have enough credit available [{aggregate.Balance:0.00}] to perform transaction amount [{transactionAmount}]")); } return Result.Success(new TransactionValidationResult(TransactionResponseCode.Success, "SUCCESS")); diff --git a/TransactionProcessor.Testing/TestData.cs b/TransactionProcessor.Testing/TestData.cs index 914dd45..88b0f42 100644 --- a/TransactionProcessor.Testing/TestData.cs +++ b/TransactionProcessor.Testing/TestData.cs @@ -2424,6 +2424,13 @@ public static MerchantBalanceAggregate EmptyMerchantBalanceAggregate() return merchantBalanceAggregate; } + public static MerchantBalanceAggregate MerchantBalanceAggregateWithCredit() + { + MerchantBalanceAggregate merchantBalanceAggregate = MerchantBalanceAggregate.Create(TestData.MerchantId); + merchantBalanceAggregate.RecordMerchantDeposit(CreatedMerchantAggregate(), DepositId, DepositAmount.Value, DepositDateTime); + return merchantBalanceAggregate; + } + public static MerchantAggregate CreatedMerchantAggregate() { MerchantAggregate merchantAggregate = MerchantAggregate.Create(TestData.MerchantId);