diff --git a/TransactionProcessor.BusinessLogic.Tests/DomainEventHandlers/TransactionDomainEventHandlerTests.cs b/TransactionProcessor.BusinessLogic.Tests/DomainEventHandlers/TransactionDomainEventHandlerTests.cs index ea4dade5..7bac1bc7 100644 --- a/TransactionProcessor.BusinessLogic.Tests/DomainEventHandlers/TransactionDomainEventHandlerTests.cs +++ b/TransactionProcessor.BusinessLogic.Tests/DomainEventHandlers/TransactionDomainEventHandlerTests.cs @@ -247,6 +247,46 @@ public async Task TransactionDomainEventHandler_Handle_TransactionHasBeenComplet pendingSettlementAggregate.GetNumberOfFeesSettled().ShouldBe(0); } + [Fact] + public async Task TransactionDomainEventHandler_Handle_TransactionHasBeenCompletedEvent_SuccessfulSale_MerchantWithNotSetSettlementSchedule_ErrorThrown() + { + this.TransactionAggregateManager.Setup(t => t.GetAggregate(It.IsAny(), It.IsAny(), It.IsAny())) + .ReturnsAsync(TestData.GetCompletedAuthorisedSaleTransactionAggregate); + + this.FeeCalculationManager.Setup(f => f.CalculateFees(It.IsAny>(), It.IsAny())).Returns(new List + { + TestData.CalculatedFeeMerchantFee(), + TestData.CalculatedFeeServiceProviderFee + }); + + this.EstateClient.Setup(e => e.GetMerchant(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) + .ReturnsAsync(new MerchantResponse + { + SettlementSchedule = SettlementSchedule.NotSet, + }); + this.EstateClient.Setup(e => e.GetTransactionFeesForProduct(It.IsAny(), + It.IsAny(), + It.IsAny(), + It.IsAny(), + It.IsAny(), + It.IsAny())).ReturnsAsync(TestData.ContractProductTransactionFees); + + this.SecurityServiceClient.Setup(s => s.GetToken(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(TestData.TokenResponse); + + + TransactionDomainEventHandler transactionDomainEventHandler = new TransactionDomainEventHandler(this.TransactionAggregateManager.Object, + this.FeeCalculationManager.Object, + this.EstateClient.Object, + this.SecurityServiceClient.Object, + this.TransactionReceiptBuilder.Object, + this.MessagingServiceClient.Object, + this.SettlementAggregateRepository.Object); + Should.Throw(async () => + { + await transactionDomainEventHandler.Handle(TestData.TransactionHasBeenCompletedEvent, CancellationToken.None); + }); + } + [Fact] public async Task TransactionDomainEventHandler_Handle_TransactionHasBeenCompletedEvent_UnsuccessfulSale_EventIsHandled() { diff --git a/TransactionProcessor.BusinessLogic.Tests/RequestHandler/TransactionRequestHandlerTests.cs b/TransactionProcessor.BusinessLogic.Tests/RequestHandler/TransactionRequestHandlerTests.cs index 4e6fe44f..acf9f34f 100644 --- a/TransactionProcessor.BusinessLogic.Tests/RequestHandler/TransactionRequestHandlerTests.cs +++ b/TransactionProcessor.BusinessLogic.Tests/RequestHandler/TransactionRequestHandlerTests.cs @@ -61,13 +61,13 @@ public void TransactionRequestHandler_ProcessReconciliationRequest_IsHandled() } } - public class SettlementRequestHanslerTests + public class SettlementRequestHandlerTests { [Fact] public void TransactionRequestHandler_ProcessLogonTransactionRequest_IsHandled() { - Mock transactionDomainService = new Mock(); - SettlementRequestHandler handler = new SettlementRequestHandler(transactionDomainService.Object); + Mock settlementDomainService = new Mock(); + SettlementRequestHandler handler = new SettlementRequestHandler(settlementDomainService.Object); ProcessSettlementRequest command = TestData.ProcessSettlementRequest; diff --git a/TransactionProcessor.BusinessLogic.Tests/Services/SettlementDomainServiceTests.cs b/TransactionProcessor.BusinessLogic.Tests/Services/SettlementDomainServiceTests.cs new file mode 100644 index 00000000..cdb80896 --- /dev/null +++ b/TransactionProcessor.BusinessLogic.Tests/Services/SettlementDomainServiceTests.cs @@ -0,0 +1,139 @@ +namespace TransactionProcessor.BusinessLogic.Tests.Services +{ + using System; + using System.Threading; + using System.Threading.Tasks; + using BusinessLogic.Services; + using Microsoft.Extensions.Configuration; + using Models; + using Moq; + using SettlementAggregates; + using Shared.DomainDrivenDesign.EventSourcing; + using Shared.EventStore.Aggregate; + using Shared.General; + using Shared.Logger; + using Shouldly; + using Testing; + using Xunit; + + public class SettlementDomainServiceTests + { + [Fact] + public async Task TransactionDomainService_ProcessSettlement_SettlementIsProcessed() + { + IConfigurationRoot configurationRoot = new ConfigurationBuilder().AddInMemoryCollection(TestData.DefaultAppSettings).Build(); + ConfigurationReader.Initialise(configurationRoot); + + Logger.Initialise(NullLogger.Instance); + + Mock transactionAggregateManager = new Mock(); + Mock> settlementAggregateRepository = + new Mock>(); + settlementAggregateRepository.Setup(s => s.GetLatestVersion(It.IsAny(), It.IsAny())) + .ReturnsAsync(TestData.GetSettlementAggregateWithPendingMerchantFees(10)); + + SettlementDomainService settlementDomainService= + new SettlementDomainService(transactionAggregateManager.Object, settlementAggregateRepository.Object); + + ProcessSettlementResponse response = await settlementDomainService.ProcessSettlement(TestData.SettlementDate, + TestData.EstateId, + CancellationToken.None); + + response.ShouldNotBeNull(); + response.NumberOfFeesFailedToSettle.ShouldBe(0); + response.NumberOfFeesPendingSettlement.ShouldBe(0); + response.NumberOfFeesSuccessfullySettled.ShouldBe(10); + } + + [Fact] + public async Task TransactionDomainService_ProcessSettlement_SettlementAggregateNotCreated_NothingProcessed() + { + IConfigurationRoot configurationRoot = new ConfigurationBuilder().AddInMemoryCollection(TestData.DefaultAppSettings).Build(); + ConfigurationReader.Initialise(configurationRoot); + + Logger.Initialise(NullLogger.Instance); + + Mock transactionAggregateManager = new Mock(); + Mock> settlementAggregateRepository = + new Mock>(); + settlementAggregateRepository.Setup(s => s.GetLatestVersion(It.IsAny(), It.IsAny())) + .ReturnsAsync(TestData.GetEmptySettlementAggregate); + + SettlementDomainService settlementDomainService = + new SettlementDomainService(transactionAggregateManager.Object, + settlementAggregateRepository.Object); + + ProcessSettlementResponse response = await settlementDomainService.ProcessSettlement(TestData.SettlementDate, + TestData.EstateId, + CancellationToken.None); + + response.ShouldNotBeNull(); + response.NumberOfFeesFailedToSettle.ShouldBe(0); + response.NumberOfFeesPendingSettlement.ShouldBe(0); + response.NumberOfFeesSuccessfullySettled.ShouldBe(0); + } + + [Fact] + public async Task TransactionDomainService_ProcessSettlement_SettlementAggregateNoFeesToSettles_NothingProcessed() + { + IConfigurationRoot configurationRoot = new ConfigurationBuilder().AddInMemoryCollection(TestData.DefaultAppSettings).Build(); + ConfigurationReader.Initialise(configurationRoot); + + Logger.Initialise(NullLogger.Instance); + + Mock transactionAggregateManager = new Mock(); + Mock> settlementAggregateRepository = + new Mock>(); + settlementAggregateRepository.Setup(s => s.GetLatestVersion(It.IsAny(), It.IsAny())) + .ReturnsAsync(TestData.GetCreatedSettlementAggregate); + + SettlementDomainService settlementDomainService = + new SettlementDomainService(transactionAggregateManager.Object, + settlementAggregateRepository.Object); + + ProcessSettlementResponse response = await settlementDomainService.ProcessSettlement(TestData.SettlementDate, + TestData.EstateId, + CancellationToken.None); + + response.ShouldNotBeNull(); + response.NumberOfFeesFailedToSettle.ShouldBe(0); + response.NumberOfFeesPendingSettlement.ShouldBe(0); + response.NumberOfFeesSuccessfullySettled.ShouldBe(0); + } + + [Fact] + public async Task TransactionDomainService_ProcessSettlement_AddSettledFeeThrownException_SettlementProcessed() + { + IConfigurationRoot configurationRoot = new ConfigurationBuilder().AddInMemoryCollection(TestData.DefaultAppSettings).Build(); + ConfigurationReader.Initialise(configurationRoot); + + Logger.Initialise(NullLogger.Instance); + + Mock transactionAggregateManager = new Mock(); + transactionAggregateManager.Setup(t => t.AddSettledFee(It.IsAny(), + It.IsAny(), + It.IsAny(), + It.IsAny(), + It.IsAny(), + It.IsAny())).ThrowsAsync(new Exception()); + + Mock> settlementAggregateRepository = + new Mock>(); + settlementAggregateRepository.Setup(s => s.GetLatestVersion(It.IsAny(), It.IsAny())) + .ReturnsAsync(TestData.GetSettlementAggregateWithPendingMerchantFees(10)); + + SettlementDomainService settlementDomainService = + new SettlementDomainService(transactionAggregateManager.Object, + settlementAggregateRepository.Object); + + ProcessSettlementResponse response = await settlementDomainService.ProcessSettlement(TestData.SettlementDate, + TestData.EstateId, + CancellationToken.None); + + response.ShouldNotBeNull(); + response.NumberOfFeesFailedToSettle.ShouldBe(10); + response.NumberOfFeesPendingSettlement.ShouldBe(0); + response.NumberOfFeesSuccessfullySettled.ShouldBe(0); + } + } +} \ No newline at end of file diff --git a/TransactionProcessor.BusinessLogic.Tests/Services/TransactionDomainServiceTests.cs b/TransactionProcessor.BusinessLogic.Tests/Services/TransactionDomainServiceTests.cs index d5e596a6..b79a5b79 100644 --- a/TransactionProcessor.BusinessLogic.Tests/Services/TransactionDomainServiceTests.cs +++ b/TransactionProcessor.BusinessLogic.Tests/Services/TransactionDomainServiceTests.cs @@ -17,7 +17,6 @@ namespace TransactionProcessor.BusinessLogic.Tests.Services using ReconciliationAggregate; using SecurityService.Client; using SecurityService.DataTransferObjects.Responses; - using SettlementAggregates; using Shared.DomainDrivenDesign.EventSourcing; using Shared.EventStore.Aggregate; using Shared.EventStore.EventStore; @@ -54,14 +53,11 @@ public async Task TransactionDomainService_ProcessReconciliationTransaction_Tran new Mock>(); reconciliationAggregateRepository.Setup(r => r.GetLatestVersion(It.IsAny(), It.IsAny())) .ReturnsAsync(new ReconciliationAggregate()); - Mock> settlementAggregateRepository = - new Mock>(); TransactionDomainService transactionDomainService = new TransactionDomainService(transactionAggregateManager.Object, estateClient.Object, securityServiceClient.Object, operatorProxyResolver, - reconciliationAggregateRepository.Object, - settlementAggregateRepository.Object); + reconciliationAggregateRepository.Object); ProcessReconciliationTransactionResponse response = await transactionDomainService.ProcessReconciliationTransaction(TestData.TransactionId, TestData.EstateId, @@ -98,13 +94,10 @@ public async Task TransactionDomainService_ProcessReconciliationTransaction_Inco new Mock>(); reconciliationAggregateRepository.Setup(r => r.GetLatestVersion(It.IsAny(), It.IsAny())) .ReturnsAsync(new ReconciliationAggregate()); - Mock> settlementAggregateRepository = - new Mock>(); TransactionDomainService transactionDomainService = new TransactionDomainService(transactionAggregateManager.Object, estateClient.Object, securityServiceClient.Object, - operatorProxyResolver, reconciliationAggregateRepository.Object, - settlementAggregateRepository.Object); + operatorProxyResolver, reconciliationAggregateRepository.Object); ProcessReconciliationTransactionResponse response = await transactionDomainService.ProcessReconciliationTransaction(TestData.TransactionId, TestData.EstateId, @@ -145,13 +138,10 @@ public async Task TransactionDomainService_ProcessReconciliationTransaction_Merc new Mock>(); reconciliationAggregateRepository.Setup(r => r.GetLatestVersion(It.IsAny(), It.IsAny())) .ReturnsAsync(new ReconciliationAggregate()); - Mock> settlementAggregateRepository = - new Mock>(); TransactionDomainService transactionDomainService = new TransactionDomainService(transactionAggregateManager.Object, estateClient.Object, securityServiceClient.Object, - operatorProxyResolver, reconciliationAggregateRepository.Object, - settlementAggregateRepository.Object); + operatorProxyResolver, reconciliationAggregateRepository.Object); ProcessReconciliationTransactionResponse response = await transactionDomainService.ProcessReconciliationTransaction(TestData.TransactionId, TestData.EstateId, @@ -188,13 +178,10 @@ public async Task TransactionDomainService_ProcessReconciliationTransaction_Inva new Mock>(); reconciliationAggregateRepository.Setup(r => r.GetLatestVersion(It.IsAny(), It.IsAny())) .ReturnsAsync(new ReconciliationAggregate()); - Mock> settlementAggregateRepository = - new Mock>(); TransactionDomainService transactionDomainService = new TransactionDomainService(transactionAggregateManager.Object, estateClient.Object, securityServiceClient.Object, - operatorProxyResolver, reconciliationAggregateRepository.Object, - settlementAggregateRepository.Object); + operatorProxyResolver, reconciliationAggregateRepository.Object); ProcessReconciliationTransactionResponse response = await transactionDomainService.ProcessReconciliationTransaction(TestData.TransactionId, TestData.EstateId, @@ -231,13 +218,10 @@ public async Task TransactionDomainService_ProcessReconciliationTransaction_Inva new Mock>(); reconciliationAggregateRepository.Setup(r => r.GetLatestVersion(It.IsAny(), It.IsAny())) .ReturnsAsync(new ReconciliationAggregate()); - Mock> settlementAggregateRepository = - new Mock>(); TransactionDomainService transactionDomainService = new TransactionDomainService(transactionAggregateManager.Object, estateClient.Object, securityServiceClient.Object, - operatorProxyResolver, reconciliationAggregateRepository.Object, - settlementAggregateRepository.Object); + operatorProxyResolver, reconciliationAggregateRepository.Object); ProcessReconciliationTransactionResponse response = await transactionDomainService.ProcessReconciliationTransaction(TestData.TransactionId, TestData.EstateId, @@ -275,14 +259,11 @@ public async Task TransactionDomainService_ProcessLogonTransaction_TransactionIs Mock> reconciliationAggregateRepository = new Mock>(); - Mock> settlementAggregateRepository = - new Mock>(); TransactionDomainService transactionDomainService = new TransactionDomainService(transactionAggregateManager.Object, estateClient.Object, securityServiceClient.Object, operatorProxyResolver, - reconciliationAggregateRepository.Object, - settlementAggregateRepository.Object); + reconciliationAggregateRepository.Object); ProcessLogonTransactionResponse response = await transactionDomainService.ProcessLogonTransaction(TestData.TransactionId, TestData.EstateId, @@ -318,13 +299,10 @@ public async Task TransactionDomainService_ProcessLogonTransaction_MerchantWithN Mock> reconciliationAggregateRepository = new Mock>(); - Mock> settlementAggregateRepository = - new Mock>(); TransactionDomainService transactionDomainService = new TransactionDomainService(transactionAggregateManager.Object, estateClient.Object, securityServiceClient.Object, - operatorProxyResolver, reconciliationAggregateRepository.Object, - settlementAggregateRepository.Object); + operatorProxyResolver, reconciliationAggregateRepository.Object); ProcessLogonTransactionResponse response = await transactionDomainService.ProcessLogonTransaction(TestData.TransactionId, TestData.EstateId, @@ -361,13 +339,10 @@ public async Task TransactionDomainService_ProcessLogonTransaction_MerchantWithN Mock> reconciliationAggregateRepository = new Mock>(); - Mock> settlementAggregateRepository = - new Mock>(); TransactionDomainService transactionDomainService = new TransactionDomainService(transactionAggregateManager.Object, estateClient.Object, securityServiceClient.Object, - operatorProxyResolver, reconciliationAggregateRepository.Object, - settlementAggregateRepository.Object); + operatorProxyResolver, reconciliationAggregateRepository.Object); ProcessLogonTransactionResponse response = await transactionDomainService.ProcessLogonTransaction(TestData.TransactionId, TestData.EstateId, @@ -403,13 +378,10 @@ public async Task TransactionDomainService_ProcessLogonTransaction_IncorrectDevi Mock> reconciliationAggregateRepository = new Mock>(); - Mock> settlementAggregateRepository = - new Mock>(); TransactionDomainService transactionDomainService = new TransactionDomainService(transactionAggregateManager.Object, estateClient.Object, securityServiceClient.Object, - operatorProxyResolver, reconciliationAggregateRepository.Object, - settlementAggregateRepository.Object); + operatorProxyResolver, reconciliationAggregateRepository.Object); ProcessLogonTransactionResponse response = await transactionDomainService.ProcessLogonTransaction(TestData.TransactionId, TestData.EstateId, @@ -445,13 +417,10 @@ public async Task TransactionDomainService_ProcessLogonTransaction_InvalidEstate Mock> reconciliationAggregateRepository = new Mock>(); - Mock> settlementAggregateRepository = - new Mock>(); TransactionDomainService transactionDomainService = new TransactionDomainService(transactionAggregateManager.Object, estateClient.Object, securityServiceClient.Object, - operatorProxyResolver, reconciliationAggregateRepository.Object, - settlementAggregateRepository.Object); + operatorProxyResolver, reconciliationAggregateRepository.Object); ProcessLogonTransactionResponse response = await transactionDomainService.ProcessLogonTransaction(TestData.TransactionId, TestData.EstateId, @@ -487,13 +456,10 @@ public async Task TransactionDomainService_ProcessLogonTransaction_InvalidMercha Mock> reconciliationAggregateRepository = new Mock>(); - Mock> settlementAggregateRepository = - new Mock>(); - + TransactionDomainService transactionDomainService = new TransactionDomainService(transactionAggregateManager.Object, estateClient.Object, securityServiceClient.Object, - operatorProxyResolver, reconciliationAggregateRepository.Object, - settlementAggregateRepository.Object); + operatorProxyResolver, reconciliationAggregateRepository.Object); ProcessLogonTransactionResponse response = await transactionDomainService.ProcessLogonTransaction(TestData.TransactionId, TestData.EstateId, @@ -545,14 +511,10 @@ public async Task TransactionDomainService_ProcessSaleTransaction_SuccesfulOpera Mock> reconciliationAggregateRepository = new Mock>(); - - Mock> settlementAggregateRepository = - new Mock>(); - + TransactionDomainService transactionDomainService = new TransactionDomainService(transactionAggregateManager.Object, estateClient.Object, securityServiceClient.Object, - operatorProxyResolver, reconciliationAggregateRepository.Object, - settlementAggregateRepository.Object); + operatorProxyResolver, reconciliationAggregateRepository.Object); ProcessSaleTransactionResponse response = await transactionDomainService.ProcessSaleTransaction(TestData.TransactionId, TestData.EstateId, @@ -594,14 +556,11 @@ public async Task TransactionDomainService_ProcessSaleTransaction_InvalidTransac Mock> reconciliationAggregateRepository = new Mock>(); - - Mock> settlementAggregateRepository = - new Mock>(); + TransactionDomainService transactionDomainService = new TransactionDomainService(transactionAggregateManager.Object, estateClient.Object, securityServiceClient.Object, - operatorProxyResolver, reconciliationAggregateRepository.Object, - settlementAggregateRepository.Object); + operatorProxyResolver, reconciliationAggregateRepository.Object); ProcessSaleTransactionResponse response = await transactionDomainService.ProcessSaleTransaction(TestData.TransactionId, TestData.EstateId, @@ -661,13 +620,10 @@ public async Task TransactionDomainService_ProcessSaleTransaction_MetaDataCaseTe Mock> reconciliationAggregateRepository = new Mock>(); - Mock> settlementAggregateRepository = - new Mock>(); TransactionDomainService transactionDomainService = new TransactionDomainService(transactionAggregateManager.Object, estateClient.Object, securityServiceClient.Object, - operatorProxyResolver, reconciliationAggregateRepository.Object, - settlementAggregateRepository.Object); + operatorProxyResolver, reconciliationAggregateRepository.Object); @@ -729,13 +685,10 @@ public async Task TransactionDomainService_ProcessSaleTransaction_MetaDataCaseTe Mock> reconciliationAggregateRepository = new Mock>(); - Mock> settlementAggregateRepository = - new Mock>(); TransactionDomainService transactionDomainService = new TransactionDomainService(transactionAggregateManager.Object, estateClient.Object, securityServiceClient.Object, - operatorProxyResolver, reconciliationAggregateRepository.Object, - settlementAggregateRepository.Object); + operatorProxyResolver, reconciliationAggregateRepository.Object); @@ -792,13 +745,10 @@ public async Task TransactionDomainService_ProcessSaleTransaction_FailedOperator Mock> reconciliationAggregateRepository = new Mock>(); - Mock> settlementAggregateRepository = - new Mock>(); TransactionDomainService transactionDomainService = new TransactionDomainService(transactionAggregateManager.Object, estateClient.Object, securityServiceClient.Object, - operatorProxyResolver, reconciliationAggregateRepository.Object, - settlementAggregateRepository.Object); + operatorProxyResolver, reconciliationAggregateRepository.Object); ProcessSaleTransactionResponse response = await transactionDomainService.ProcessSaleTransaction(TestData.TransactionId, TestData.EstateId, @@ -839,13 +789,10 @@ public async Task TransactionDomainService_ProcessSaleTransaction_MerchantWithNu Mock> reconciliationAggregateRepository = new Mock>(); - Mock> settlementAggregateRepository = - new Mock>(); TransactionDomainService transactionDomainService = new TransactionDomainService(transactionAggregateManager.Object, estateClient.Object, securityServiceClient.Object, - operatorProxyResolver, reconciliationAggregateRepository.Object, - settlementAggregateRepository.Object); + operatorProxyResolver, reconciliationAggregateRepository.Object); ProcessSaleTransactionResponse response = await transactionDomainService.ProcessSaleTransaction(TestData.TransactionId, TestData.EstateId, @@ -887,13 +834,10 @@ public async Task TransactionDomainService_ProcessSaleTransaction_MerchantWithNo Mock> reconciliationAggregateRepository = new Mock>(); - Mock> settlementAggregateRepository = - new Mock>(); TransactionDomainService transactionDomainService = new TransactionDomainService(transactionAggregateManager.Object, estateClient.Object, securityServiceClient.Object, - operatorProxyResolver, reconciliationAggregateRepository.Object, - settlementAggregateRepository.Object); + operatorProxyResolver, reconciliationAggregateRepository.Object); ProcessSaleTransactionResponse response = await transactionDomainService.ProcessSaleTransaction(TestData.TransactionId, TestData.EstateId, @@ -934,13 +878,10 @@ public async Task TransactionDomainService_ProcessSaleTransaction_IncorrectDevic Mock> reconciliationAggregateRepository = new Mock>(); - Mock> settlementAggregateRepository = - new Mock>(); TransactionDomainService transactionDomainService = new TransactionDomainService(transactionAggregateManager.Object, estateClient.Object, securityServiceClient.Object, - operatorProxyResolver, reconciliationAggregateRepository.Object, - settlementAggregateRepository.Object); + operatorProxyResolver, reconciliationAggregateRepository.Object); ProcessSaleTransactionResponse response = await transactionDomainService.ProcessSaleTransaction(TestData.TransactionId, TestData.EstateId, @@ -981,13 +922,10 @@ public async Task TransactionDomainService_ProcessSaleTransaction_InvalidEstate_ Mock> reconciliationAggregateRepository = new Mock>(); - Mock> settlementAggregateRepository = - new Mock>(); TransactionDomainService transactionDomainService = new TransactionDomainService(transactionAggregateManager.Object, estateClient.Object, securityServiceClient.Object, - operatorProxyResolver, reconciliationAggregateRepository.Object, - settlementAggregateRepository.Object); + operatorProxyResolver, reconciliationAggregateRepository.Object); ProcessSaleTransactionResponse response = await transactionDomainService.ProcessSaleTransaction(TestData.TransactionId, TestData.EstateId, @@ -1028,14 +966,11 @@ public async Task TransactionDomainService_ProcessSaleTransaction_NotEnoughCredi Mock> reconciliationAggregateRepository = new Mock>(); - Mock> settlementAggregateRepository = - new Mock>(); TransactionDomainService transactionDomainService = new TransactionDomainService(transactionAggregateManager.Object, estateClient.Object, securityServiceClient.Object, operatorProxyResolver, - reconciliationAggregateRepository.Object, - settlementAggregateRepository.Object); + reconciliationAggregateRepository.Object); ProcessSaleTransactionResponse response = await transactionDomainService.ProcessSaleTransaction(TestData.TransactionId, TestData.EstateId, @@ -1075,13 +1010,10 @@ public async Task TransactionDomainService_ProcessSaleTransaction_InvalidMerchan Mock> reconciliationAggregateRepository = new Mock>(); - Mock> settlementAggregateRepository = - new Mock>(); - + TransactionDomainService transactionDomainService = new TransactionDomainService(transactionAggregateManager.Object, estateClient.Object, securityServiceClient.Object, - operatorProxyResolver, reconciliationAggregateRepository.Object, - settlementAggregateRepository.Object); + operatorProxyResolver, reconciliationAggregateRepository.Object); ProcessSaleTransactionResponse response = await transactionDomainService.ProcessSaleTransaction(TestData.TransactionId, TestData.EstateId, @@ -1122,12 +1054,9 @@ public async Task TransactionDomainService_ProcessSaleTransaction_EstateWithEmpt Mock> reconciliationAggregateRepository = new Mock>(); - Mock> settlementAggregateRepository = - new Mock>(); TransactionDomainService transactionDomainService = new TransactionDomainService(transactionAggregateManager.Object, estateClient.Object, securityServiceClient.Object, - operatorProxyResolver, reconciliationAggregateRepository.Object, - settlementAggregateRepository.Object); + operatorProxyResolver, reconciliationAggregateRepository.Object); ProcessSaleTransactionResponse response = await transactionDomainService.ProcessSaleTransaction(TestData.TransactionId, TestData.EstateId, @@ -1168,13 +1097,10 @@ public async Task TransactionDomainService_ProcessSaleTransaction_EstateWithNull Mock> reconciliationAggregateRepository = new Mock>(); - Mock> settlementAggregateRepository = - new Mock>(); TransactionDomainService transactionDomainService = new TransactionDomainService(transactionAggregateManager.Object, estateClient.Object, securityServiceClient.Object, - operatorProxyResolver,reconciliationAggregateRepository.Object, - settlementAggregateRepository.Object); + operatorProxyResolver,reconciliationAggregateRepository.Object); ProcessSaleTransactionResponse response = await transactionDomainService.ProcessSaleTransaction(TestData.TransactionId, TestData.EstateId, @@ -1215,13 +1141,10 @@ public async Task TransactionDomainService_ProcessSaleTransaction_OperatorNotSup Mock> reconciliationAggregateRepository = new Mock>(); - Mock> settlementAggregateRepository = - new Mock>(); TransactionDomainService transactionDomainService = new TransactionDomainService(transactionAggregateManager.Object, estateClient.Object, securityServiceClient.Object, - operatorProxyResolver, reconciliationAggregateRepository.Object, - settlementAggregateRepository.Object); + operatorProxyResolver, reconciliationAggregateRepository.Object); ProcessSaleTransactionResponse response = await transactionDomainService.ProcessSaleTransaction(TestData.TransactionId, TestData.EstateId, @@ -1262,14 +1185,11 @@ public async Task TransactionDomainService_ProcessSaleTransaction_MerchantWithEm Mock> reconciliationAggregateRepository = new Mock>(); - Mock> settlementAggregateRepository = - new Mock>(); TransactionDomainService transactionDomainService = new TransactionDomainService(transactionAggregateManager.Object, estateClient.Object, securityServiceClient.Object, operatorProxyResolver, - reconciliationAggregateRepository.Object, - settlementAggregateRepository.Object); + reconciliationAggregateRepository.Object); ProcessSaleTransactionResponse response = await transactionDomainService.ProcessSaleTransaction(TestData.TransactionId, TestData.EstateId, @@ -1310,13 +1230,10 @@ public async Task TransactionDomainService_ProcessSaleTransaction_MerchantWithNu Mock> reconciliationAggregateRepository = new Mock>(); - Mock> settlementAggregateRepository = - new Mock>(); TransactionDomainService transactionDomainService = new TransactionDomainService(transactionAggregateManager.Object, estateClient.Object, securityServiceClient.Object, - operatorProxyResolver,reconciliationAggregateRepository.Object, - settlementAggregateRepository.Object); + operatorProxyResolver,reconciliationAggregateRepository.Object); ProcessSaleTransactionResponse response = await transactionDomainService.ProcessSaleTransaction(TestData.TransactionId, TestData.EstateId, @@ -1356,14 +1273,11 @@ public async Task TransactionDomainService_ProcessSaleTransaction_OperatorNotSup .ReturnsAsync(TestData.GetDeclinedTransactionAggregate(TransactionResponseCode.OperatorNotValidForMerchant)); Mock> reconciliationAggregateRepository = - new Mock>(); - Mock> settlementAggregateRepository = - new Mock>(); + new Mock>();; TransactionDomainService transactionDomainService = new TransactionDomainService(transactionAggregateManager.Object, estateClient.Object, securityServiceClient.Object, - operatorProxyResolver, reconciliationAggregateRepository.Object, - settlementAggregateRepository.Object); + operatorProxyResolver, reconciliationAggregateRepository.Object); ProcessSaleTransactionResponse response = await transactionDomainService.ProcessSaleTransaction(TestData.TransactionId, TestData.EstateId, @@ -1413,13 +1327,10 @@ public async Task TransactionDomainService_ProcessSaleTransaction_ErrorInOperato Mock> reconciliationAggregateRepository = new Mock>(); - Mock> settlementAggregateRepository = - new Mock>(); TransactionDomainService transactionDomainService = new TransactionDomainService(transactionAggregateManager.Object, estateClient.Object, securityServiceClient.Object, - operatorProxyResolver, reconciliationAggregateRepository.Object, - settlementAggregateRepository.Object); + operatorProxyResolver, reconciliationAggregateRepository.Object); ProcessSaleTransactionResponse response = await transactionDomainService.ProcessSaleTransaction(TestData.TransactionId, TestData.EstateId, @@ -1474,159 +1385,5 @@ private void ValidateResponse(ProcessReconciliationTransactionResponse response, response.ResponseCode.ShouldBe(TestData.GetResponseCodeAsString(transactionResponseCode)); } - - [Fact] - public async Task TransactionDomainService_ProcessSettlement_SettlementIsProcessed() - { - IConfigurationRoot configurationRoot = new ConfigurationBuilder().AddInMemoryCollection(TestData.DefaultAppSettings).Build(); - ConfigurationReader.Initialise(configurationRoot); - - Logger.Initialise(NullLogger.Instance); - - Mock transactionAggregateManager = new Mock(); - Mock estateClient = new Mock(); - Mock securityServiceClient = new Mock(); - Mock operatorProxy = new Mock(); - Func operatorProxyResolver = (operatorName) => { return operatorProxy.Object; }; - - Mock> reconciliationAggregateRepository = - new Mock>(); - Mock> settlementAggregateRepository = - new Mock>(); - settlementAggregateRepository.Setup(s => s.GetLatestVersion(It.IsAny(), It.IsAny())) - .ReturnsAsync(TestData.GetSettlementAggregateWithPendingMerchantFees(10)); - - TransactionDomainService transactionDomainService = - new TransactionDomainService(transactionAggregateManager.Object, estateClient.Object, securityServiceClient.Object, - operatorProxyResolver, - reconciliationAggregateRepository.Object, - settlementAggregateRepository.Object); - - ProcessSettlementResponse response = await transactionDomainService.ProcessSettlement(TestData.SettlementDate, - TestData.EstateId, - CancellationToken.None); - - response.ShouldNotBeNull(); - response.NumberOfFeesFailedToSettle.ShouldBe(0); - response.NumberOfFeesPendingSettlement.ShouldBe(0); - response.NumberOfFeesSuccessfullySettled.ShouldBe(10); - } - - [Fact] - public async Task TransactionDomainService_ProcessSettlement_SettlementAggregateNotCreated_NothingProcessed() - { - IConfigurationRoot configurationRoot = new ConfigurationBuilder().AddInMemoryCollection(TestData.DefaultAppSettings).Build(); - ConfigurationReader.Initialise(configurationRoot); - - Logger.Initialise(NullLogger.Instance); - - Mock transactionAggregateManager = new Mock(); - Mock estateClient = new Mock(); - Mock securityServiceClient = new Mock(); - Mock operatorProxy = new Mock(); - Func operatorProxyResolver = (operatorName) => { return operatorProxy.Object; }; - - Mock> reconciliationAggregateRepository = - new Mock>(); - Mock> settlementAggregateRepository = - new Mock>(); - settlementAggregateRepository.Setup(s => s.GetLatestVersion(It.IsAny(), It.IsAny())) - .ReturnsAsync(TestData.GetEmptySettlementAggregate); - - TransactionDomainService transactionDomainService = - new TransactionDomainService(transactionAggregateManager.Object, estateClient.Object, securityServiceClient.Object, - operatorProxyResolver, - reconciliationAggregateRepository.Object, - settlementAggregateRepository.Object); - - ProcessSettlementResponse response = await transactionDomainService.ProcessSettlement(TestData.SettlementDate, - TestData.EstateId, - CancellationToken.None); - - response.ShouldNotBeNull(); - response.NumberOfFeesFailedToSettle.ShouldBe(0); - response.NumberOfFeesPendingSettlement.ShouldBe(0); - response.NumberOfFeesSuccessfullySettled.ShouldBe(0); - } - - [Fact] - public async Task TransactionDomainService_ProcessSettlement_SettlementAggregateNoFeesToSettles_NothingProcessed() - { - IConfigurationRoot configurationRoot = new ConfigurationBuilder().AddInMemoryCollection(TestData.DefaultAppSettings).Build(); - ConfigurationReader.Initialise(configurationRoot); - - Logger.Initialise(NullLogger.Instance); - - Mock transactionAggregateManager = new Mock(); - Mock estateClient = new Mock(); - Mock securityServiceClient = new Mock(); - Mock operatorProxy = new Mock(); - Func operatorProxyResolver = (operatorName) => { return operatorProxy.Object; }; - - Mock> reconciliationAggregateRepository = - new Mock>(); - Mock> settlementAggregateRepository = - new Mock>(); - settlementAggregateRepository.Setup(s => s.GetLatestVersion(It.IsAny(), It.IsAny())) - .ReturnsAsync(TestData.GetCreatedSettlementAggregate); - - TransactionDomainService transactionDomainService = - new TransactionDomainService(transactionAggregateManager.Object, estateClient.Object, securityServiceClient.Object, - operatorProxyResolver, - reconciliationAggregateRepository.Object, - settlementAggregateRepository.Object); - - ProcessSettlementResponse response = await transactionDomainService.ProcessSettlement(TestData.SettlementDate, - TestData.EstateId, - CancellationToken.None); - - response.ShouldNotBeNull(); - response.NumberOfFeesFailedToSettle.ShouldBe(0); - response.NumberOfFeesPendingSettlement.ShouldBe(0); - response.NumberOfFeesSuccessfullySettled.ShouldBe(0); - } - - [Fact] - public async Task TransactionDomainService_ProcessSettlement_AddSettledFeeThrownException_SettlementProcessed() - { - IConfigurationRoot configurationRoot = new ConfigurationBuilder().AddInMemoryCollection(TestData.DefaultAppSettings).Build(); - ConfigurationReader.Initialise(configurationRoot); - - Logger.Initialise(NullLogger.Instance); - - Mock transactionAggregateManager = new Mock(); - transactionAggregateManager.Setup(t => t.AddSettledFee(It.IsAny(), - It.IsAny(), - It.IsAny(), - It.IsAny(), - It.IsAny(), - It.IsAny())).ThrowsAsync(new Exception()); - Mock estateClient = new Mock(); - Mock securityServiceClient = new Mock(); - Mock operatorProxy = new Mock(); - Func operatorProxyResolver = (operatorName) => { return operatorProxy.Object; }; - - Mock> reconciliationAggregateRepository = - new Mock>(); - Mock> settlementAggregateRepository = - new Mock>(); - settlementAggregateRepository.Setup(s => s.GetLatestVersion(It.IsAny(), It.IsAny())) - .ReturnsAsync(TestData.GetSettlementAggregateWithPendingMerchantFees(10)); - - TransactionDomainService transactionDomainService = - new TransactionDomainService(transactionAggregateManager.Object, estateClient.Object, securityServiceClient.Object, - operatorProxyResolver, - reconciliationAggregateRepository.Object, - settlementAggregateRepository.Object); - - ProcessSettlementResponse response = await transactionDomainService.ProcessSettlement(TestData.SettlementDate, - TestData.EstateId, - CancellationToken.None); - - response.ShouldNotBeNull(); - response.NumberOfFeesFailedToSettle.ShouldBe(10); - response.NumberOfFeesPendingSettlement.ShouldBe(0); - response.NumberOfFeesSuccessfullySettled.ShouldBe(0); - } } } diff --git a/TransactionProcessor.BusinessLogic/EventHandling/TransactionDomainEventHandler.cs b/TransactionProcessor.BusinessLogic/EventHandling/TransactionDomainEventHandler.cs index 390dd03f..8083e6cb 100644 --- a/TransactionProcessor.BusinessLogic/EventHandling/TransactionDomainEventHandler.cs +++ b/TransactionProcessor.BusinessLogic/EventHandling/TransactionDomainEventHandler.cs @@ -261,15 +261,17 @@ private async Task HandleSpecificDomainEvent(TransactionHasBeenCompletedEvent do private DateTime CalculateSettlementDate(SettlementSchedule merchantSettlementSchedule, DateTime completeDateTime) { - switch(merchantSettlementSchedule) + if (merchantSettlementSchedule == SettlementSchedule.Weekly) { - case SettlementSchedule.Weekly: - return completeDateTime.Date.AddDays(7).Date; - case SettlementSchedule.Monthly: - return completeDateTime.Date.AddMonths(1).Date; - default: - throw new Exception("Invalid merchant settlement schedule"); + return completeDateTime.Date.AddDays(7).Date; } + + if (merchantSettlementSchedule == SettlementSchedule.Monthly) + { + return completeDateTime.Date.AddMonths(1).Date; + } + + return completeDateTime; } /// diff --git a/TransactionProcessor.BusinessLogic/RequestHandlers/SettlementRequestHandler.cs b/TransactionProcessor.BusinessLogic/RequestHandlers/SettlementRequestHandler.cs index c2539e21..1261493c 100644 --- a/TransactionProcessor.BusinessLogic/RequestHandlers/SettlementRequestHandler.cs +++ b/TransactionProcessor.BusinessLogic/RequestHandlers/SettlementRequestHandler.cs @@ -14,17 +14,17 @@ namespace TransactionProcessor.BusinessLogic.RequestHandlers public class SettlementRequestHandler : IRequestHandler { - private readonly ITransactionDomainService TransactionDomainService; + private readonly ISettlementDomainService SettlementDomainService; - public SettlementRequestHandler(ITransactionDomainService transactionDomainService) + public SettlementRequestHandler(ISettlementDomainService settlementDomainService) { - this.TransactionDomainService = transactionDomainService; + this.SettlementDomainService = settlementDomainService; } public async Task Handle(ProcessSettlementRequest request, CancellationToken cancellationToken) { - ProcessSettlementResponse processSettlementResponse = await this.TransactionDomainService.ProcessSettlement(request.SettlementDate, request.EstateId, cancellationToken); + ProcessSettlementResponse processSettlementResponse = await this.SettlementDomainService.ProcessSettlement(request.SettlementDate, request.EstateId, cancellationToken); return processSettlementResponse; } diff --git a/TransactionProcessor.BusinessLogic/Services/ISettlementDomainService.cs b/TransactionProcessor.BusinessLogic/Services/ISettlementDomainService.cs new file mode 100644 index 00000000..f6467d00 --- /dev/null +++ b/TransactionProcessor.BusinessLogic/Services/ISettlementDomainService.cs @@ -0,0 +1,17 @@ +namespace TransactionProcessor.BusinessLogic.Services +{ + using System; + using System.Threading; + using System.Threading.Tasks; + using Models; + + /// + /// + /// + public interface ISettlementDomainService + { + Task ProcessSettlement(DateTime pendingSettlementDate, + Guid estateId, + CancellationToken cancellationToken); + } +} \ No newline at end of file diff --git a/TransactionProcessor.BusinessLogic/Services/ITransactionDomainService.cs b/TransactionProcessor.BusinessLogic/Services/ITransactionDomainService.cs index d87b0a4c..e55afd88 100644 --- a/TransactionProcessor.BusinessLogic/Services/ITransactionDomainService.cs +++ b/TransactionProcessor.BusinessLogic/Services/ITransactionDomainService.cs @@ -6,9 +6,6 @@ using System.Threading.Tasks; using Models; - /// - /// - /// public interface ITransactionDomainService { #region Methods @@ -81,11 +78,6 @@ Task ProcessReconciliationTransaction( Int32 transactionCount, Decimal transactionValue, CancellationToken cancellationToken); - - Task ProcessSettlement(DateTime pendingSettlementDate, - Guid estateId, - CancellationToken cancellationToken); - #endregion } } \ No newline at end of file diff --git a/TransactionProcessor.BusinessLogic/Services/SettlementDomainService.cs b/TransactionProcessor.BusinessLogic/Services/SettlementDomainService.cs new file mode 100644 index 00000000..76c9190f --- /dev/null +++ b/TransactionProcessor.BusinessLogic/Services/SettlementDomainService.cs @@ -0,0 +1,70 @@ +namespace TransactionProcessor.BusinessLogic.Services +{ + using System; + using System.Threading; + using System.Threading.Tasks; + using Common; + using Models; + using SettlementAggregates; + using Shared.DomainDrivenDesign.EventSourcing; + using Shared.EventStore.Aggregate; + using Shared.Logger; + + public class SettlementDomainService : ISettlementDomainService + { + private readonly ITransactionAggregateManager TransactionAggregateManager; + + private readonly IAggregateRepository SettlementAggregateRepository; + + public async Task ProcessSettlement(DateTime settlementDate, + Guid estateId, + CancellationToken cancellationToken) + { + ProcessSettlementResponse response = new ProcessSettlementResponse(); + + Guid aggregateId = settlementDate.ToGuid(); + + SettlementAggregate settlementAggregate = await this.SettlementAggregateRepository.GetLatestVersion(aggregateId, cancellationToken); + + if (settlementAggregate.IsCreated == false) + { + // Not pending settlement for this date + return response; + } + + var feesToBeSettled = settlementAggregate.GetFeesToBeSettled(); + response.NumberOfFeesPendingSettlement = feesToBeSettled.Count; + + foreach ((Guid transactionId, Guid merchantId, CalculatedFee calculatedFee) feeToSettle in feesToBeSettled) + { + try + { + await this.TransactionAggregateManager.AddSettledFee(estateId, + feeToSettle.transactionId, + feeToSettle.calculatedFee, + settlementDate, + DateTime.Now, + cancellationToken); + response.NumberOfFeesSuccessfullySettled++; + response.NumberOfFeesPendingSettlement--; + } + catch (Exception ex) + { + Logger.LogError(ex); + response.NumberOfFeesPendingSettlement--; + response.NumberOfFeesFailedToSettle++; + } + + } + + return response; + } + + public SettlementDomainService(ITransactionAggregateManager transactionAggregateManager, + IAggregateRepository settlementAggregateRepository) + { + this.TransactionAggregateManager = transactionAggregateManager; + this.SettlementAggregateRepository = settlementAggregateRepository; + } + } +} \ No newline at end of file diff --git a/TransactionProcessor.BusinessLogic/Services/TransactionDomainService.cs b/TransactionProcessor.BusinessLogic/Services/TransactionDomainService.cs index 316e9cd4..8a5e22ba 100644 --- a/TransactionProcessor.BusinessLogic/Services/TransactionDomainService.cs +++ b/TransactionProcessor.BusinessLogic/Services/TransactionDomainService.cs @@ -17,7 +17,6 @@ using ReconciliationAggregate; using SecurityService.Client; using SecurityService.DataTransferObjects.Responses; - using SettlementAggregates; using Shared.DomainDrivenDesign.EventSourcing; using Shared.EventStore.Aggregate; using Shared.EventStore.EventStore; @@ -63,8 +62,6 @@ public class TransactionDomainService : ITransactionDomainService /// private readonly IAggregateRepository ReconciliationAggregateRepository; - private readonly IAggregateRepository SettlementAggregateRepository; - #endregion #region Constructors @@ -81,15 +78,13 @@ public TransactionDomainService(ITransactionAggregateManager transactionAggregat IEstateClient estateClient, ISecurityServiceClient securityServiceClient, Func operatorProxyResolver, - IAggregateRepository reconciliationAggregateRepository, - IAggregateRepository settlementAggregateRepository) + IAggregateRepository reconciliationAggregateRepository) { this.TransactionAggregateManager = transactionAggregateManager; this.EstateClient = estateClient; this.SecurityServiceClient = securityServiceClient; this.OperatorProxyResolver = operatorProxyResolver; this.ReconciliationAggregateRepository = reconciliationAggregateRepository; - this.SettlementAggregateRepository = settlementAggregateRepository; } #endregion @@ -396,49 +391,7 @@ public async Task ProcessReconciliatio }; } - public async Task ProcessSettlement(DateTime settlementDate, - Guid estateId, - CancellationToken cancellationToken) - { - ProcessSettlementResponse response = new ProcessSettlementResponse(); - - Guid aggregateId = settlementDate.ToGuid(); - - SettlementAggregate settlementAggregate = await this.SettlementAggregateRepository.GetLatestVersion(aggregateId, cancellationToken); - - if (settlementAggregate.IsCreated == false) - { - // Not pending settlement for this date - return response; - } - - var feesToBeSettled = settlementAggregate.GetFeesToBeSettled(); - response.NumberOfFeesPendingSettlement = feesToBeSettled.Count; - - foreach ((Guid transactionId, Guid merchantId, CalculatedFee calculatedFee) feeToSettle in feesToBeSettled) - { - try - { - await this.TransactionAggregateManager.AddSettledFee(estateId, - feeToSettle.transactionId, - feeToSettle.calculatedFee, - settlementDate, - DateTime.Now, - cancellationToken); - response.NumberOfFeesSuccessfullySettled++; - response.NumberOfFeesPendingSettlement--; - } - catch(Exception ex) - { - Logger.LogError(ex); - response.NumberOfFeesPendingSettlement--; - response.NumberOfFeesFailedToSettle++; - } - - } - - return response; - } + /// /// Adds the device to merchant. diff --git a/TransactionProcessor.SettlementAggregates/SettlementAggregate.cs b/TransactionProcessor.SettlementAggregates/SettlementAggregate.cs index 997a5880..83fe92f3 100644 --- a/TransactionProcessor.SettlementAggregates/SettlementAggregate.cs +++ b/TransactionProcessor.SettlementAggregates/SettlementAggregate.cs @@ -178,6 +178,7 @@ public override void PlayEvent(IDomainEvent domainEvent) this.PlayEvent((dynamic)domainEvent); } + [ExcludeFromCodeCoverage] protected override Object GetMetadata() { return null; diff --git a/TransactionProcessor/Startup.cs b/TransactionProcessor/Startup.cs index f653ac62..75856019 100644 --- a/TransactionProcessor/Startup.cs +++ b/TransactionProcessor/Startup.cs @@ -159,6 +159,7 @@ public void ConfigureServices(IServiceCollection services) services.AddSingleton, AggregateRepository>(); services.AddSingleton, AggregateRepository>(); services.AddSingleton(); + services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); services.AddSingleton();