diff --git a/TransactionProcessor.BusinessLogic.Tests/DomainEventHandlers/TransactionDomainEventHandlerTests.cs b/TransactionProcessor.BusinessLogic.Tests/DomainEventHandlers/TransactionDomainEventHandlerTests.cs index cab65792..34cd8248 100644 --- a/TransactionProcessor.BusinessLogic.Tests/DomainEventHandlers/TransactionDomainEventHandlerTests.cs +++ b/TransactionProcessor.BusinessLogic.Tests/DomainEventHandlers/TransactionDomainEventHandlerTests.cs @@ -1,5 +1,6 @@ using MediatR; using SimpleResults; +using TransactionProcessor.Float.DomainEvents; namespace TransactionProcessor.BusinessLogic.Tests.DomainEventHandlers { @@ -35,8 +36,10 @@ namespace TransactionProcessor.BusinessLogic.Tests.DomainEventHandlers using Shouldly; using Testing; using TransactionAggregate; + using TransactionProcessor.Settlement.DomainEvents; + using TransactionProcessor.Transaction.DomainEvents; using Xunit; - /* + public class TransactionDomainEventHandlerTests { private Mock> SettlementAggregateRepository; @@ -86,390 +89,37 @@ public TransactionDomainEventHandlerTests() this.FloatActivityAggregateRepository.Object, this.MemoryCache.Object, this.Mediator.Object); + + this.Mediator.Setup(s => s.Send(It.IsAny>(), It.IsAny())).ReturnsAsync(Result.Success()); } + [Theory] - [InlineData(EstateManagement.DataTransferObjects.Responses.Merchant.SettlementSchedule.Immediate)] - [InlineData(EstateManagement.DataTransferObjects.Responses.Merchant.SettlementSchedule.Weekly)] - [InlineData(EstateManagement.DataTransferObjects.Responses.Merchant.SettlementSchedule.Monthly)] - public async Task TransactionDomainEventHandler_Handle_TransactionHasBeenCompletedEvent_SuccessfulSale_EventIsHandled(EstateManagement.DataTransferObjects.Responses.Merchant.SettlementSchedule settlementSchedule) - { - this.FloatActivityAggregateRepository.Setup(f => f.GetLatestVersionFromLastEvent(It.IsAny(), It.IsAny())).ReturnsAsync(Result.Success(TestData.GetEmptyFloatActivityAggregate())); - - TransactionAggregate transactionAggregate = TestData.GetCompletedAuthorisedSaleTransactionAggregate(); - this.TransactionAggregateRepository.Setup(t => t.GetLatestVersion(It.IsAny(), It.IsAny())) - .ReturnsAsync(transactionAggregate); - - this.FeeCalculationManager.Setup(f => f.CalculateFees(It.IsAny>(), It.IsAny(), It.IsAny())).Returns(new List - { - TestData.CalculatedFeeMerchantFee(TestData.TransactionFeeId), - TestData.CalculatedFeeServiceProviderFee(TestData.TransactionFeeId2) - }); - - this.EstateClient.Setup(e => e.GetMerchant(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) - .ReturnsAsync(new EstateManagement.DataTransferObjects.Responses.Merchant.MerchantResponse - { - SettlementSchedule = settlementSchedule, - }); - 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); - - this.MemoryCache.Setup(m => m.Set(It.IsAny(), It.IsAny(), It.IsAny())); - - await this.TransactionDomainEventHandler.Handle(TestData.TransactionHasBeenCompletedEvent, CancellationToken.None); - - CalculatedFee merchantFee = transactionAggregate.GetFees().SingleOrDefault(f => f.FeeId == TestData.TransactionFeeId); - merchantFee.ShouldNotBeNull(); - if (settlementSchedule == EstateManagement.DataTransferObjects.Responses.Merchant.SettlementSchedule.Immediate){ - merchantFee.IsSettled.ShouldBeTrue(); - } - else{ - merchantFee.IsSettled.ShouldBeFalse(); - } - - DateTime expectedSettlementDate = settlementSchedule switch{ - EstateManagement.DataTransferObjects.Responses.Merchant.SettlementSchedule.Monthly => transactionAggregate.TransactionDateTime.Date.AddMonths(1), - EstateManagement.DataTransferObjects.Responses.Merchant.SettlementSchedule.Weekly => transactionAggregate.TransactionDateTime.Date.AddDays(7), - _ => transactionAggregate.TransactionDateTime.Date + [InlineData(typeof(FloatCreditPurchasedEvent))] + [InlineData(typeof(TransactionCostInformationRecordedEvent))] + [InlineData(typeof(TransactionHasBeenCompletedEvent))] + [InlineData(typeof(MerchantFeePendingSettlementAddedToTransactionEvent))] + [InlineData(typeof(SettledMerchantFeeAddedToTransactionEvent))] + [InlineData(typeof(MerchantFeeSettledEvent))] + //[InlineData(typeof(CustomerEmailReceiptRequestedEvent))] + //[InlineData(typeof(CustomerEmailReceiptResendRequestedEvent))] + public async Task TransactionDomainEventHandler_EventPassedIn_EventIsHandled(Type eventType) { + DomainEvent domainEvent = eventType.Name switch { + nameof(FloatCreditPurchasedEvent) => new FloatCreditPurchasedEvent(TestData.FloatAggregateId, TestData.EstateId, TestData.CreditPurchasedDateTime, TestData.FloatCreditAmount, TestData.FloatCreditCostPrice), + nameof(TransactionCostInformationRecordedEvent) => TestData.TransactionCostInformationRecordedEvent, + nameof(TransactionHasBeenCompletedEvent) => TestData.TransactionHasBeenCompletedEvent, + nameof(MerchantFeePendingSettlementAddedToTransactionEvent) => new MerchantFeePendingSettlementAddedToTransactionEvent(TestData.TransactionId, TestData.EstateId, TestData.MerchantId, TestData.CalculatedFeeValue, 0, TestData.TransactionFeeId, TestData.TransactionFeeValue, TestData.TransactionFeeCalculateDateTime, TestData.TransactionFeeSettlementDueDate, TestData.TransactionDateTime), + nameof(SettledMerchantFeeAddedToTransactionEvent)=> TestData.SettledMerchantFeeAddedToTransactionEvent(TestData.SettlementDate), + nameof(MerchantFeeSettledEvent)=> new MerchantFeeSettledEvent(TestData.SettlementAggregateId, TestData.EstateId, TestData.MerchantId, TestData.TransactionId, TestData.CalculatedFeeValue, 0, TestData.TransactionFeeId, TestData.TransactionFeeValue, TestData.TransactionFeeCalculateDateTime, TestData.SettlementDate), + nameof(CustomerEmailReceiptRequestedEvent)=> TestData.CustomerEmailReceiptRequestedEvent, + nameof(CustomerEmailReceiptResendRequestedEvent)=> TestData.CustomerEmailReceiptResendRequestedEvent, + _ => throw new NotSupportedException($"Event {eventType.Name} not supported") }; - merchantFee.SettlementDueDate.ShouldBe(expectedSettlementDate); - - CalculatedFee nonMerchantFee = transactionAggregate.GetFees().SingleOrDefault(f => f.FeeId == TestData.TransactionFeeId2); - nonMerchantFee.ShouldNotBeNull(); - } - - [Theory(Skip = "investigation on caching atm")] - [InlineData(EstateManagement.DataTransferObjects.Responses.Merchant.SettlementSchedule.Immediate)] - [InlineData(EstateManagement.DataTransferObjects.Responses.Merchant.SettlementSchedule.Weekly)] - [InlineData(EstateManagement.DataTransferObjects.Responses.Merchant.SettlementSchedule.Monthly)] - public async Task TransactionDomainEventHandler_Handle_TransactionHasBeenCompletedEvent_SuccessfulSale_FeesAlreadyCached_EventIsHandled(EstateManagement.DataTransferObjects.Responses.Merchant.SettlementSchedule settlementSchedule) - { - this.FloatActivityAggregateRepository.Setup(f => f.GetLatestVersionFromLastEvent(It.IsAny(), It.IsAny())).ReturnsAsync(Result.Success(TestData.GetEmptyFloatActivityAggregate())); - - TransactionAggregate transactionAggregate = TestData.GetCompletedAuthorisedSaleTransactionAggregate(); - this.TransactionAggregateRepository.Setup(t => t.GetLatestVersion(It.IsAny(), It.IsAny())) - .ReturnsAsync(transactionAggregate); - - this.FeeCalculationManager.Setup(f => f.CalculateFees(It.IsAny>(), It.IsAny(), It.IsAny())).Returns(new List - { - TestData.CalculatedFeeMerchantFee(TestData.TransactionFeeId), - TestData.CalculatedFeeServiceProviderFee(TestData.TransactionFeeId2) - }); - - this.EstateClient.Setup(e => e.GetMerchant(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) - .ReturnsAsync(new EstateManagement.DataTransferObjects.Responses.Merchant.MerchantResponse - { - SettlementSchedule = settlementSchedule, - }); - - this.MemoryCache.Setup(m => m.TryGetValue(It.IsAny(), out It.Ref>.IsAny)) - .Returns((Object key, out List value) => - { - value = TestData.ContractProductTransactionFees; // Set the out parameter - return true; // Return value indicating success - }); - - this.SecurityServiceClient.Setup(s => s.GetToken(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(TestData.TokenResponse); - - this.MemoryCache.Setup(m => m.Set(It.IsAny(), It.IsAny(), It.IsAny())); - - await this.TransactionDomainEventHandler.Handle(TestData.TransactionHasBeenCompletedEvent, CancellationToken.None); - - CalculatedFee merchantFee = transactionAggregate.GetFees().SingleOrDefault(f => f.FeeId == TestData.TransactionFeeId); - merchantFee.ShouldNotBeNull(); - if (settlementSchedule == EstateManagement.DataTransferObjects.Responses.Merchant.SettlementSchedule.Immediate) - { - merchantFee.IsSettled.ShouldBeTrue(); - } - else - { - merchantFee.IsSettled.ShouldBeFalse(); - } - - DateTime expectedSettlementDate = settlementSchedule switch - { - EstateManagement.DataTransferObjects.Responses.Merchant.SettlementSchedule.Monthly => transactionAggregate.TransactionDateTime.Date.AddMonths(1), - EstateManagement.DataTransferObjects.Responses.Merchant.SettlementSchedule.Weekly => transactionAggregate.TransactionDateTime.Date.AddDays(7), - _ => transactionAggregate.TransactionDateTime.Date - }; - merchantFee.SettlementDueDate.ShouldBe(expectedSettlementDate); - - CalculatedFee nonMerchantFee = transactionAggregate.GetFees().SingleOrDefault(f => f.FeeId == TestData.TransactionFeeId2); - nonMerchantFee.ShouldNotBeNull(); - } - - [Fact] - public async Task TransactionDomainEventHandler_Handle_TransactionHasBeenCompletedEvent_SuccessfulSale_MerchantWithNotSetSettlementSchedule_ErrorThrown() - { - this.FloatActivityAggregateRepository.Setup(f => f.GetLatestVersionFromLastEvent(It.IsAny(), It.IsAny())).ReturnsAsync(Result.Success(TestData.GetEmptyFloatActivityAggregate())); - - TransactionAggregate transactionAggregate = TestData.GetCompletedAuthorisedSaleTransactionAggregate(); - this.TransactionAggregateRepository.Setup(t => t.GetLatestVersion(It.IsAny(), It.IsAny())) - .ReturnsAsync(transactionAggregate); - this.FeeCalculationManager.Setup(f => f.CalculateFees(It.IsAny>(), It.IsAny(), It.IsAny())).Returns(new List - { - TestData.CalculatedFeeMerchantFee(TestData.TransactionFeeId), - TestData.CalculatedFeeServiceProviderFee(TestData.TransactionFeeId2) - }); - - this.EstateClient.Setup(e => e.GetMerchant(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) - .ReturnsAsync(new EstateManagement.DataTransferObjects.Responses.Merchant.MerchantResponse - { - SettlementSchedule = EstateManagement.DataTransferObjects.Responses.Merchant.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); - - this.MemoryCache.Setup(m => m.Set(It.IsAny(), It.IsAny(), It.IsAny())); - - var result = await this.TransactionDomainEventHandler.Handle(TestData.TransactionHasBeenCompletedEvent, CancellationToken.None); + var result = await this.TransactionDomainEventHandler.Handle(domainEvent, CancellationToken.None); result.IsSuccess.ShouldBeTrue(); } - - [Fact] - public async Task TransactionDomainEventHandler_Handle_TransactionHasBeenCompletedEvent_UnsuccessfulSale_EventIsHandled() - { - this.FloatActivityAggregateRepository.Setup(f => f.GetLatestVersionFromLastEvent(It.IsAny(), It.IsAny())).ReturnsAsync(Result.Success(TestData.GetEmptyFloatActivityAggregate())); - - this.TransactionAggregateRepository.Setup(t => t.GetLatestVersion(It.IsAny(), It.IsAny())) - .ReturnsAsync(Result.Success(TestData.GetCompletedDeclinedSaleTransactionAggregate())); - - await this.TransactionDomainEventHandler.Handle(TestData.TransactionHasBeenCompletedEvent, CancellationToken.None); - } - - [Fact] - public async Task TransactionDomainEventHandler_Handle_TransactionHasBeenCompletedEvent_IncompleteSale_EventIsHandled() - { - this.FloatActivityAggregateRepository.Setup(f => f.GetLatestVersionFromLastEvent(It.IsAny(), It.IsAny())).ReturnsAsync(Result.Success(TestData.GetEmptyFloatActivityAggregate())); - - this.TransactionAggregateRepository.Setup(t => t.GetLatestVersion(It.IsAny(), It.IsAny())) - .ReturnsAsync(Result.Success(TestData.GetIncompleteAuthorisedSaleTransactionAggregate())); - await this.TransactionDomainEventHandler.Handle(TestData.TransactionHasBeenCompletedEvent, CancellationToken.None); - } - - [Fact] - public async Task TransactionDomainEventHandler_Handle_TransactionHasBeenCompletedEvent_SaleWithNoProductDetails_EventIsHandled() - { - this.FloatActivityAggregateRepository.Setup(f => f.GetLatestVersionFromLastEvent(It.IsAny(), It.IsAny())).ReturnsAsync(Result.Success(TestData.GetEmptyFloatActivityAggregate())); - - this.TransactionAggregateRepository.Setup(t => t.GetLatestVersion(It.IsAny(), It.IsAny())) - .ReturnsAsync(Result.Success(TestData.GetCompletedAuthorisedSaleWithNoProductDetailsTransactionAggregate())); - - await this.TransactionDomainEventHandler.Handle(TestData.TransactionHasBeenCompletedEvent, CancellationToken.None); - } - - [Fact] - public async Task TransactionDomainEventHandler_Handle_TransactionHasBeenCompletedEvent_AuthorisedLogon_EventIsHandled(){ - this.FloatActivityAggregateRepository.Setup(f => f.GetLatestVersionFromLastEvent(It.IsAny(), It.IsAny())).ReturnsAsync(Result.Success(TestData.GetEmptyFloatActivityAggregate())); - - this.TransactionAggregateRepository.Setup(t => t.GetLatestVersion(It.IsAny(), It.IsAny())) - .ReturnsAsync(Result.Success(TestData.GetCompletedAuthorisedLogonTransactionAggregate())); - - await this.TransactionDomainEventHandler.Handle(TestData.TransactionHasBeenCompletedEvent, CancellationToken.None); - } - - [Fact] - public async Task TransactionDomainEventHandler_Handle_CustomerEmailReceiptRequestedEvent_EventIsHandled() - { - this.TransactionAggregateRepository.Setup(t => t.GetLatestVersion(It.IsAny(), It.IsAny())) - .ReturnsAsync(Result.Success(TestData.GetCompletedAuthorisedSaleTransactionAggregate())); - this.TransactionAggregateRepository.Setup(t => t.SaveChanges(It.IsAny(), It.IsAny())) - .ReturnsAsync(Result.Success()); - this.EstateClient.Setup(e => e.GetEstate(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(TestData.GetEstateResponseWithOperator1); - this.EstateClient.Setup(e => e.GetMerchant(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(TestData.GetMerchantResponseWithOperator1); - - this.SecurityServiceClient.Setup(s => s.GetToken(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(TestData.TokenResponse); - - this.MessagingServiceClient - .Setup(m => m.SendEmail(It.IsAny(), It.IsAny(), - It.IsAny())).ReturnsAsync(Result.Success); - - var result = await this.TransactionDomainEventHandler.Handle(TestData.CustomerEmailReceiptRequestedEvent, CancellationToken.None); - result.IsSuccess.ShouldBeTrue(); - } - - [Fact] - public async Task TransactionDomainEventHandler_Handle_CustomerEmailReceiptResendRequestedEvent_EventIsHandled() - { - this.SecurityServiceClient.Setup(s => s.GetToken(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(TestData.TokenResponse); - - await this.TransactionDomainEventHandler.Handle(TestData.CustomerEmailReceiptResendRequestedEvent, CancellationToken.None); - - this.MessagingServiceClient.Verify(v => v.ResendEmail(It.IsAny(), - It.IsAny(), - It.IsAny()), Times.Once); - } - - [Fact] - public async Task TransactionDomainEventHandler_Handle_TransactionCostInformationRecordedEvent_EventIsHandled(){ - this.TransactionAggregateRepository.Setup(t => t.GetLatestVersion(It.IsAny(), It.IsAny())) - .ReturnsAsync(Result.Success(TestData.GetCompletedAuthorisedSaleTransactionAggregate())); - this.TransactionAggregateRepository.Setup(t => t.SaveChanges(It.IsAny(), It.IsAny())) - .ReturnsAsync(Result.Success()); - this.FloatActivityAggregateRepository.Setup(f => f.GetLatestVersionFromLastEvent(It.IsAny(), It.IsAny())).ReturnsAsync(Result.Success(TestData.GetEmptyFloatActivityAggregate())); - - await this.TransactionDomainEventHandler.Handle(TestData.TransactionCostInformationRecordedEvent, CancellationToken.None); - - this.FloatActivityAggregateRepository.Verify(f => f.SaveChanges(It.IsAny(), It.IsAny()), Times.Once); - } - - [Fact] - public async Task TransactionDomainEventHandler_Handle_TransactionCostInformationRecordedEvent_TransactionNotAuthorised_EventIsHandled() - { - this.TransactionAggregateRepository.Setup(t => t.GetLatestVersion(It.IsAny(), It.IsAny())) - .ReturnsAsync(Result.Success(TestData.GetCompletedDeclinedSaleTransactionAggregate())); - - this.FloatActivityAggregateRepository.Setup(f => f.GetLatestVersionFromLastEvent(It.IsAny(), It.IsAny())).ReturnsAsync(Result.Success(TestData.GetEmptyFloatActivityAggregate())); - - await this.TransactionDomainEventHandler.Handle(TestData.TransactionCostInformationRecordedEvent, CancellationToken.None); - - this.FloatActivityAggregateRepository.Verify(f => f.SaveChanges(It.IsAny(), It.IsAny()), Times.Never); - } - - [Fact] - public async Task TransactionDomainEventHandler_Handle_TransactionCostInformationRecordedEvent_TransactionNotCompleted_EventIsHandled() - { - - var result = await this.TransactionDomainEventHandler.Handle(TestData.TransactionCostInformationRecordedEvent, CancellationToken.None); - - result.IsSuccess.ShouldBeTrue(); - } - - //[Fact] - //public async Task TransactionDomainEventHandler_Handle_MerchantFeeAddedToTransactionEvent_EventIsHandled() - //{ - // this.SettlementAggregateRepository.Setup(s => s.GetLatestVersion(It.IsAny(), It.IsAny())) - // .ReturnsAsync(TestData.GetSettlementAggregateWithPendingMerchantFees(1)); - - // await this.TransactionDomainEventHandler.Handle(TestData.SettledMerchantFeeAddedToTransactionEvent(TestData.TransactionFeeSettlementDueDate), CancellationToken.None); - //} - - //[Fact] - //public async Task TransactionDomainEventHandler_Handle_MerchantFeeAddedToTransactionEvent_EventHasNoSettlementDueDate_EventIsHandled() - //{ - // await this.TransactionDomainEventHandler.Handle(TestData.SettledMerchantFeeAddedToTransactionEvent(DateTime.MinValue), CancellationToken.None); - //} - - [Fact] - public async Task TransactionDomainEventHandler_RequireFeeCalculation_IsNotAuthorised_ReturnsFalse(){ - - TransactionAggregate transactionAggregate = TransactionAggregate.Create(TestData.TransactionId); - transactionAggregate.StartTransaction(TestData.TransactionDateTime, TestData.TransactionNumber, - TransactionType.Sale, TestData.TransactionReference, - TestData.EstateId, TestData.MerchantId, TestData.DeviceIdentifier, - TestData.TransactionAmount); - transactionAggregate.DeclineTransaction(TestData.OperatorId, "111", "SUCCESS", "0000", "SUCCESS"); - - var result = TransactionDomainEventHandler.RequireFeeCalculation(transactionAggregate); - result.ShouldBeFalse(); - } - - [Fact] - public async Task TransactionDomainEventHandler_RequireFeeCalculation_IsNotCompelted_ReturnsFalse() - { - TransactionAggregate transactionAggregate = TransactionAggregate.Create(TestData.TransactionId); - transactionAggregate.StartTransaction(TestData.TransactionDateTime, TestData.TransactionNumber, - TransactionType.Sale, TestData.TransactionReference, - TestData.EstateId, TestData.MerchantId, TestData.DeviceIdentifier, - TestData.TransactionAmount); - transactionAggregate.AuthoriseTransaction(TestData.OperatorId, "111", "111", "SUCCESS", "1234", "0000", "SUCCESS"); - - var result = TransactionDomainEventHandler.RequireFeeCalculation(transactionAggregate); - result.ShouldBeFalse(); - } - - [Fact] - public async Task TransactionDomainEventHandler_RequireFeeCalculation_IsALogon_ReturnsFalse() - { - TransactionAggregate transactionAggregate = TransactionAggregate.Create(TestData.TransactionId); - transactionAggregate.StartTransaction(TestData.TransactionDateTime, TestData.TransactionNumber, - TransactionType.Logon, TestData.TransactionReference, - TestData.EstateId, TestData.MerchantId, TestData.DeviceIdentifier, - TestData.TransactionAmount); - transactionAggregate.AuthoriseTransactionLocally("111", "0001", "SUCCESS"); - transactionAggregate.CompleteTransaction(); - - - var result = TransactionDomainEventHandler.RequireFeeCalculation(transactionAggregate); - result.ShouldBeFalse(); - } - - [Fact] - public async Task TransactionDomainEventHandler_RequireFeeCalculation_NoContractId_ReturnsFalse() - { - TransactionAggregate transactionAggregate = TransactionAggregate.Create(TestData.TransactionId); - transactionAggregate.StartTransaction(TestData.TransactionDateTime, TestData.TransactionNumber, - TransactionType.Sale, TestData.TransactionReference, - TestData.EstateId, TestData.MerchantId, TestData.DeviceIdentifier, - TestData.TransactionAmount); - transactionAggregate.AuthoriseTransaction(TestData.OperatorId, "111", "111", "SUCCESS", "1234", "0000", "SUCCESS"); - transactionAggregate.CompleteTransaction(); - - - var result = TransactionDomainEventHandler.RequireFeeCalculation(transactionAggregate); - result.ShouldBeFalse(); - } - - [Fact] - public async Task TransactionDomainEventHandler_RequireFeeCalculation_NullAmount_ReturnsFalse() - { - TransactionAggregate transactionAggregate = TransactionAggregate.Create(TestData.TransactionId); - transactionAggregate.StartTransaction(TestData.TransactionDateTime, TestData.TransactionNumber, - TransactionType.Sale, TestData.TransactionReference, - TestData.EstateId, TestData.MerchantId, TestData.DeviceIdentifier, - null); - transactionAggregate.AddProductDetails(TestData.ContractId, TestData.ProductId); - transactionAggregate.AuthoriseTransaction(TestData.OperatorId, "111", "111", "SUCCESS", "1234", "0000", "SUCCESS"); - transactionAggregate.CompleteTransaction(); - - - var result = TransactionDomainEventHandler.RequireFeeCalculation(transactionAggregate); - result.ShouldBeFalse(); - } - - [Fact] - public async Task TransactionDomainEventHandler_RequireFeeCalculation_ReturnsTrue() - { - TransactionAggregate transactionAggregate = TransactionAggregate.Create(TestData.TransactionId); - transactionAggregate.StartTransaction(TestData.TransactionDateTime, TestData.TransactionNumber, - TransactionType.Sale, TestData.TransactionReference, - TestData.EstateId, TestData.MerchantId, TestData.DeviceIdentifier, - TestData.TransactionAmount); - transactionAggregate.AddProductDetails(TestData.ContractId, TestData.ProductId); - transactionAggregate.AuthoriseTransaction(TestData.OperatorId, "111", "111", "SUCCESS", "1234", "0000", "SUCCESS"); - transactionAggregate.CompleteTransaction(); - - - var result = TransactionDomainEventHandler.RequireFeeCalculation(transactionAggregate); - result.ShouldBeTrue(); - } - - [Theory] - [InlineData(SettlementSchedule.Immediate, "2024-05-01", "2024-05-01")] - [InlineData(SettlementSchedule.NotSet, "2024-05-01", "2024-05-01")] - [InlineData(SettlementSchedule.Weekly, "2024-05-01", "2024-05-08")] - [InlineData(SettlementSchedule.Monthly, "2024-05-01", "2024-06-01")] - public async Task TransactionDomainEventHandler_CalculateSettlementDate_CorrectDateReturned(SettlementSchedule settlementSchedule, String completedDateString, String expectedDateString){ - - DateTime completedDate = DateTime.ParseExact(completedDateString, "yyyy-MM-dd", null); - DateTime expectedDate = DateTime.ParseExact(expectedDateString, "yyyy-MM-dd", null); - DateTime result = TransactionDomainEventHandler.CalculateSettlementDate(settlementSchedule, completedDate); - result.Date.ShouldBe(expectedDate.Date); - } - }*/ + } } diff --git a/TransactionProcessor.BusinessLogic.Tests/Manager/FeeCalculationManagerTests.cs b/TransactionProcessor.BusinessLogic.Tests/Manager/FeeCalculationManagerTests.cs index ef8d0a93..2900fb99 100644 --- a/TransactionProcessor.BusinessLogic.Tests/Manager/FeeCalculationManagerTests.cs +++ b/TransactionProcessor.BusinessLogic.Tests/Manager/FeeCalculationManagerTests.cs @@ -34,6 +34,27 @@ public void FeeCalculationManager_CalculateFees_SingleFixedFee_ServiceFee_FeesAr calculatedFee.FeeValue.ShouldBe(FeeCalculationManagerTestData.FixedServiceFee5.Value); } + [Fact] + public void FeeCalculationManager_CalculateFees_SingleFixedFee_ServiceFee_WithCalculationDate_FeesAreCalculated() + { + IFeeCalculationManager manager = new FeeCalculationManager(); + + List feesList = new List + { + FeeCalculationManagerTestData.FixedServiceFee5 + }; + + List calculatedFees = manager.CalculateFees(feesList, FeeCalculationManagerTestData.TransactionAmount100, DateTime.Now); + + calculatedFees.ShouldHaveSingleItem(); + CalculatedFee calculatedFee = calculatedFees.Single(); + calculatedFee.CalculatedValue.ShouldBe(5.0m); + calculatedFee.FeeType.ShouldBe(FeeCalculationManagerTestData.FixedServiceFee5.FeeType); + calculatedFee.FeeCalculationType.ShouldBe(FeeCalculationManagerTestData.FixedServiceFee5.CalculationType); + calculatedFee.FeeId.ShouldBe(FeeCalculationManagerTestData.FixedServiceFee5.FeeId); + calculatedFee.FeeValue.ShouldBe(FeeCalculationManagerTestData.FixedServiceFee5.Value); + } + [Fact] public void FeeCalculationManager_CalculateFees_MultipleFixedFees_ServiceFee_FeesAreCalculated() { @@ -83,6 +104,27 @@ public void FeeCalculationManager_CalculateFees_SinglePercentageFee_ServiceFee_F calculatedFee.FeeValue.ShouldBe(FeeCalculationManagerTestData.PercentageServiceFeeQuarterPercent.Value); } + [Fact] + public void FeeCalculationManager_CalculateFees_SinglePercentageFee_ServiceFee_WithFixedDate_FeesAreCalculated() + { + IFeeCalculationManager manager = new FeeCalculationManager(); + + List feesList = new List + { + FeeCalculationManagerTestData.PercentageServiceFeeQuarterPercent + }; + + List calculatedFees = manager.CalculateFees(feesList, FeeCalculationManagerTestData.TransactionAmount100, DateTime.Now); + + calculatedFees.ShouldHaveSingleItem(); + CalculatedFee calculatedFee = calculatedFees.Single(); + calculatedFee.CalculatedValue.ShouldBe(0.25m); + calculatedFee.FeeType.ShouldBe(FeeCalculationManagerTestData.PercentageServiceFeeQuarterPercent.FeeType); + calculatedFee.FeeCalculationType.ShouldBe(FeeCalculationManagerTestData.PercentageServiceFeeQuarterPercent.CalculationType); + calculatedFee.FeeId.ShouldBe(FeeCalculationManagerTestData.PercentageServiceFeeQuarterPercent.FeeId); + calculatedFee.FeeValue.ShouldBe(FeeCalculationManagerTestData.PercentageServiceFeeQuarterPercent.Value); + } + [Fact] public void FeeCalculationManager_CalculateFees_MultiplePercentageFees_ServiceFee_FeesAreCalculated() { diff --git a/TransactionProcessor.BusinessLogic.Tests/Mediator/DummyTransactionDomainService.cs b/TransactionProcessor.BusinessLogic.Tests/Mediator/DummyTransactionDomainService.cs index c44cdfab..36fcd065 100644 --- a/TransactionProcessor.BusinessLogic.Tests/Mediator/DummyTransactionDomainService.cs +++ b/TransactionProcessor.BusinessLogic.Tests/Mediator/DummyTransactionDomainService.cs @@ -1,5 +1,10 @@ -using SimpleResults; +using EventStore.Client; +using Newtonsoft.Json; +using SimpleResults; using TransactionProcessor.BusinessLogic.Requests; +using TransactionProcessor.ProjectionEngine.Models; +using TransactionProcessor.ProjectionEngine.Repository; +using TransactionProcessor.ProjectionEngine.State; namespace TransactionProcessor.BusinessLogic.Tests.Mediator; @@ -9,6 +14,8 @@ namespace TransactionProcessor.BusinessLogic.Tests.Mediator; using System.Threading.Tasks; using BusinessLogic.Services; using Models; +using Shared.DomainDrivenDesign.EventSourcing; +using Shared.EventStore.EventStore; public class DummyTransactionDomainService : ITransactionDomainService { @@ -39,3 +46,93 @@ public async Task AddSettledMerchantFee(TransactionCommands.AddSettledMe CancellationToken cancellationToken) => Result.Success(); } + +public class DummyMerchantBalanceStateRepository : IProjectionStateRepository +{ + public async Task> Load(IDomainEvent @event, CancellationToken cancellationToken) { + return new MerchantBalanceState(); + } + + public async Task> Load(Guid estateId, Guid stateId, CancellationToken cancellationToken) + { + return new MerchantBalanceState(); + } + + public async Task> Save(MerchantBalanceState state, IDomainEvent @event, CancellationToken cancellationToken) { + return state; + } +} + +public class DummyTransactionProcessorReadRepository : ITransactionProcessorReadRepository { + public async Task AddMerchantBalanceChangedEntry(MerchantBalanceChangedEntry entry, + CancellationToken cancellationToken) { + return Result.Success(); + } + + public async Task>> GetMerchantBalanceHistory(Guid estateId, + Guid merchantId, + DateTime startDate, + DateTime endDate, + CancellationToken cancellationToken) { + return Result.Success(); + } +} + +public class DummyEventStoreContext : IEventStoreContext { + public async Task>> GetEventsBackward(String streamName, + Int32 maxNumberOfEventsToRetrieve, + CancellationToken cancellationToken) { + return Result.Success(); + } + + public async Task> GetPartitionResultFromProjection(String projectionName, + String partitionId, + CancellationToken cancellationToken) { + return Result.Success(); + } + + public async Task> GetPartitionStateFromProjection(String projectionName, + String partitionId, + CancellationToken cancellationToken) { + MerchantBalanceProjectionState1 state = new MerchantBalanceProjectionState1(new Merchant("", "", 0, 0, new Deposits(0, 0, DateTime.MinValue), new Withdrawals(0, 0, DateTime.MinValue), new AuthorisedSales(0, 0, DateTime.MinValue), new DeclinedSales(0, 0, DateTime.MinValue), new Fees(0, 0)) { }); + return Result.Success(JsonConvert.SerializeObject(state)); + } + + public async Task> GetResultFromProjection(String projectionName, + CancellationToken cancellationToken) { + return Result.Success(); + } + + public async Task> GetStateFromProjection(String projectionName, + CancellationToken cancellationToken) { + return Result.Success(); + } + + public async Task InsertEvents(String streamName, + Int64 expectedVersion, + List aggregateEvents, + CancellationToken cancellationToken) { + return Result.Success(); + } + + public async Task InsertEvents(String streamName, + Int64 expectedVersion, + List aggregateEvents, + Object metadata, + CancellationToken cancellationToken) { + return Result.Success(); + } + + public async Task>> ReadEvents(String streamName, + Int64 fromVersion, + CancellationToken cancellationToken) { + return Result.Success(); + } + + public async Task> RunTransientQuery(String query, + CancellationToken cancellationToken) { + return Result.Success(); + } + + public event TraceHandler TraceGenerated; +} diff --git a/TransactionProcessor.BusinessLogic.Tests/Mediator/MediatorTests.cs b/TransactionProcessor.BusinessLogic.Tests/Mediator/MediatorTests.cs index b3e59f77..e9d60b6a 100644 --- a/TransactionProcessor.BusinessLogic.Tests/Mediator/MediatorTests.cs +++ b/TransactionProcessor.BusinessLogic.Tests/Mediator/MediatorTests.cs @@ -9,6 +9,8 @@ using System.Linq; using System.Text; using System.Threading.Tasks; +using Shared.EventStore.EventStore; +using TransactionProcessor.ProjectionEngine.Repository; using Xunit; namespace TransactionProcessor.BusinessLogic.Tests.Mediator @@ -17,6 +19,7 @@ namespace TransactionProcessor.BusinessLogic.Tests.Mediator using Lamar; using Microsoft.Extensions.DependencyInjection; using Testing; + using TransactionProcessor.ProjectionEngine.State; public class MediatorTests { @@ -28,6 +31,20 @@ public MediatorTests() this.Requests.Add(TestData.ProcessReconciliationCommand); this.Requests.Add(TestData.ProcessSaleTransactionCommand); this.Requests.Add(TestData.ProcessSettlementCommand); + this.Requests.Add(TestData.GetMerchantBalanceQuery); + this.Requests.Add(TestData.GetMerchantLiveBalanceQuery); + this.Requests.Add(TestData.GetMerchantBalanceHistoryQuery); + this.Requests.Add(TestData.AddMerchantFeePendingSettlementCommand); + this.Requests.Add(TestData.AddSettledFeeToSettlementCommand); + this.Requests.Add(TestData.GetPendingSettlementQuery); + this.Requests.Add(TestData.RecordCreditPurchaseCommand); + this.Requests.Add(TestData.CalculateFeesForTransactionCommand); + this.Requests.Add(TestData.AddSettledMerchantFeeCommand); + // TODO: this needs the query handling function refactoring to use a repository not the context direct + //this.Requests.Add(TestData.GetVoucherByVoucherCodeQuery); + //this.Requests.Add(TestData.GetVoucherByTransactionIdQuery); + + } [Fact] @@ -56,7 +73,7 @@ public async Task Mediator_Send_RequestHandled() } catch (Exception ex) { - errors.Add(ex.Message); + errors.Add($"Command: {baseRequest.GetType().Name} Exception: {ex.Message}"); } } @@ -70,7 +87,7 @@ public async Task Mediator_Send_RequestHandled() private IConfigurationRoot SetupMemoryConfiguration() { Dictionary configuration = new Dictionary(); - + IConfigurationBuilder builder = new ConfigurationBuilder(); builder.AddInMemoryCollection(TestData.DefaultAppSettings); @@ -93,6 +110,9 @@ private void AddTestRegistrations(ServiceRegistry services, s.AddSingleton(); s.AddSingleton(); s.AddSingleton(); + s.AddSingleton, DummyMerchantBalanceStateRepository>(); + s.AddSingleton(); + s.AddSingleton(); }); } } diff --git a/TransactionProcessor.BusinessLogic.Tests/Services/DomainServiceHelperTests.cs b/TransactionProcessor.BusinessLogic.Tests/Services/DomainServiceHelperTests.cs new file mode 100644 index 00000000..222a9dfa --- /dev/null +++ b/TransactionProcessor.BusinessLogic.Tests/Services/DomainServiceHelperTests.cs @@ -0,0 +1,74 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Shared.DomainDrivenDesign.EventSourcing; +using Shared.EventStore.Aggregate; +using Shouldly; +using SimpleResults; +using TransactionProcessor.BusinessLogic.Services; +using Xunit; + +namespace TransactionProcessor.BusinessLogic.Tests.Services +{ + public class DomainServiceHelperTests + { + [Fact] + public void DomainServiceHelper_HandleGetAggregateResult_SuccessfulGet_ResultHandled() { + Guid aggregateId = Guid.Parse("0639682D-1D28-4AD8-B29D-4B76619083F1"); + Result result = Result.Success(new TestAggregate { + AggregateId = aggregateId}); + + var handleResult = DomainServiceHelper.HandleGetAggregateResult(result, aggregateId, true); + handleResult.IsSuccess.ShouldBeTrue(); + handleResult.Data.ShouldBeOfType(typeof(TestAggregate)); + handleResult.Data.AggregateId.ShouldBe(aggregateId); + } + + [Fact] + public void DomainServiceHelper_HandleGetAggregateResult_FailedGet_ResultHandled() + { + Guid aggregateId = Guid.Parse("0639682D-1D28-4AD8-B29D-4B76619083F1"); + Result result = Result.Failure("Failed Get"); + + var handleResult = DomainServiceHelper.HandleGetAggregateResult(result, aggregateId, true); + handleResult.IsFailed.ShouldBeTrue(); + handleResult.Message.ShouldBe("Failed Get"); + } + + [Fact] + public void DomainServiceHelper_HandleGetAggregateResult_FailedGet_NotFoundButIsError_ResultHandled() + { + Guid aggregateId = Guid.Parse("0639682D-1D28-4AD8-B29D-4B76619083F1"); + Result result = Result.NotFound("Failed Get"); + + var handleResult = DomainServiceHelper.HandleGetAggregateResult(result, aggregateId, true); + handleResult.IsFailed.ShouldBeTrue(); + handleResult.Message.ShouldBe("Failed Get"); + } + + [Fact] + public void DomainServiceHelper_HandleGetAggregateResult_FailedGet_NotFoundButIsNotError_ResultHandled() + { + Guid aggregateId = Guid.Parse("0639682D-1D28-4AD8-B29D-4B76619083F1"); + Result result = Result.NotFound("Failed Get"); + + var handleResult = DomainServiceHelper.HandleGetAggregateResult(result, aggregateId, false); + handleResult.IsSuccess.ShouldBeTrue(); + handleResult.Data.ShouldBeOfType(typeof(TestAggregate)); + handleResult.Data.AggregateId.ShouldBe(aggregateId); + } + } + + public record TestAggregate : Aggregate { + public override void PlayEvent(IDomainEvent domainEvent) { + + } + + protected override Object GetMetadata() { + return new Object(); + } + } + +} diff --git a/TransactionProcessor.BusinessLogic.Tests/Services/FloatDomainServiceTests.cs b/TransactionProcessor.BusinessLogic.Tests/Services/FloatDomainServiceTests.cs index 81e42fb1..15cfa669 100644 --- a/TransactionProcessor.BusinessLogic.Tests/Services/FloatDomainServiceTests.cs +++ b/TransactionProcessor.BusinessLogic.Tests/Services/FloatDomainServiceTests.cs @@ -170,5 +170,74 @@ public async Task FloatDomainService_RecordCreditPurchase_PurchaseRecorded(){ var result = await this.FloatDomainService.RecordCreditPurchase(command, CancellationToken.None); result.IsSuccess.ShouldBeTrue(); } + + [Fact] + public async Task FloatDomainService_RecordCreditPurchase_SaveFailed() + { + FloatAggregate floatAggregate = FloatAggregate.Create(TestData.FloatAggregateId); + floatAggregate.CreateFloat(TestData.EstateId, TestData.ContractId, TestData.ProductId, TestData.FloatCreatedDateTime); + this.FloatAggregateRepository.Setup(f => f.GetLatestVersion(It.IsAny(), It.IsAny())).ReturnsAsync(floatAggregate); + this.FloatAggregateRepository.Setup(f => f.SaveChanges(It.IsAny(), It.IsAny())).ReturnsAsync(Result.Failure); + + var command = new FloatCommands.RecordCreditPurchaseForFloatCommand(TestData.EstateId, + TestData.FloatAggregateId, TestData.FloatCreditAmount, TestData.FloatCreditCostPrice, + TestData.CreditPurchasedDateTime); + var result = await this.FloatDomainService.RecordCreditPurchase(command, CancellationToken.None); + result.IsFailed.ShouldBeTrue(); + } + + [Fact] + public async Task FloatDomainService_RecordCreditPurchase_ExceptionThrown() + { + FloatAggregate floatAggregate = FloatAggregate.Create(TestData.FloatAggregateId); + floatAggregate.CreateFloat(TestData.EstateId, TestData.ContractId, TestData.ProductId, TestData.FloatCreatedDateTime); + this.FloatAggregateRepository.Setup(f => f.GetLatestVersion(It.IsAny(), It.IsAny())).ReturnsAsync(floatAggregate); + this.FloatAggregateRepository.Setup(f => f.SaveChanges(It.IsAny(), It.IsAny())).ThrowsAsync(new Exception()); + + var command = new FloatCommands.RecordCreditPurchaseForFloatCommand(TestData.EstateId, + TestData.FloatAggregateId, TestData.FloatCreditAmount, TestData.FloatCreditCostPrice, + TestData.CreditPurchasedDateTime); + var result = await this.FloatDomainService.RecordCreditPurchase(command, CancellationToken.None); + result.IsFailed.ShouldBeTrue(); + } + + [Fact] + public async Task FloatDomainService_RecordCreditPurchase_FloatActivity_PurchaseRecorded() + { + FloatActivityAggregate floatAggregate = FloatActivityAggregate.Create(TestData.FloatAggregateId); + this.FloatActivityAggregateRepository.Setup(f => f.GetLatestVersionFromLastEvent(It.IsAny(), It.IsAny())).ReturnsAsync(floatAggregate); + this.FloatActivityAggregateRepository.Setup(f => f.SaveChanges(It.IsAny(), It.IsAny())).ReturnsAsync(Result.Success); + + var command = new FloatActivityCommands.RecordCreditPurchaseCommand(TestData.EstateId, + TestData.FloatAggregateId, TestData.CreditPurchasedDateTime, TestData.FloatCreditAmount); + var result = await this.FloatDomainService.RecordCreditPurchase(command, CancellationToken.None); + result.IsSuccess.ShouldBeTrue(); + } + + [Fact] + public async Task FloatDomainService_RecordCreditPurchase_FloatActivity_SaveFailed() + { + FloatActivityAggregate floatAggregate = FloatActivityAggregate.Create(TestData.FloatAggregateId); + this.FloatActivityAggregateRepository.Setup(f => f.GetLatestVersionFromLastEvent(It.IsAny(), It.IsAny())).ReturnsAsync(floatAggregate); + this.FloatActivityAggregateRepository.Setup(f => f.SaveChanges(It.IsAny(), It.IsAny())).ReturnsAsync(Result.Failure); + + var command = new FloatActivityCommands.RecordCreditPurchaseCommand(TestData.EstateId, + TestData.FloatAggregateId, TestData.CreditPurchasedDateTime, TestData.FloatCreditAmount); + var result = await this.FloatDomainService.RecordCreditPurchase(command, CancellationToken.None); + result.IsFailed.ShouldBeTrue(); + } + + [Fact] + public async Task FloatDomainService_RecordCreditPurchase_FloatActivity_ExceptionThrown() + { + FloatActivityAggregate floatAggregate = FloatActivityAggregate.Create(TestData.FloatAggregateId); + this.FloatActivityAggregateRepository.Setup(f => f.GetLatestVersionFromLastEvent(It.IsAny(), It.IsAny())).ReturnsAsync(floatAggregate); + this.FloatActivityAggregateRepository.Setup(f => f.SaveChanges(It.IsAny(), It.IsAny())).ThrowsAsync(new Exception()); + + var command = new FloatActivityCommands.RecordCreditPurchaseCommand(TestData.EstateId, + TestData.FloatAggregateId, TestData.CreditPurchasedDateTime, TestData.FloatCreditAmount); + var result = await this.FloatDomainService.RecordCreditPurchase(command, CancellationToken.None); + result.IsFailed.ShouldBeTrue(); + } } } diff --git a/TransactionProcessor.BusinessLogic.Tests/Services/SettlementDomainServiceTests.cs b/TransactionProcessor.BusinessLogic.Tests/Services/SettlementDomainServiceTests.cs index f0289530..b08f03ae 100644 --- a/TransactionProcessor.BusinessLogic.Tests/Services/SettlementDomainServiceTests.cs +++ b/TransactionProcessor.BusinessLogic.Tests/Services/SettlementDomainServiceTests.cs @@ -100,6 +100,53 @@ public async Task SettlementDomainService_ProcessSettlement_SettlementIsProcesse result.Data.ShouldNotBe(Guid.Empty); } + [Fact] + public async Task SettlementDomainService_ProcessSettlement_MerchantWithImmediateSettlement_SettlementIsProcessed() + { + settlementAggregateRepository.Setup(s => s.GetLatestVersion(It.IsAny(), It.IsAny())) + .ReturnsAsync(Result.Success(TestData.GetSettlementAggregateWithPendingMerchantFees(10))); + this.transactionAggregateRepository.SetupSequence(s => s.GetLatestVersion(It.IsAny(), It.IsAny())) + .ReturnsAsync(TestData.GetCompletedAuthorisedSaleTransactionAggregateWithPendingFee(TestData.FeeIds.GetValueOrDefault(0))) + .ReturnsAsync(TestData.GetCompletedAuthorisedSaleTransactionAggregateWithPendingFee(TestData.FeeIds.GetValueOrDefault(1))) + .ReturnsAsync(TestData.GetCompletedAuthorisedSaleTransactionAggregateWithPendingFee(TestData.FeeIds.GetValueOrDefault(2))) + .ReturnsAsync(TestData.GetCompletedAuthorisedSaleTransactionAggregateWithPendingFee(TestData.FeeIds.GetValueOrDefault(3))) + .ReturnsAsync(TestData.GetCompletedAuthorisedSaleTransactionAggregateWithPendingFee(TestData.FeeIds.GetValueOrDefault(4))) + .ReturnsAsync(TestData.GetCompletedAuthorisedSaleTransactionAggregateWithPendingFee(TestData.FeeIds.GetValueOrDefault(5))) + .ReturnsAsync(TestData.GetCompletedAuthorisedSaleTransactionAggregateWithPendingFee(TestData.FeeIds.GetValueOrDefault(6))) + .ReturnsAsync(TestData.GetCompletedAuthorisedSaleTransactionAggregateWithPendingFee(TestData.FeeIds.GetValueOrDefault(7))) + .ReturnsAsync(TestData.GetCompletedAuthorisedSaleTransactionAggregateWithPendingFee(TestData.FeeIds.GetValueOrDefault(8))) + .ReturnsAsync(TestData.GetCompletedAuthorisedSaleTransactionAggregateWithPendingFee(TestData.FeeIds.GetValueOrDefault(9))); + this.settlementAggregateRepository + .Setup(s => s.SaveChanges(It.IsAny(), It.IsAny())) + .ReturnsAsync(Result.Success); + this.transactionAggregateRepository.SetupSequence(s => s.SaveChanges(It.IsAny(), It.IsAny())) + .ReturnsAsync(Result.Success()) + .ReturnsAsync(Result.Success()) + .ReturnsAsync(Result.Success()) + .ReturnsAsync(Result.Success()) + .ReturnsAsync(Result.Success()) + .ReturnsAsync(Result.Success()) + .ReturnsAsync(Result.Success()) + .ReturnsAsync(Result.Success()) + .ReturnsAsync(Result.Success()) + .ReturnsAsync(Result.Success()); + + + this.securityServiceClient.Setup(s => s.GetToken(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(Result.Success(TestData.TokenResponse())); + + this.estateClient.Setup(e => e.GetMerchant(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) + .ReturnsAsync(TestData.GetMerchantResponseWithOperator1ImmediateSettlement); + + SettlementCommands.ProcessSettlementCommand command = + new(TestData.SettlementDate, TestData.MerchantId, + TestData.EstateId); + + var result = await settlementDomainService.ProcessSettlement(command, CancellationToken.None); + + result.IsSuccess.ShouldBeTrue(); + result.Data.ShouldNotBe(Guid.Empty); + } + [Fact] public async Task SettlementDomainService_ProcessSettlement_SettlementAggregateNotCreated_NothingProcessed() { @@ -182,5 +229,160 @@ public async Task SettlementDomainService_ProcessSettlement_AddSettledFeeThrownE var result = await settlementDomainService.ProcessSettlement(command, CancellationToken.None); result.IsFailed.ShouldBeTrue(); } + + [Fact] + public async Task SettlementDomainService_ProcessSettlement_GetTransactionThrownException_SettlementProcessed() + { + settlementAggregateRepository.Setup(s => s.GetLatestVersion(It.IsAny(), It.IsAny())) + .ReturnsAsync(Result.Success(TestData.GetSettlementAggregateWithPendingMerchantFees(10))); + this.settlementAggregateRepository + .Setup(s => s.SaveChanges(It.IsAny(), It.IsAny())) + .ReturnsAsync(Result.Success); + this.securityServiceClient.Setup(s => s.GetToken(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(Result.Success(TestData.TokenResponse())); + + this.transactionAggregateRepository.Setup(s => s.GetLatestVersion(It.IsAny(), It.IsAny())) + .ThrowsAsync(new Exception()); + + this.estateClient.Setup(e => e.GetMerchant(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) + .ReturnsAsync(TestData.GetMerchantResponseWithOperator1); + + SettlementCommands.ProcessSettlementCommand command = new(TestData.SettlementDate, TestData.MerchantId, TestData.EstateId); + + var result = await settlementDomainService.ProcessSettlement(command, CancellationToken.None); + result.IsFailed.ShouldBeTrue(); + } + + [Fact] + public async Task SettlementDomainService_ProcessSettlement_GetMerchantThrownException_SettlementProcessed() + { + settlementAggregateRepository.Setup(s => s.GetLatestVersion(It.IsAny(), It.IsAny())) + .ReturnsAsync(Result.Success(TestData.GetSettlementAggregateWithPendingMerchantFees(10))); + this.settlementAggregateRepository + .Setup(s => s.SaveChanges(It.IsAny(), It.IsAny())) + .ReturnsAsync(Result.Success); + this.securityServiceClient.Setup(s => s.GetToken(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(Result.Success(TestData.TokenResponse())); + + this.estateClient.Setup(e => e.GetMerchant(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) + .ThrowsAsync(new Exception()); + + SettlementCommands.ProcessSettlementCommand command = new(TestData.SettlementDate, TestData.MerchantId, TestData.EstateId); + + var result = await settlementDomainService.ProcessSettlement(command, CancellationToken.None); + result.IsFailed.ShouldBeTrue(); + } + + [Fact] + public async Task SettlementDomainService_AddMerchantFeePendingSettlement_FeeAdded() { + settlementAggregateRepository.Setup(s => s.GetLatestVersion(It.IsAny(), It.IsAny())) + .ReturnsAsync(Result.Success(TestData.GetCreatedSettlementAggregate())); + this.settlementAggregateRepository + .Setup(s => s.SaveChanges(It.IsAny(), It.IsAny())) + .ReturnsAsync(Result.Success); + + SettlementCommands.AddMerchantFeePendingSettlementCommand command = new(TestData.TransactionId, TestData.CalculatedFeeValue, TestData.TransactionFeeCalculateDateTime, CalculationType.Fixed, TestData.TransactionFeeId, TestData.TransactionFeeValue, TestData.TransactionFeeSettlementDueDate, TestData.MerchantId, TestData.EstateId); + + var result = await settlementDomainService.AddMerchantFeePendingSettlement(command, CancellationToken.None); + result.IsSuccess.ShouldBeTrue(); + } + + [Fact] + public async Task SettlementDomainService_AddMerchantFeePendingSettlement_AggregateNotCreated_FeeAdded() + { + settlementAggregateRepository.Setup(s => s.GetLatestVersion(It.IsAny(), It.IsAny())) + .ReturnsAsync(Result.Success(TestData.GetEmptySettlementAggregate())); + this.settlementAggregateRepository + .Setup(s => s.SaveChanges(It.IsAny(), It.IsAny())) + .ReturnsAsync(Result.Success); + + SettlementCommands.AddMerchantFeePendingSettlementCommand command = new(TestData.TransactionId, TestData.CalculatedFeeValue, TestData.TransactionFeeCalculateDateTime, CalculationType.Fixed, TestData.TransactionFeeId, TestData.TransactionFeeValue, TestData.TransactionFeeSettlementDueDate, TestData.MerchantId, TestData.EstateId); + + var result = await settlementDomainService.AddMerchantFeePendingSettlement(command, CancellationToken.None); + result.IsSuccess.ShouldBeTrue(); + } + + [Fact] + public async Task SettlementDomainService_AddSettledFeeToSettlement_FeeAdded() + { + settlementAggregateRepository.Setup(s => s.GetLatestVersion(It.IsAny(), It.IsAny())) + .ReturnsAsync(Result.Success(TestData.GetCreatedSettlementAggregate())); + this.settlementAggregateRepository + .Setup(s => s.SaveChanges(It.IsAny(), It.IsAny())) + .ReturnsAsync(Result.Success); + this.estateClient.Setup(e => e.GetMerchant(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(Result.Success(TestData.Merchant)); + this.securityServiceClient.Setup(s => s.GetToken(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(Result.Success(TestData.TokenResponse())); + + SettlementCommands.AddSettledFeeToSettlementCommand command = new(TestData.SettlementDate, TestData.MerchantId, TestData.EstateId, TestData.TransactionFeeId, TestData.TransactionId); + + var result = await settlementDomainService.AddSettledFeeToSettlement(command, CancellationToken.None); + result.IsSuccess.ShouldBeTrue(); + } + + [Fact] + public async Task SettlementDomainService_AddSettledFeeToSettlement_ImmediateSettlement_FeeAdded() + { + settlementAggregateRepository.Setup(s => s.GetLatestVersion(It.IsAny(), It.IsAny())) + .ReturnsAsync(Result.Success(TestData.GetCreatedSettlementAggregate())); + this.settlementAggregateRepository + .Setup(s => s.SaveChanges(It.IsAny(), It.IsAny())) + .ReturnsAsync(Result.Success); + this.estateClient.Setup(e => e.GetMerchant(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(Result.Success(TestData.MerchantWithImmediateSettlement)); + this.securityServiceClient.Setup(s => s.GetToken(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(Result.Success(TestData.TokenResponse())); + + SettlementCommands.AddSettledFeeToSettlementCommand command = new(TestData.SettlementDate, TestData.MerchantId, TestData.EstateId, TestData.TransactionFeeId, TestData.TransactionId); + + var result = await settlementDomainService.AddSettledFeeToSettlement(command, CancellationToken.None); + result.IsSuccess.ShouldBeTrue(); + } + + [Fact] + public async Task SettlementDomainService_AddSettledFeeToSettlement_FailedGettingMerchant_FeeAdded() + { + settlementAggregateRepository.Setup(s => s.GetLatestVersion(It.IsAny(), It.IsAny())) + .ReturnsAsync(Result.Success(TestData.GetCreatedSettlementAggregate())); + this.settlementAggregateRepository + .Setup(s => s.SaveChanges(It.IsAny(), It.IsAny())) + .ReturnsAsync(Result.Success); + this.estateClient.Setup(e => e.GetMerchant(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(Result.Failure()); + this.securityServiceClient.Setup(s => s.GetToken(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(Result.Success(TestData.TokenResponse())); + + SettlementCommands.AddSettledFeeToSettlementCommand command = new(TestData.SettlementDate, TestData.MerchantId, TestData.EstateId, TestData.TransactionFeeId, TestData.TransactionId); + + var result = await settlementDomainService.AddSettledFeeToSettlement(command, CancellationToken.None); + result.IsFailed.ShouldBeTrue(); + } + + [Fact] + public async Task SettlementDomainService_AddSettledFeeToSettlement_SaveFailed_FeeAdded() + { + settlementAggregateRepository.Setup(s => s.GetLatestVersion(It.IsAny(), It.IsAny())) + .ReturnsAsync(Result.Success(TestData.GetCreatedSettlementAggregate())); + this.settlementAggregateRepository + .Setup(s => s.SaveChanges(It.IsAny(), It.IsAny())) + .ReturnsAsync(Result.Failure); + this.estateClient.Setup(e => e.GetMerchant(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(Result.Success(TestData.MerchantWithImmediateSettlement)); + this.securityServiceClient.Setup(s => s.GetToken(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(Result.Success(TestData.TokenResponse())); + + SettlementCommands.AddSettledFeeToSettlementCommand command = new(TestData.SettlementDate, TestData.MerchantId, TestData.EstateId, TestData.TransactionFeeId, TestData.TransactionId); + + var result = await settlementDomainService.AddSettledFeeToSettlement(command, CancellationToken.None); + result.IsFailed.ShouldBeTrue(); + } + + [Fact] + public async Task SettlementDomainService_AddSettledFeeToSettlement_ExceptionThrown_FeeAdded() + { + settlementAggregateRepository.Setup(s => s.GetLatestVersion(It.IsAny(), It.IsAny())) + .ReturnsAsync(Result.Success(TestData.GetCreatedSettlementAggregate())); + this.settlementAggregateRepository + .Setup(s => s.SaveChanges(It.IsAny(), It.IsAny())) + .ThrowsAsync(new Exception()); + this.estateClient.Setup(e => e.GetMerchant(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(Result.Success(TestData.MerchantWithImmediateSettlement)); + this.securityServiceClient.Setup(s => s.GetToken(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(Result.Success(TestData.TokenResponse())); + + SettlementCommands.AddSettledFeeToSettlementCommand command = new(TestData.SettlementDate, TestData.MerchantId, TestData.EstateId, TestData.TransactionFeeId, TestData.TransactionId); + + var result = await settlementDomainService.AddSettledFeeToSettlement(command, CancellationToken.None); + result.IsFailed.ShouldBeTrue(); + } } } diff --git a/TransactionProcessor.BusinessLogic.Tests/Services/TransactionDomainServiceTests.cs b/TransactionProcessor.BusinessLogic.Tests/Services/TransactionDomainServiceTests.cs index f727e01e..b97a4a94 100644 --- a/TransactionProcessor.BusinessLogic.Tests/Services/TransactionDomainServiceTests.cs +++ b/TransactionProcessor.BusinessLogic.Tests/Services/TransactionDomainServiceTests.cs @@ -1,4 +1,5 @@ -using Microsoft.Extensions.Caching.Memory; +using EstateManagement.DataTransferObjects.Responses.Contract; +using Microsoft.Extensions.Caching.Memory; using SimpleResults; using TransactionProcessor.BusinessLogic.Common; using TransactionProcessor.BusinessLogic.Manager; @@ -102,7 +103,7 @@ public async Task TransactionDomainService_ProcessLogonTransaction_DeviceNeedsAd this.SecurityServiceClient.Setup(s => s.GetToken(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(Result.Success(TestData.TokenResponse())); - this.TransactionValidationService.Setup(t => t.ValidateLogonTransactionX(It.IsAny(), + this.TransactionValidationService.Setup(t => t.ValidateLogonTransaction(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(Result.Success(new TransactionValidationResult(TransactionResponseCode.SuccessNeedToAddDevice, "SUCCESS"))); @@ -131,7 +132,7 @@ public async Task TransactionDomainService_ProcessLogonTransaction_TransactionIs this.TransactionAggregateRepository.Setup(t => t.SaveChanges(It.IsAny(), It.IsAny())) .ReturnsAsync(Result.Success()); - this.TransactionValidationService.Setup(t => t.ValidateLogonTransactionX(It.IsAny(), + this.TransactionValidationService.Setup(t => t.ValidateLogonTransaction(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(Result.Success(new TransactionValidationResult(TransactionResponseCode.Success, "SUCCESS"))); @@ -162,7 +163,7 @@ public async Task TransactionDomainService_ProcessLogonTransaction_ValidationFai .ReturnsAsync(Result.Success(TestData.GetEmptyTransactionAggregate())); this.TransactionAggregateRepository.Setup(t => t.SaveChanges(It.IsAny(), It.IsAny())) .ReturnsAsync(Result.Success()); - this.TransactionValidationService.Setup(t => t.ValidateLogonTransactionX(It.IsAny(), + this.TransactionValidationService.Setup(t => t.ValidateLogonTransaction(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(Result.Success(new TransactionValidationResult(responseCode, responseCode.ToString()))); @@ -190,7 +191,7 @@ public async Task TransactionDomainService_ProcessReconciliationTransaction_Reco .ReturnsAsync(new ReconciliationAggregate()); this.ReconciliationAggregateRepository.Setup(t => t.SaveChanges(It.IsAny(), It.IsAny())) .ReturnsAsync(Result.Success()); - this.TransactionValidationService.Setup(t => t.ValidateReconciliationTransactionX(It.IsAny(), + this.TransactionValidationService.Setup(t => t.ValidateReconciliationTransaction(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(Result.Success(new TransactionValidationResult(TransactionResponseCode.Success, "SUCCESS"))); @@ -219,7 +220,7 @@ public async Task TransactionDomainService_ProcessReconciliationTransaction_Vali .ReturnsAsync(new ReconciliationAggregate()); this.ReconciliationAggregateRepository.Setup(t => t.SaveChanges(It.IsAny(), It.IsAny())) .ReturnsAsync(Result.Success()); - this.TransactionValidationService.Setup(t => t.ValidateReconciliationTransactionX(It.IsAny(), + this.TransactionValidationService.Setup(t => t.ValidateReconciliationTransaction(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(Result.Success(new TransactionValidationResult(responseCode, responseCode.ToString()))); @@ -254,7 +255,7 @@ public async Task TransactionDomainService_ProcessSaleTransaction_DeclinedByOper this.FloatAggregateRepository.Setup(f => f.GetLatestVersion(It.IsAny(), It.IsAny())).ReturnsAsync(Result.Success(TestData.GetEmptyFloatAggregate())); - this.TransactionValidationService.Setup(t => t.ValidateSaleTransactionX(It.IsAny(), + this.TransactionValidationService.Setup(t => t.ValidateSaleTransaction(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), @@ -292,7 +293,49 @@ public async Task TransactionDomainService_ProcessSaleTransaction_DeclinedByOper response.ResponseCode.ShouldBe("1008"); response.TransactionId.ShouldBe(TestData.TransactionId); } - + + [Fact] + public async Task TransactionDomainService_ProcessSaleTransaction_OperatorProxyThrowssException_TransactionIsProcessed() + { + this.SecurityServiceClient.Setup(s => s.GetToken(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(Result.Success(TestData.TokenResponse())); + + this.EstateClient.Setup(e => e.GetMerchant(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) + .ReturnsAsync(TestData.GetMerchantResponseWithOperator1); + this.EstateClient.Setup(e => e.GetEstate(It.IsAny(), It.IsAny(), It.IsAny())) + .ReturnsAsync(TestData.GetEstateResponseWithOperator1); + + this.TransactionAggregateRepository.Setup(t => t.GetLatestVersion(It.IsAny(), It.IsAny())) + .ReturnsAsync(Result.Success(TestData.GetEmptyTransactionAggregate())); + this.TransactionAggregateRepository.Setup(t => t.SaveChanges(It.IsAny(), It.IsAny())) + .ReturnsAsync(Result.Success()); + + this.FloatAggregateRepository.Setup(f => f.GetLatestVersion(It.IsAny(), It.IsAny())).ReturnsAsync(Result.Success(TestData.GetEmptyFloatAggregate())); + + this.TransactionValidationService.Setup(t => t.ValidateSaleTransaction(It.IsAny(), + It.IsAny(), + It.IsAny(), + It.IsAny(), + It.IsAny(), + It.IsAny(), + It.IsAny(), + It.IsAny())).ReturnsAsync(Result.Success(new TransactionValidationResult(TransactionResponseCode.Success, "SUCCESS"))); + + this.OperatorProxy.Setup(o => o.ProcessSaleMessage(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny>(), It.IsAny())).Throws(new Exception()); + TransactionCommands.ProcessSaleTransactionCommand command = + new TransactionCommands.ProcessSaleTransactionCommand(TestData.TransactionId, TestData.EstateId, + TestData.MerchantId, TestData.DeviceIdentifier, TestData.TransactionTypeSale.ToString(), + TestData.TransactionDateTime, TestData.TransactionNumber, TestData.OperatorId, + TestData.CustomerEmailAddress, TestData.AdditionalTransactionMetaDataForMobileTopup(), + TestData.ContractId, TestData.ProductId, TestData.TransactionSource); + + ProcessSaleTransactionResponse response = await this.TransactionDomainService.ProcessSaleTransaction(command, CancellationToken.None); + + response.EstateId.ShouldBe(TestData.EstateId); + response.MerchantId.ShouldBe(TestData.MerchantId); + response.ResponseCode.ShouldBe("1008"); + response.TransactionId.ShouldBe(TestData.TransactionId); + } + [Fact] public async Task TransactionDomainService_ProcessSaleTransaction_TransactionIsProcessed(){ this.SecurityServiceClient.Setup(s => s.GetToken(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(Result.Success(TestData.TokenResponse())); @@ -312,7 +355,7 @@ public async Task TransactionDomainService_ProcessSaleTransaction_TransactionIsP this.FloatAggregateRepository.Setup(f => f.GetLatestVersion(It.IsAny(), It.IsAny())).ReturnsAsync(floatAggregate); - this.TransactionValidationService.Setup(t => t.ValidateSaleTransactionX(It.IsAny(), + this.TransactionValidationService.Setup(t => t.ValidateSaleTransaction(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), @@ -376,7 +419,7 @@ public async Task TransactionDomainService_ProcessSaleTransaction_NoFloatFound_T this.FloatAggregateRepository.Setup(f => f.GetLatestVersion(It.IsAny(), It.IsAny())).ReturnsAsync(Result.Success(TestData.GetEmptyFloatAggregate())); - this.TransactionValidationService.Setup(t => t.ValidateSaleTransactionX(It.IsAny(), + this.TransactionValidationService.Setup(t => t.ValidateSaleTransaction(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), @@ -433,7 +476,7 @@ public async Task TransactionDomainService_ProcessSaleTransaction_ValidationFail this.TransactionAggregateRepository.Setup(t => t.SaveChanges(It.IsAny(), It.IsAny())) .ReturnsAsync(Result.Success()); - this.TransactionValidationService.Setup(t => t.ValidateSaleTransactionX(It.IsAny(), + this.TransactionValidationService.Setup(t => t.ValidateSaleTransaction(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), @@ -470,6 +513,222 @@ public async Task TransactionDomainService_ResendTransactionReceipt_TransactionR result.IsSuccess.ShouldBeTrue(); } + [Fact] + public async Task TransactionDomainService_RequireFeeCalculation_IsNotAuthorised_ReturnsFalse(){ + + TransactionAggregate transactionAggregate = TransactionAggregate.Create(TestData.TransactionId); + transactionAggregate.StartTransaction(TestData.TransactionDateTime, TestData.TransactionNumber, + TransactionType.Sale, TestData.TransactionReference, + TestData.EstateId, TestData.MerchantId, TestData.DeviceIdentifier, + TestData.TransactionAmount); + transactionAggregate.DeclineTransaction(TestData.OperatorId, "111", "SUCCESS", "0000", "SUCCESS"); + + // TODO: maybe move this to an extension on aggregate + var result = TransactionDomainService.RequireFeeCalculation(transactionAggregate); + result.ShouldBeFalse(); + } + + [Fact] + public async Task TransactionDomainService_RequireFeeCalculation_IsNotCompelted_ReturnsFalse() + { + TransactionAggregate transactionAggregate = TransactionAggregate.Create(TestData.TransactionId); + transactionAggregate.StartTransaction(TestData.TransactionDateTime, TestData.TransactionNumber, + TransactionType.Sale, TestData.TransactionReference, + TestData.EstateId, TestData.MerchantId, TestData.DeviceIdentifier, + TestData.TransactionAmount); + transactionAggregate.AuthoriseTransaction(TestData.OperatorId, "111", "111", "SUCCESS", "1234", "0000", "SUCCESS"); + + var result = TransactionDomainService.RequireFeeCalculation(transactionAggregate); + result.ShouldBeFalse(); + } + + [Fact] + public async Task TransactionDomainService_RequireFeeCalculation_IsALogon_ReturnsFalse() + { + TransactionAggregate transactionAggregate = TransactionAggregate.Create(TestData.TransactionId); + transactionAggregate.StartTransaction(TestData.TransactionDateTime, TestData.TransactionNumber, + TransactionType.Logon, TestData.TransactionReference, + TestData.EstateId, TestData.MerchantId, TestData.DeviceIdentifier, + TestData.TransactionAmount); + transactionAggregate.AuthoriseTransactionLocally("111", "0001", "SUCCESS"); + transactionAggregate.CompleteTransaction(); + + + var result = TransactionDomainService.RequireFeeCalculation(transactionAggregate); + result.ShouldBeFalse(); + } + + [Fact] + public async Task TransactionDomainService_RequireFeeCalculation_NoContractId_ReturnsFalse() + { + TransactionAggregate transactionAggregate = TransactionAggregate.Create(TestData.TransactionId); + transactionAggregate.StartTransaction(TestData.TransactionDateTime, TestData.TransactionNumber, + TransactionType.Sale, TestData.TransactionReference, + TestData.EstateId, TestData.MerchantId, TestData.DeviceIdentifier, + TestData.TransactionAmount); + transactionAggregate.AuthoriseTransaction(TestData.OperatorId, "111", "111", "SUCCESS", "1234", "0000", "SUCCESS"); + transactionAggregate.CompleteTransaction(); + + + var result = TransactionDomainService.RequireFeeCalculation(transactionAggregate); + result.ShouldBeFalse(); + } + + [Fact] + public async Task TransactionDomainService_RequireFeeCalculation_NullAmount_ReturnsFalse() + { + TransactionAggregate transactionAggregate = TransactionAggregate.Create(TestData.TransactionId); + transactionAggregate.StartTransaction(TestData.TransactionDateTime, TestData.TransactionNumber, + TransactionType.Sale, TestData.TransactionReference, + TestData.EstateId, TestData.MerchantId, TestData.DeviceIdentifier, + null); + transactionAggregate.AddProductDetails(TestData.ContractId, TestData.ProductId); + transactionAggregate.AuthoriseTransaction(TestData.OperatorId, "111", "111", "SUCCESS", "1234", "0000", "SUCCESS"); + transactionAggregate.CompleteTransaction(); + + + var result = TransactionDomainService.RequireFeeCalculation(transactionAggregate); + result.ShouldBeFalse(); + } + + [Fact] + public async Task TransactionDomainService_RequireFeeCalculation_ReturnsTrue() + { + TransactionAggregate transactionAggregate = TransactionAggregate.Create(TestData.TransactionId); + transactionAggregate.StartTransaction(TestData.TransactionDateTime, TestData.TransactionNumber, + TransactionType.Sale, TestData.TransactionReference, + TestData.EstateId, TestData.MerchantId, TestData.DeviceIdentifier, + TestData.TransactionAmount); + transactionAggregate.AddProductDetails(TestData.ContractId, TestData.ProductId); + transactionAggregate.AuthoriseTransaction(TestData.OperatorId, "111", "111", "SUCCESS", "1234", "0000", "SUCCESS"); + transactionAggregate.CompleteTransaction(); + + + var result = TransactionDomainService.RequireFeeCalculation(transactionAggregate); + result.ShouldBeTrue(); + } + + [Theory] + [InlineData(SettlementSchedule.Immediate, "2024-05-01", "2024-05-01")] + [InlineData(SettlementSchedule.NotSet, "2024-05-01", "2024-05-01")] + [InlineData(SettlementSchedule.Weekly, "2024-05-01", "2024-05-08")] + [InlineData(SettlementSchedule.Monthly, "2024-05-01", "2024-06-01")] + public async Task TransactionDomainService_CalculateSettlementDate_CorrectDateReturned(SettlementSchedule settlementSchedule, String completedDateString, String expectedDateString){ + + DateTime completedDate = DateTime.ParseExact(completedDateString, "yyyy-MM-dd", null); + DateTime expectedDate = DateTime.ParseExact(expectedDateString, "yyyy-MM-dd", null); + DateTime result = TransactionDomainService.CalculateSettlementDate(settlementSchedule, completedDate); + result.Date.ShouldBe(expectedDate.Date); + } + + [Fact] + public async Task TransactionDomainService_CalculateFeesForTransaction_FeesCalculated() { + this.TransactionAggregateRepository.Setup(t => t.GetLatestVersion(It.IsAny(), It.IsAny())).ReturnsAsync(Result.Success(TestData.GetCompletedAuthorisedSaleTransactionAggregate())); + this.TransactionAggregateRepository.Setup(t => t.SaveChanges(It.IsAny(), It.IsAny())).ReturnsAsync(Result.Success()); + this.EstateClient.Setup(e => e.GetTransactionFeesForProduct(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(TestData.ContractProductTransactionFees); + this.EstateClient.Setup(e => e.GetMerchant(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(Result.Success(TestData.Merchant)); + this.SecurityServiceClient.Setup(s => s.GetToken(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(Result.Success(TestData.TokenResponse())); + + this.FeeCalculationManager.Setup(f => f.CalculateFees(It.IsAny>(), It.IsAny(), It.IsAny())).Returns(TestData.CalculatedMerchantFees); + + TransactionCommands.CalculateFeesForTransactionCommand command = new(TestData.TransactionId, TestData.TransactionDateTime, TestData.EstateId, TestData.MerchantId); + + var result = await this.TransactionDomainService.CalculateFeesForTransaction(command, CancellationToken.None); + result.IsSuccess.ShouldBeTrue(); + } + + [Fact] + public async Task TransactionDomainService_CalculateFeesForTransaction_MerchantWithImmediateSettlement_FeesCalculated() + { + this.TransactionAggregateRepository.Setup(t => t.GetLatestVersion(It.IsAny(), It.IsAny())).ReturnsAsync(Result.Success(TestData.GetCompletedAuthorisedSaleTransactionAggregate())); + this.TransactionAggregateRepository.Setup(t => t.SaveChanges(It.IsAny(), It.IsAny())).ReturnsAsync(Result.Success()); + this.EstateClient.Setup(e => e.GetTransactionFeesForProduct(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(TestData.ContractProductTransactionFees); + this.EstateClient.Setup(e => e.GetMerchant(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(Result.Success(TestData.MerchantWithImmediateSettlement)); + this.SecurityServiceClient.Setup(s => s.GetToken(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(Result.Success(TestData.TokenResponse())); + + this.FeeCalculationManager.Setup(f => f.CalculateFees(It.IsAny>(), It.IsAny(), It.IsAny())).Returns(TestData.CalculatedMerchantFees); + + TransactionCommands.CalculateFeesForTransactionCommand command = new(TestData.TransactionId, TestData.TransactionDateTime, TestData.EstateId, TestData.MerchantId); + + var result = await this.TransactionDomainService.CalculateFeesForTransaction(command, CancellationToken.None); + result.IsSuccess.ShouldBeTrue(); + } + + [Fact] + public async Task TransactionDomainService_CalculateFeesForTransaction_NonMerchantFees_FeesCalculated() + { + this.TransactionAggregateRepository.Setup(t => t.GetLatestVersion(It.IsAny(), It.IsAny())).ReturnsAsync(Result.Success(TestData.GetCompletedAuthorisedSaleTransactionAggregate())); + this.TransactionAggregateRepository.Setup(t => t.SaveChanges(It.IsAny(), It.IsAny())).ReturnsAsync(Result.Success()); + this.EstateClient.Setup(e => e.GetTransactionFeesForProduct(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(TestData.ContractProductTransactionFees); + this.EstateClient.Setup(e => e.GetMerchant(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(Result.Success(TestData.MerchantWithImmediateSettlement)); + this.SecurityServiceClient.Setup(s => s.GetToken(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(Result.Success(TestData.TokenResponse())); + + this.FeeCalculationManager.Setup(f => f.CalculateFees(It.IsAny>(), It.IsAny(), It.IsAny())).Returns(TestData.CalculatedServiceProviderFees); + + TransactionCommands.CalculateFeesForTransactionCommand command = new(TestData.TransactionId, TestData.TransactionDateTime, TestData.EstateId, TestData.MerchantId); + + var result = await this.TransactionDomainService.CalculateFeesForTransaction(command, CancellationToken.None); + result.IsSuccess.ShouldBeTrue(); + } + + [Fact] + public async Task TransactionDomainService_CalculateFeesForTransaction_TransactionNotNeedingFeeCaclulation_FeesCalculated() + { + this.TransactionAggregateRepository.Setup(t => t.GetLatestVersion(It.IsAny(), It.IsAny())).ReturnsAsync(Result.Success(TestData.GetCompletedLogonTransactionAggregate())); + this.TransactionAggregateRepository.Setup(t => t.SaveChanges(It.IsAny(), It.IsAny())).ReturnsAsync(Result.Success()); + this.EstateClient.Setup(e => e.GetTransactionFeesForProduct(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(TestData.ContractProductTransactionFees); + this.EstateClient.Setup(e => e.GetMerchant(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(Result.Success(TestData.MerchantWithImmediateSettlement)); + this.SecurityServiceClient.Setup(s => s.GetToken(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(Result.Success(TestData.TokenResponse())); + + this.FeeCalculationManager.Setup(f => f.CalculateFees(It.IsAny>(), It.IsAny(), It.IsAny())).Returns(TestData.CalculatedServiceProviderFees); + + TransactionCommands.CalculateFeesForTransactionCommand command = new(TestData.TransactionId, TestData.TransactionDateTime, TestData.EstateId, TestData.MerchantId); + + var result = await this.TransactionDomainService.CalculateFeesForTransaction(command, CancellationToken.None); + result.IsSuccess.ShouldBeTrue(); + } + + [Fact] + public async Task TransactionDomainService_CalculateFeesForTransaction_NoFeesReturned_FeesCalculated() + { + this.TransactionAggregateRepository.Setup(t => t.GetLatestVersion(It.IsAny(), It.IsAny())).ReturnsAsync(Result.Success(TestData.GetCompletedAuthorisedSaleTransactionAggregate())); + this.TransactionAggregateRepository.Setup(t => t.SaveChanges(It.IsAny(), It.IsAny())).ReturnsAsync(Result.Success()); + + this.EstateClient.Setup(e => e.GetTransactionFeesForProduct(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(Result.Failure()); + this.EstateClient.Setup(e => e.GetMerchant(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(Result.Success(TestData.MerchantWithImmediateSettlement)); + this.SecurityServiceClient.Setup(s => s.GetToken(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(Result.Success(TestData.TokenResponse())); + + this.FeeCalculationManager.Setup(f => f.CalculateFees(It.IsAny>(), It.IsAny(), It.IsAny())).Returns(TestData.CalculatedServiceProviderFees); + + TransactionCommands.CalculateFeesForTransactionCommand command = new(TestData.TransactionId, TestData.TransactionDateTime, TestData.EstateId, TestData.MerchantId); + + var result = await this.TransactionDomainService.CalculateFeesForTransaction(command, CancellationToken.None); + result.IsFailed.ShouldBeTrue(); + } + + [Fact] + public async Task TransactionDomainService_AddSettledMerchantFee_FeeAdded() { + this.TransactionAggregateRepository.Setup(t => t.GetLatestVersion(It.IsAny(), It.IsAny())).ReturnsAsync(Result.Success(TestData.GetCompletedAuthorisedSaleTransactionAggregateWithPendingFee(TestData.TransactionFeeId))); + this.TransactionAggregateRepository.Setup(t => t.SaveChanges(It.IsAny(), It.IsAny())).ReturnsAsync(Result.Success()); + + TransactionCommands.AddSettledMerchantFeeCommand command = new(TestData.TransactionId, TestData.CalculatedFeeValue, TestData.TransactionFeeCalculateDateTime, CalculationType.Fixed, TestData.TransactionFeeId, TestData.CalculatedFeeValue, TestData.SettlementDate, TestData.SettlementAggregateId); + + var result = await this.TransactionDomainService.AddSettledMerchantFee(command, CancellationToken.None); + result.IsSuccess.ShouldBeTrue(); + } + + [Fact] + public async Task TransactionDomainService_AddSettledMerchantFee_SaveFailed_ResultFailed() + { + this.TransactionAggregateRepository.Setup(t => t.GetLatestVersion(It.IsAny(), It.IsAny())).ReturnsAsync(Result.Success(TestData.GetCompletedAuthorisedSaleTransactionAggregate())); + this.TransactionAggregateRepository.Setup(t => t.SaveChanges(It.IsAny(), It.IsAny())).ReturnsAsync(Result.Failure()); + + TransactionCommands.AddSettledMerchantFeeCommand command = new(TestData.TransactionId, TestData.CalculatedFeeValue, TestData.TransactionFeeCalculateDateTime, CalculationType.Fixed, TestData.TransactionFeeId, TestData.CalculatedFeeValue, TestData.SettlementDate, TestData.SettlementAggregateId); + + var result = await this.TransactionDomainService.AddSettledMerchantFee(command, CancellationToken.None); + result.IsFailed.ShouldBeTrue(); + } + #endregion } } \ No newline at end of file diff --git a/TransactionProcessor.BusinessLogic.Tests/Services/TransactionValidationServiceTests.cs b/TransactionProcessor.BusinessLogic.Tests/Services/TransactionValidationServiceTests.cs index e7d0e29b..84aa9d11 100644 --- a/TransactionProcessor.BusinessLogic.Tests/Services/TransactionValidationServiceTests.cs +++ b/TransactionProcessor.BusinessLogic.Tests/Services/TransactionValidationServiceTests.cs @@ -23,7 +23,7 @@ namespace TransactionProcessor.BusinessLogic.Tests.Services; using Testing; using Xunit; - +/* public class TransactionValidationServiceTests{ private readonly TransactionValidationService TransactionValidationService; private readonly Mock SecurityServiceClient; @@ -58,10 +58,10 @@ public async Task TransactionValidationService_ValidateLogonTransaction_DeviceNo this.EstateClient.Setup(e => e.GetMerchant(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) .ReturnsAsync(TestData.GetMerchantResponseWithOperator1); - (String responseMessage, TransactionResponseCode responseCode) response = + Result result= await this.TransactionValidationService.ValidateLogonTransaction(TestData.EstateId, TestData.MerchantId, TestData.DeviceIdentifier1, CancellationToken.None); - - response.responseCode.ShouldBe(TransactionResponseCode.InvalidDeviceIdentifier); + result.IsFailed.ShouldBeTrue(); + result.Data.ResponseCode.ShouldBe(TransactionResponseCode.InvalidDeviceIdentifier); } [Fact] @@ -71,10 +71,10 @@ public async Task TransactionValidationService_ValidateLogonTransaction_EstateNo this.EstateClient.Setup(e => e.GetEstate(It.IsAny(), It.IsAny(), It.IsAny())) .ReturnsAsync(Result.NotFound()); - (String responseMessage, TransactionResponseCode responseCode) response = + Result result = await this.TransactionValidationService.ValidateLogonTransaction(TestData.EstateId, TestData.MerchantId, TestData.DeviceIdentifier, CancellationToken.None); - - response.responseCode.ShouldBe(TransactionResponseCode.InvalidEstateId); + result.IsFailed.ShouldBeTrue(); + result.Data.ResponseCode.ShouldBe(TransactionResponseCode.InvalidEstateId); } [Fact] @@ -86,10 +86,11 @@ public async Task TransactionValidationService_ValidateLogonTransaction_Merchant this.EstateClient.Setup(e => e.GetMerchant(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) .ReturnsAsync(TestData.GetMerchantResponseWithNoDevices); - (String responseMessage, TransactionResponseCode responseCode) response = + var result = await this.TransactionValidationService.ValidateLogonTransaction(TestData.EstateId, TestData.MerchantId, TestData.DeviceIdentifier, CancellationToken.None); - response.responseCode.ShouldBe(TransactionResponseCode.SuccessNeedToAddDevice); + result.IsSuccess.ShouldBeTrue(); + result.Data.ResponseCode.ShouldBe(TransactionResponseCode.SuccessNeedToAddDevice); } [Fact] @@ -102,10 +103,11 @@ public async Task TransactionValidationService_ValidateLogonTransaction_Merchant .ReturnsAsync(TestData.GetMerchantResponseWithNullDevices); // TODO: Verify device was added... - (String responseMessage, TransactionResponseCode responseCode) response = + var result = await this.TransactionValidationService.ValidateLogonTransaction(TestData.EstateId, TestData.MerchantId, TestData.DeviceIdentifier, CancellationToken.None); - response.responseCode.ShouldBe(TransactionResponseCode.SuccessNeedToAddDevice); + result.IsSuccess.ShouldBeTrue(); + result.Data.ResponseCode.ShouldBe(TransactionResponseCode.SuccessNeedToAddDevice); } [Fact] @@ -118,10 +120,11 @@ public async Task TransactionValidationService_ValidateLogonTransaction_Merchant .Setup(e => e.GetMerchant(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(Result.NotFound()); - (String responseMessage, TransactionResponseCode responseCode) response = + var result = await this.TransactionValidationService.ValidateLogonTransaction(TestData.EstateId, TestData.MerchantId, TestData.DeviceIdentifier, CancellationToken.None); - response.responseCode.ShouldBe(TransactionResponseCode.InvalidMerchantId); + result.IsFailed.ShouldBeTrue(); + result.Data.ResponseCode.ShouldBe(TransactionResponseCode.InvalidMerchantId); } [Fact] @@ -133,10 +136,11 @@ public async Task TransactionValidationService_ValidateLogonTransaction_Successf this.EstateClient.Setup(e => e.GetMerchant(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) .ReturnsAsync(TestData.GetMerchantResponseWithOperator1); - (String responseMessage, TransactionResponseCode responseCode) response = + var result = await this.TransactionValidationService.ValidateLogonTransaction(TestData.EstateId, TestData.MerchantId, TestData.DeviceIdentifier, CancellationToken.None); - response.responseCode.ShouldBe(TransactionResponseCode.Success); + result.IsSuccess.ShouldBeTrue(); + result.Data.ResponseCode.ShouldBe(TransactionResponseCode.Success); } [Fact] @@ -148,13 +152,13 @@ public async Task TransactionValidationService_ValidateReconciliationTransaction this.EstateClient.Setup(e => e.GetMerchant(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) .ReturnsAsync(TestData.GetMerchantResponseWithOperator1); - (String responseMessage, TransactionResponseCode responseCode) response = + var result = await this.TransactionValidationService.ValidateReconciliationTransaction(TestData.EstateId, TestData.MerchantId, TestData.DeviceIdentifier1, CancellationToken.None); - - response.responseCode.ShouldBe(TransactionResponseCode.InvalidDeviceIdentifier); + result.IsFailed.ShouldBeTrue(); + result.Data.ResponseCode.ShouldBe(TransactionResponseCode.InvalidDeviceIdentifier); } [Fact] @@ -164,13 +168,14 @@ public async Task TransactionValidationService_ValidateReconciliationTransaction this.EstateClient.Setup(e => e.GetEstate(It.IsAny(), It.IsAny(), It.IsAny())) .ReturnsAsync(Result.NotFound()); - (String responseMessage, TransactionResponseCode responseCode) response = + var result = await this.TransactionValidationService.ValidateReconciliationTransaction(TestData.EstateId, TestData.MerchantId, TestData.DeviceIdentifier, CancellationToken.None); - response.responseCode.ShouldBe(TransactionResponseCode.InvalidEstateId); + result.IsFailed.ShouldBeTrue(); + result.Data.ResponseCode.ShouldBe(TransactionResponseCode.InvalidEstateId); } [Fact] @@ -182,13 +187,14 @@ public async Task TransactionValidationService_ValidateReconciliationTransaction this.EstateClient.Setup(e => e.GetMerchant(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) .ReturnsAsync(TestData.GetMerchantResponseWithNoDevices); - (String responseMessage, TransactionResponseCode responseCode) response = + var result = await this.TransactionValidationService.ValidateReconciliationTransaction(TestData.EstateId, TestData.MerchantId, TestData.DeviceIdentifier, CancellationToken.None); - response.responseCode.ShouldBe(TransactionResponseCode.NoValidDevices); + result.IsFailed.ShouldBeTrue(); + result.Data.ResponseCode.ShouldBe(TransactionResponseCode.NoValidDevices); } [Fact] @@ -200,7 +206,7 @@ public async Task TransactionValidationService_ValidateReconciliationTransaction this.EstateClient.Setup(e => e.GetMerchant(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) .ReturnsAsync(TestData.GetMerchantResponseWithNullDevices); - (String responseMessage, TransactionResponseCode responseCode) response = + var response = await this.TransactionValidationService.ValidateReconciliationTransaction(TestData.EstateId, TestData.MerchantId, TestData.DeviceIdentifier, @@ -246,237 +252,276 @@ await this.TransactionValidationService.ValidateReconciliationTransaction(TestDa response.responseCode.ShouldBe(TransactionResponseCode.Success); } - [Fact] - public async Task TransactionValidationService_ValidateSaleTransaction_DeviceNotRegisteredToMerchant_ResponseIsInvalidDeviceIdentifier() { + +}*/ + +public class TransactionValidationServiceTests_New { + private readonly TransactionValidationService TransactionValidationService; + private readonly Mock SecurityServiceClient; + + private readonly Mock> StateRepository; + private readonly Mock EstateClient; + private readonly Mock EventStoreContext; + public TransactionValidationServiceTests_New() { + IConfigurationRoot configurationRoot = new ConfigurationBuilder().AddInMemoryCollection(TestData.DefaultAppSettings).Build(); + ConfigurationReader.Initialise(configurationRoot); + + Logger.Initialise(NullLogger.Instance); + + this.EstateClient = new Mock(); + this.SecurityServiceClient = new Mock(); + this.StateRepository = new Mock>(); + this.EventStoreContext = new Mock(); + this.SecurityServiceClient.Setup(s => s.GetToken(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(Result.Success(TestData.TokenResponse())); + this.TransactionValidationService = new TransactionValidationService(this.EstateClient.Object, + this.SecurityServiceClient.Object, + this.StateRepository.Object, + this.EventStoreContext.Object); + } + + [Fact] + public async Task ValidateLogonTransactionX_ValidationSuccessful_CorrectResponseReturned() { this.EstateClient.Setup(e => e.GetEstate(It.IsAny(), It.IsAny(), It.IsAny())) - .ReturnsAsync(TestData.GetEstateResponseWithOperator1); + .ReturnsAsync(Result.Success(TestData.GetEstateResponseWithOperator1)); this.EstateClient.Setup(e => e.GetMerchant(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) - .ReturnsAsync(TestData.GetMerchantResponseWithOperator1); + .ReturnsAsync(Result.Success(TestData.GetMerchantResponseWithOperator1)); - (String responseMessage, TransactionResponseCode responseCode) response = await this.TransactionValidationService.ValidateSaleTransaction(TestData.EstateId, - TestData.MerchantId, - TestData.ContractId, - TestData.ProductId, - TestData.DeviceIdentifier1, - TestData.OperatorId, - TestData.TransactionAmount, - CancellationToken.None); + Result result = await this.TransactionValidationService.ValidateLogonTransaction(TestData.EstateId, TestData.MerchantId, + TestData.DeviceIdentifier, CancellationToken.None); - response.responseCode.ShouldBe(TransactionResponseCode.InvalidDeviceIdentifier); + result.IsSuccess.ShouldBeTrue(); + result.Data.ResponseCode.ShouldBe(TransactionResponseCode.Success); } - - [Fact] - public async Task TransactionValidationService_ValidateSaleTransaction_EstateFoundButHasNoOperators_ResponseIsInvalidEstateId() { - this.SecurityServiceClient.Setup(s => s.GetToken(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(Result.Success(TestData.TokenResponse())); + [Fact] + public async Task ValidateLogonTransactionX_InvalidEstate_CorrectResponseReturned() { this.EstateClient.Setup(e => e.GetEstate(It.IsAny(), It.IsAny(), It.IsAny())) - .ReturnsAsync(TestData.GetEstateResponseWithEmptyOperators); - this.EstateClient.Setup(e => e.GetMerchant(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) - .ReturnsAsync(TestData.GetEmptyMerchantResponse); + .ReturnsAsync(Result.NotFound("Estate not found")); - (String responseMessage, TransactionResponseCode responseCode) response = await this.TransactionValidationService.ValidateSaleTransaction(TestData.EstateId, - TestData.MerchantId, - TestData.ContractId, - TestData.ProductId, - TestData.DeviceIdentifier, - TestData.OperatorId, - TestData.TransactionAmount, - CancellationToken.None); + Result result = await this.TransactionValidationService.ValidateLogonTransaction(TestData.EstateId, TestData.MerchantId, + TestData.DeviceIdentifier, CancellationToken.None); - response.responseCode.ShouldBe(TransactionResponseCode.NoEstateOperators); + result.IsFailed.ShouldBeTrue(); + result.Data.ResponseCode.ShouldBe(TransactionResponseCode.InvalidEstateId); } [Fact] - public async Task TransactionValidationService_ValidateSaleTransaction_EstateFoundButOperatorIsDeleted_ResponseIsOperatorNotEnabledForEstate() + public async Task ValidateLogonTransactionX_FailureWhileGettingEstate_CorrectResponseReturned() { - this.SecurityServiceClient.Setup(s => s.GetToken(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(Result.Success(TestData.TokenResponse())); - this.EstateClient.Setup(e => e.GetEstate(It.IsAny(), It.IsAny(), It.IsAny())) - .ReturnsAsync(TestData.GetEstateResponseWithOperator1Deleted); - this.EstateClient.Setup(e => e.GetMerchant(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) - .ReturnsAsync(TestData.GetEmptyMerchantResponse); + .ReturnsAsync(Result.Failure("Failure Message")); - (String responseMessage, TransactionResponseCode responseCode) response = await this.TransactionValidationService.ValidateSaleTransaction(TestData.EstateId, - TestData.MerchantId, - TestData.ContractId, - TestData.ProductId, - TestData.DeviceIdentifier, - TestData.OperatorId, - TestData.TransactionAmount, - CancellationToken.None); + Result result = await this.TransactionValidationService.ValidateLogonTransaction(TestData.EstateId, TestData.MerchantId, + TestData.DeviceIdentifier, CancellationToken.None); - response.responseCode.ShouldBe(TransactionResponseCode.OperatorNotEnabledForEstate); + result.IsFailed.ShouldBeTrue(); + result.Data.ResponseCode.ShouldBe(TransactionResponseCode.UnknownFailure); } [Fact] - public async Task TransactionValidationService_ValidateSaleTransaction_EstateFoundButHasNullOperators_ResponseIsInvalidEstateId() { - this.SecurityServiceClient.Setup(s => s.GetToken(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(Result.Success(TestData.TokenResponse())); - + public async Task ValidateLogonTransactionX_InvalidMerchant_CorrectResponseReturned() + { this.EstateClient.Setup(e => e.GetEstate(It.IsAny(), It.IsAny(), It.IsAny())) - .ReturnsAsync(TestData.GetEstateResponseWithNullOperators); + .ReturnsAsync(Result.Success(TestData.GetEstateResponseWithOperator1)); this.EstateClient.Setup(e => e.GetMerchant(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) - .ReturnsAsync(TestData.GetEmptyMerchantResponse); + .ReturnsAsync(Result.NotFound("Merchant Not Found")); - (String responseMessage, TransactionResponseCode responseCode) response = await this.TransactionValidationService.ValidateSaleTransaction(TestData.EstateId, - TestData.MerchantId, - TestData.ContractId, - TestData.ProductId, - TestData.DeviceIdentifier, - TestData.OperatorId, - TestData.TransactionAmount, - CancellationToken.None); + Result result = await this.TransactionValidationService.ValidateLogonTransaction(TestData.EstateId, TestData.MerchantId, + TestData.DeviceIdentifier, CancellationToken.None); - response.responseCode.ShouldBe(TransactionResponseCode.NoEstateOperators); + result.IsFailed.ShouldBeTrue(); + result.Data.ResponseCode.ShouldBe(TransactionResponseCode.InvalidMerchantId); } [Fact] - public async Task TransactionValidationService_ValidateSaleTransaction_EstateFoundOperatorsNotConfiguredForEstate_ResponseIsOperatorNotValidForEstate() { - this.SecurityServiceClient.Setup(s => s.GetToken(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(Result.Success(TestData.TokenResponse())); - + public async Task ValidateLogonTransactionX_FailureWhileGettingMerchant_CorrectResponseReturned() + { this.EstateClient.Setup(e => e.GetEstate(It.IsAny(), It.IsAny(), It.IsAny())) - .ReturnsAsync(TestData.GetEstateResponseWithOperator1); + .ReturnsAsync(Result.Success()); this.EstateClient.Setup(e => e.GetMerchant(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) - .ReturnsAsync(TestData.GetEmptyMerchantResponse); + .ReturnsAsync(Result.Failure("Merchant Not Found")); - (String responseMessage, TransactionResponseCode responseCode) response = await this.TransactionValidationService.ValidateSaleTransaction(TestData.EstateId, - TestData.MerchantId, - TestData.ContractId, - TestData.ProductId, - TestData.DeviceIdentifier, - TestData.OperatorId2, - TestData.TransactionAmount, - CancellationToken.None); + Result result = await this.TransactionValidationService.ValidateLogonTransaction(TestData.EstateId, TestData.MerchantId, + TestData.DeviceIdentifier, CancellationToken.None); - response.responseCode.ShouldBe(TransactionResponseCode.OperatorNotValidForEstate); + result.IsFailed.ShouldBeTrue(); + result.Data.ResponseCode.ShouldBe(TransactionResponseCode.UnknownFailure); } [Fact] - public async Task TransactionValidationService_ValidateSaleTransaction_EstateNotFound_ResponseIsInvalidEstateId() { - this.SecurityServiceClient.Setup(s => s.GetToken(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(Result.Success(TestData.TokenResponse())); - + public async Task ValidateLogonTransactionX_InvalidDeviceId_CorrectResponseReturned() + { this.EstateClient.Setup(e => e.GetEstate(It.IsAny(), It.IsAny(), It.IsAny())) - .ReturnsAsync(Result.NotFound()); + .ReturnsAsync(Result.Success(TestData.GetEstateResponseWithOperator1)); + this.EstateClient.Setup(e => e.GetMerchant(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) + .ReturnsAsync(Result.Success(TestData.GetMerchantResponseWithOperator1)); - (String responseMessage, TransactionResponseCode responseCode) response = await this.TransactionValidationService.ValidateSaleTransaction(TestData.EstateId, - TestData.MerchantId, - TestData.ContractId, - TestData.ProductId, - TestData.DeviceIdentifier, - TestData.OperatorId, - TestData.TransactionAmount, - CancellationToken.None); + Result result = await this.TransactionValidationService.ValidateLogonTransaction(TestData.EstateId, TestData.MerchantId, + TestData.DeviceIdentifier1, CancellationToken.None); - response.responseCode.ShouldBe(TransactionResponseCode.InvalidEstateId); + result.IsFailed.ShouldBeTrue(); + result.Data.ResponseCode.ShouldBe(TransactionResponseCode.InvalidDeviceIdentifier); } [Fact] - public async Task TransactionValidationService_ValidateSaleTransaction_InvalidContractId_ResponseIsInvalidContractIdValue() { - this.SecurityServiceClient.Setup(s => s.GetToken(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(Result.Success(TestData.TokenResponse())); - + public async Task ValidateLogonTransactionX_MerchantHasNoDevices_CorrectResponseReturned() + { this.EstateClient.Setup(e => e.GetEstate(It.IsAny(), It.IsAny(), It.IsAny())) - .ReturnsAsync(TestData.GetEstateResponseWithOperator1); + .ReturnsAsync(Result.Success(TestData.GetEstateResponseWithOperator1)); this.EstateClient.Setup(e => e.GetMerchant(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) - .ReturnsAsync(TestData.GetMerchantResponseWithOperator1); - - this.EventStoreContext.Setup(e => e.GetPartitionStateFromProjection(It.IsAny(), It.IsAny(), It.IsAny())) - .ReturnsAsync(JsonConvert.SerializeObject(TestData.MerchantBalanceProjectionState)); + .ReturnsAsync(Result.Success(TestData.GetMerchantResponseWithNoDevices)); - (String responseMessage, TransactionResponseCode responseCode) response = await this.TransactionValidationService.ValidateSaleTransaction(TestData.EstateId, - TestData.MerchantId, - Guid.Empty, - TestData.ProductId, - TestData.DeviceIdentifier, - TestData.OperatorId, - TestData.TransactionAmount, - CancellationToken.None); + Result result = await this.TransactionValidationService.ValidateLogonTransaction(TestData.EstateId, TestData.MerchantId, + TestData.DeviceIdentifier1, CancellationToken.None); - response.responseCode.ShouldBe(TransactionResponseCode.InvalidContractIdValue); + result.IsSuccess.ShouldBeTrue(); + result.Data.ResponseCode.ShouldBe(TransactionResponseCode.SuccessNeedToAddDevice); } [Fact] - public async Task TransactionValidationService_ValidateSaleTransaction_InvalidProductId_ResponseIsInvalidProductIdValue() { - this.SecurityServiceClient.Setup(s => s.GetToken(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(Result.Success(TestData.TokenResponse())); - + public async Task ValidateLogonTransactionX_MerchantHasNullDevices_CorrectResponseReturned() + { this.EstateClient.Setup(e => e.GetEstate(It.IsAny(), It.IsAny(), It.IsAny())) - .ReturnsAsync(TestData.GetEstateResponseWithOperator1); + .ReturnsAsync(Result.Success(TestData.GetEstateResponseWithOperator1)); this.EstateClient.Setup(e => e.GetMerchant(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) - .ReturnsAsync(TestData.GetMerchantResponseWithOperator1); - this.EstateClient.Setup(e => e.GetMerchantContracts(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) - .ReturnsAsync(TestData.MerchantContractResponses); - - this.EventStoreContext.Setup(e => e.GetPartitionStateFromProjection(It.IsAny(), It.IsAny(), It.IsAny())) - .ReturnsAsync(JsonConvert.SerializeObject(TestData.MerchantBalanceProjectionState)); + .ReturnsAsync(Result.Success(TestData.GetMerchantResponseWithNullDevices)); - (String responseMessage, TransactionResponseCode responseCode) response = await this.TransactionValidationService.ValidateSaleTransaction(TestData.EstateId, - TestData.MerchantId, - TestData.ContractId, - Guid.Empty, - TestData.DeviceIdentifier, - TestData.OperatorId, - TestData.TransactionAmount, - CancellationToken.None); + Result result = await this.TransactionValidationService.ValidateLogonTransaction(TestData.EstateId, TestData.MerchantId, + TestData.DeviceIdentifier1, CancellationToken.None); - response.responseCode.ShouldBe(TransactionResponseCode.InvalidProductIdValue); + result.IsSuccess.ShouldBeTrue(); + result.Data.ResponseCode.ShouldBe(TransactionResponseCode.SuccessNeedToAddDevice); } - [Theory] - [InlineData(0)] - [InlineData(-1)] - public async Task TransactionValidationService_ValidateSaleTransaction_InvalidTransactionAmount_ResponseIsInvalidSaleTransactionAmount(Decimal transactionAmount) { - this.SecurityServiceClient.Setup(s => s.GetToken(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(Result.Success(TestData.TokenResponse())); - + [Fact] + public async Task ValidateReconciliationTransactionX_ValidationSuccessful_CorrectResponseReturned() + { this.EstateClient.Setup(e => e.GetEstate(It.IsAny(), It.IsAny(), It.IsAny())) - .ReturnsAsync(TestData.GetEstateResponseWithOperator1); + .ReturnsAsync(Result.Success(TestData.GetEstateResponseWithOperator1)); this.EstateClient.Setup(e => e.GetMerchant(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) - .ReturnsAsync(TestData.GetMerchantResponseWithOperator1); - this.EstateClient.Setup(e => e.GetMerchantContracts(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) - .ReturnsAsync(TestData.MerchantContractResponses); + .ReturnsAsync(Result.Success(TestData.GetMerchantResponseWithOperator1)); - (String responseMessage, TransactionResponseCode responseCode) response = await this.TransactionValidationService.ValidateSaleTransaction(TestData.EstateId, - TestData.MerchantId, - TestData.ContractId, - TestData.ProductId, - TestData.DeviceIdentifier, - TestData.OperatorId, - transactionAmount, - CancellationToken.None); + Result result = await this.TransactionValidationService.ValidateReconciliationTransaction(TestData.EstateId, TestData.MerchantId, + TestData.DeviceIdentifier, CancellationToken.None); - response.responseCode.ShouldBe(TransactionResponseCode.InvalidSaleTransactionAmount); + result.IsSuccess.ShouldBeTrue(); + result.Data.ResponseCode.ShouldBe(TransactionResponseCode.Success); } [Fact] - public async Task TransactionValidationService_ValidateSaleTransaction_MerchantDeviceListEmpty_ResponseIsNoValidDevices() { - this.SecurityServiceClient.Setup(s => s.GetToken(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(Result.Success(TestData.TokenResponse())); - + public async Task ValidateReconciliationTransactionX_InvalidEstate_CorrectResponseReturned() + { this.EstateClient.Setup(e => e.GetEstate(It.IsAny(), It.IsAny(), It.IsAny())) - .ReturnsAsync(TestData.GetEstateResponseWithOperator1); - this.EstateClient.Setup(e => e.GetMerchant(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) - .ReturnsAsync(TestData.GetMerchantResponseWithNoDevices); + .ReturnsAsync(Result.NotFound("Estate not found")); - (String responseMessage, TransactionResponseCode responseCode) response = await this.TransactionValidationService.ValidateSaleTransaction(TestData.EstateId, - TestData.MerchantId, - TestData.ContractId, - TestData.ProductId, - TestData.DeviceIdentifier1, - TestData.OperatorId, - TestData.TransactionAmount, - CancellationToken.None); + Result result = await this.TransactionValidationService.ValidateReconciliationTransaction(TestData.EstateId, TestData.MerchantId, + TestData.DeviceIdentifier, CancellationToken.None); - response.responseCode.ShouldBe(TransactionResponseCode.NoValidDevices); + result.IsFailed.ShouldBeTrue(); + result.Data.ResponseCode.ShouldBe(TransactionResponseCode.InvalidEstateId); } [Fact] - public async Task TransactionValidationService_ValidateSaleTransaction_MerchantDeviceListNull_ResponseIsNoValidDevices() { - this.SecurityServiceClient.Setup(s => s.GetToken(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(Result.Success(TestData.TokenResponse())); - + public async Task ValidateReconciliationTransactionX_FailureWhileGettingEstate_CorrectResponseReturned() + { + this.EstateClient.Setup(e => e.GetEstate(It.IsAny(), It.IsAny(), It.IsAny())) + .ReturnsAsync(Result.Failure("Failure Message")); + + Result result = await this.TransactionValidationService.ValidateReconciliationTransaction(TestData.EstateId, TestData.MerchantId, + TestData.DeviceIdentifier, CancellationToken.None); + + result.IsFailed.ShouldBeTrue(); + result.Data.ResponseCode.ShouldBe(TransactionResponseCode.UnknownFailure); + } + + [Fact] + public async Task ValidateReconciliationTransactionX_InvalidMerchant_CorrectResponseReturned() + { + this.EstateClient.Setup(e => e.GetEstate(It.IsAny(), It.IsAny(), It.IsAny())) + .ReturnsAsync(Result.Success(TestData.GetEstateResponseWithOperator1)); + this.EstateClient.Setup(e => e.GetMerchant(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) + .ReturnsAsync(Result.NotFound("Merchant Not Found")); + + Result result = await this.TransactionValidationService.ValidateReconciliationTransaction(TestData.EstateId, TestData.MerchantId, + TestData.DeviceIdentifier, CancellationToken.None); + + result.IsFailed.ShouldBeTrue(); + result.Data.ResponseCode.ShouldBe(TransactionResponseCode.InvalidMerchantId); + } + + [Fact] + public async Task ValidateReconciliationTransactionX_FailureWhileGettingMerchant_CorrectResponseReturned() + { + this.EstateClient.Setup(e => e.GetEstate(It.IsAny(), It.IsAny(), It.IsAny())) + .ReturnsAsync(Result.Success()); + this.EstateClient.Setup(e => e.GetMerchant(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) + .ReturnsAsync(Result.Failure("Merchant Not Found")); + + Result result = await this.TransactionValidationService.ValidateReconciliationTransaction(TestData.EstateId, TestData.MerchantId, + TestData.DeviceIdentifier, CancellationToken.None); + + result.IsFailed.ShouldBeTrue(); + result.Data.ResponseCode.ShouldBe(TransactionResponseCode.UnknownFailure); + } + + [Fact] + public async Task ValidateReconciliationTransactionX_InvalidDeviceId_CorrectResponseReturned() + { + this.EstateClient.Setup(e => e.GetEstate(It.IsAny(), It.IsAny(), It.IsAny())) + .ReturnsAsync(Result.Success(TestData.GetEstateResponseWithOperator1)); + this.EstateClient.Setup(e => e.GetMerchant(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) + .ReturnsAsync(Result.Success(TestData.GetMerchantResponseWithOperator1)); + + Result result = await this.TransactionValidationService.ValidateReconciliationTransaction(TestData.EstateId, TestData.MerchantId, + TestData.DeviceIdentifier1, CancellationToken.None); + + result.IsFailed.ShouldBeTrue(); + result.Data.ResponseCode.ShouldBe(TransactionResponseCode.InvalidDeviceIdentifier); + } + + [Fact] + public async Task ValidateReconciliationTransactionX_MerchantHasNoDevices_CorrectResponseReturned() + { + this.EstateClient.Setup(e => e.GetEstate(It.IsAny(), It.IsAny(), It.IsAny())) + .ReturnsAsync(Result.Success(TestData.GetEstateResponseWithOperator1)); + this.EstateClient.Setup(e => e.GetMerchant(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) + .ReturnsAsync(Result.Success(TestData.GetMerchantResponseWithNoDevices)); + + Result result = await this.TransactionValidationService.ValidateReconciliationTransaction(TestData.EstateId, TestData.MerchantId, + TestData.DeviceIdentifier1, CancellationToken.None); + + result.IsFailed.ShouldBeTrue(); + result.Data.ResponseCode.ShouldBe(TransactionResponseCode.NoValidDevices); + } + + [Fact] + public async Task ValidateReconciliationTransactionX_MerchantHasNullDevices_CorrectResponseReturned() + { + this.EstateClient.Setup(e => e.GetEstate(It.IsAny(), It.IsAny(), It.IsAny())) + .ReturnsAsync(Result.Success(TestData.GetEstateResponseWithOperator1)); + this.EstateClient.Setup(e => e.GetMerchant(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) + .ReturnsAsync(Result.Success(TestData.GetMerchantResponseWithNullDevices)); + + Result result = await this.TransactionValidationService.ValidateReconciliationTransaction(TestData.EstateId, TestData.MerchantId, + TestData.DeviceIdentifier1, CancellationToken.None); + + result.IsFailed.ShouldBeTrue(); + result.Data.ResponseCode.ShouldBe(TransactionResponseCode.NoValidDevices); + } + + [Fact] + public async Task TransactionValidationService_ValidateSaleTransaction_DeviceNotRegisteredToMerchant_ResponseIsInvalidDeviceIdentifier() + { + this.SecurityServiceClient.Setup(s => s.GetToken(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(Result.Success(TestData.TokenResponse())); + this.EstateClient.Setup(e => e.GetEstate(It.IsAny(), It.IsAny(), It.IsAny())) .ReturnsAsync(TestData.GetEstateResponseWithOperator1); this.EstateClient.Setup(e => e.GetMerchant(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) - .ReturnsAsync(TestData.GetMerchantResponseWithNullDevices); + .ReturnsAsync(TestData.GetMerchantResponseWithOperator1); - (String responseMessage, TransactionResponseCode responseCode) response = await this.TransactionValidationService.ValidateSaleTransaction(TestData.EstateId, + var result = await this.TransactionValidationService.ValidateSaleTransaction(TestData.EstateId, TestData.MerchantId, TestData.ContractId, TestData.ProductId, @@ -485,50 +530,44 @@ public async Task TransactionValidationService_ValidateSaleTransaction_MerchantD TestData.TransactionAmount, CancellationToken.None); - response.responseCode.ShouldBe(TransactionResponseCode.NoValidDevices); + result.IsFailed.ShouldBeTrue(); + result.Data.ResponseCode.ShouldBe(TransactionResponseCode.InvalidDeviceIdentifier); } [Fact] - public async Task TransactionValidationService_ValidateSaleTransaction_MerchantDoesNotHaveSuppliedContract_ResponseIsContractNotValidForMerchant() { + public async Task TransactionValidationService_ValidateSaleTransaction_EstateFoundButHasNoOperators_ResponseIsInvalidEstateId() + { this.SecurityServiceClient.Setup(s => s.GetToken(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(Result.Success(TestData.TokenResponse())); this.EstateClient.Setup(e => e.GetEstate(It.IsAny(), It.IsAny(), It.IsAny())) - .ReturnsAsync(TestData.GetEstateResponseWithOperator1); + .ReturnsAsync(TestData.GetEstateResponseWithEmptyOperators); this.EstateClient.Setup(e => e.GetMerchant(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) - .ReturnsAsync(TestData.GetMerchantResponseWithOperator1); - this.EstateClient.Setup(e => e.GetMerchantContracts(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) - .ReturnsAsync(TestData.MerchantContractResponses); - - this.EventStoreContext.Setup(e => e.GetPartitionStateFromProjection(It.IsAny(), It.IsAny(), It.IsAny())) - .ReturnsAsync(JsonConvert.SerializeObject(TestData.MerchantBalanceProjectionState)); + .ReturnsAsync(TestData.GetEmptyMerchantResponse); - (String responseMessage, TransactionResponseCode responseCode) response = await this.TransactionValidationService.ValidateSaleTransaction(TestData.EstateId, + var result = await this.TransactionValidationService.ValidateSaleTransaction(TestData.EstateId, TestData.MerchantId, - TestData.ContractId1, + TestData.ContractId, TestData.ProductId, TestData.DeviceIdentifier, TestData.OperatorId, TestData.TransactionAmount, CancellationToken.None); - response.responseCode.ShouldBe(TransactionResponseCode.ContractNotValidForMerchant); + result.IsFailed.ShouldBeTrue(); + result.Data.ResponseCode.ShouldBe(TransactionResponseCode.NoEstateOperators); } [Fact] - public async Task TransactionValidationService_ValidateSaleTransaction_MerchantHasNoContracts_ResponseIsMerchantDoesNotHaveEnoughCredit() { + public async Task TransactionValidationService_ValidateSaleTransaction_EstateFoundButOperatorIsDeleted_ResponseIsOperatorNotEnabledForEstate() + { this.SecurityServiceClient.Setup(s => s.GetToken(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(Result.Success(TestData.TokenResponse())); this.EstateClient.Setup(e => e.GetEstate(It.IsAny(), It.IsAny(), It.IsAny())) - .ReturnsAsync(TestData.GetEstateResponseWithOperator1); - this.EstateClient.SetupSequence(e => e.GetMerchant(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) - .ReturnsAsync(TestData.GetMerchantResponseWithOperator1) - .ReturnsAsync(TestData.GetMerchantResponseWithOperator1AndEmptyContracts); - - - this.EventStoreContext.Setup(e => e.GetPartitionStateFromProjection(It.IsAny(), It.IsAny(), It.IsAny())) - .ReturnsAsync(JsonConvert.SerializeObject(TestData.MerchantBalanceProjectionState)); + .ReturnsAsync(TestData.GetEstateResponseWithOperator1Deleted); + this.EstateClient.Setup(e => e.GetMerchant(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) + .ReturnsAsync(TestData.GetEmptyMerchantResponse); - (String responseMessage, TransactionResponseCode responseCode) response = await this.TransactionValidationService.ValidateSaleTransaction(TestData.EstateId, + var result = await this.TransactionValidationService.ValidateSaleTransaction(TestData.EstateId, TestData.MerchantId, TestData.ContractId, TestData.ProductId, @@ -537,24 +576,21 @@ public async Task TransactionValidationService_ValidateSaleTransaction_MerchantH TestData.TransactionAmount, CancellationToken.None); - response.responseCode.ShouldBe(TransactionResponseCode.MerchantHasNoContractsConfigured); + result.IsFailed.ShouldBeTrue(); + result.Data.ResponseCode.ShouldBe(TransactionResponseCode.OperatorNotEnabledForEstate); } - [Fact] - public async Task TransactionValidationService_ValidateSaleTransaction_MerchantHasNullContracts_ResponseIsMerchantDoesNotHaveEnoughCredit() { + public async Task TransactionValidationService_ValidateSaleTransaction_EstateFoundButHasNullOperators_ResponseIsInvalidEstateId() + { this.SecurityServiceClient.Setup(s => s.GetToken(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(Result.Success(TestData.TokenResponse())); this.EstateClient.Setup(e => e.GetEstate(It.IsAny(), It.IsAny(), It.IsAny())) - .ReturnsAsync(TestData.GetEstateResponseWithOperator1); - this.EstateClient.SetupSequence(e => e.GetMerchant(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) - .ReturnsAsync(TestData.GetMerchantResponseWithOperator1) - .ReturnsAsync(TestData.GetMerchantResponseWithOperator1AndNullContracts); - - this.EventStoreContext.Setup(e => e.GetPartitionStateFromProjection(It.IsAny(), It.IsAny(), It.IsAny())) - .ReturnsAsync(JsonConvert.SerializeObject(TestData.MerchantBalanceProjectionState)); + .ReturnsAsync(TestData.GetEstateResponseWithNullOperators); + this.EstateClient.Setup(e => e.GetMerchant(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) + .ReturnsAsync(TestData.GetEmptyMerchantResponse); - (String responseMessage, TransactionResponseCode responseCode) response = await this.TransactionValidationService.ValidateSaleTransaction(TestData.EstateId, + var result = await this.TransactionValidationService.ValidateSaleTransaction(TestData.EstateId, TestData.MerchantId, TestData.ContractId, TestData.ProductId, @@ -563,44 +599,42 @@ public async Task TransactionValidationService_ValidateSaleTransaction_MerchantH TestData.TransactionAmount, CancellationToken.None); - response.responseCode.ShouldBe(TransactionResponseCode.MerchantHasNoContractsConfigured); + result.IsFailed.ShouldBeTrue(); + result.Data.ResponseCode.ShouldBe(TransactionResponseCode.NoEstateOperators); } - + [Fact] - public async Task TransactionValidationService_ValidateSaleTransaction_MerchantNotEnoughCredit_ResponseIsMerchantDoesNotHaveEnoughCredit() { + public async Task TransactionValidationService_ValidateSaleTransaction_EstateFoundOperatorsNotConfiguredForEstate_ResponseIsOperatorNotValidForEstate() + { this.SecurityServiceClient.Setup(s => s.GetToken(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(Result.Success(TestData.TokenResponse())); this.EstateClient.Setup(e => e.GetEstate(It.IsAny(), It.IsAny(), It.IsAny())) .ReturnsAsync(TestData.GetEstateResponseWithOperator1); this.EstateClient.Setup(e => e.GetMerchant(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) - .ReturnsAsync(TestData.GetMerchantResponseWithOperator1); - this.EstateClient.Setup(e => e.GetMerchantContracts(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) - .ReturnsAsync(TestData.MerchantContractResponses); - this.EventStoreContext.Setup(e => e.GetPartitionStateFromProjection(It.IsAny(), It.IsAny(), It.IsAny())) - .ReturnsAsync(JsonConvert.SerializeObject(TestData.MerchantBalanceProjectionStateNoCredit)); + .ReturnsAsync(TestData.GetEmptyMerchantResponse); - (String responseMessage, TransactionResponseCode responseCode) response = await this.TransactionValidationService.ValidateSaleTransaction(TestData.EstateId, + var result = await this.TransactionValidationService.ValidateSaleTransaction(TestData.EstateId, TestData.MerchantId, TestData.ContractId, TestData.ProductId, TestData.DeviceIdentifier, - TestData.OperatorId, + TestData.OperatorId2, TestData.TransactionAmount, CancellationToken.None); - response.responseCode.ShouldBe(TransactionResponseCode.MerchantDoesNotHaveEnoughCredit); + result.IsFailed.ShouldBeTrue(); + result.Data.ResponseCode.ShouldBe(TransactionResponseCode.OperatorNotValidForEstate); } [Fact] - public async Task TransactionValidationService_ValidateSaleTransaction_MerchantNotFound_ResponseIsInvalidMerchantId() { + public async Task TransactionValidationService_ValidateSaleTransaction_EstateNotFound_ResponseIsInvalidEstateId() + { this.SecurityServiceClient.Setup(s => s.GetToken(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(Result.Success(TestData.TokenResponse())); this.EstateClient.Setup(e => e.GetEstate(It.IsAny(), It.IsAny(), It.IsAny())) - .ReturnsAsync(TestData.GetEstateResponseWithOperator1); - this.EstateClient.Setup(e => e.GetMerchant(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) .ReturnsAsync(Result.NotFound()); - (String responseMessage, TransactionResponseCode responseCode) response = await this.TransactionValidationService.ValidateSaleTransaction(TestData.EstateId, + var result = await this.TransactionValidationService.ValidateSaleTransaction(TestData.EstateId, TestData.MerchantId, TestData.ContractId, TestData.ProductId, @@ -609,124 +643,161 @@ public async Task TransactionValidationService_ValidateSaleTransaction_MerchantN TestData.TransactionAmount, CancellationToken.None); - response.responseCode.ShouldBe(TransactionResponseCode.InvalidMerchantId); + result.IsFailed.ShouldBeTrue(); + result.Data.ResponseCode.ShouldBe(TransactionResponseCode.InvalidEstateId); + } + + [Fact] + public async Task TransactionValidationService_ValidateSaleTransaction_GetEstateFailed_ResponseIsInvalidEstateId() + { + this.SecurityServiceClient.Setup(s => s.GetToken(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(Result.Success(TestData.TokenResponse())); + + this.EstateClient.Setup(e => e.GetEstate(It.IsAny(), It.IsAny(), It.IsAny())) + .ReturnsAsync(Result.Failure()); + + var result = await this.TransactionValidationService.ValidateSaleTransaction(TestData.EstateId, + TestData.MerchantId, + TestData.ContractId, + TestData.ProductId, + TestData.DeviceIdentifier, + TestData.OperatorId, + TestData.TransactionAmount, + CancellationToken.None); + + result.IsFailed.ShouldBeTrue(); + result.Data.ResponseCode.ShouldBe(TransactionResponseCode.UnknownFailure); } [Fact] - public async Task TransactionValidationService_ValidateSaleTransaction_MerchantNotFoundOnGetContract_ResponseIsInvalidMerchantId() { + public async Task TransactionValidationService_ValidateSaleTransaction_InvalidContractId_ResponseIsInvalidContractIdValue() + { this.SecurityServiceClient.Setup(s => s.GetToken(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(Result.Success(TestData.TokenResponse())); this.EstateClient.Setup(e => e.GetEstate(It.IsAny(), It.IsAny(), It.IsAny())) .ReturnsAsync(TestData.GetEstateResponseWithOperator1); - this.EstateClient.SetupSequence(e => e.GetMerchant(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) - .ReturnsAsync(TestData.GetMerchantResponseWithOperator1) - .ThrowsAsync(new Exception("Exception", new KeyNotFoundException("Invalid Merchant"))); - //this.EstateClient.Setup(e => e.GetMerchantContracts(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) - // .ThrowsAsync(new Exception("Exception", new KeyNotFoundException("Invalid Merchant"))); + this.EstateClient.Setup(e => e.GetMerchant(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) + .ReturnsAsync(TestData.GetMerchantResponseWithOperator1); this.EventStoreContext.Setup(e => e.GetPartitionStateFromProjection(It.IsAny(), It.IsAny(), It.IsAny())) .ReturnsAsync(JsonConvert.SerializeObject(TestData.MerchantBalanceProjectionState)); - (String responseMessage, TransactionResponseCode responseCode) response = await this.TransactionValidationService.ValidateSaleTransaction(TestData.EstateId, + var result = await this.TransactionValidationService.ValidateSaleTransaction(TestData.EstateId, TestData.MerchantId, - TestData.ContractId, + Guid.Empty, TestData.ProductId, TestData.DeviceIdentifier, TestData.OperatorId, TestData.TransactionAmount, CancellationToken.None); - response.responseCode.ShouldBe(TransactionResponseCode.InvalidMerchantId); + result.IsFailed.ShouldBeTrue(); + result.Data.ResponseCode.ShouldBe(TransactionResponseCode.InvalidContractIdValue); } [Fact] - public async Task TransactionValidationService_ValidateSaleTransaction_MerchantOperatorListEmpty_ResponseIsNoMerchantOperators() { + public async Task TransactionValidationService_ValidateSaleTransaction_InvalidProductId_ResponseIsInvalidProductIdValue() + { this.SecurityServiceClient.Setup(s => s.GetToken(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(Result.Success(TestData.TokenResponse())); this.EstateClient.Setup(e => e.GetEstate(It.IsAny(), It.IsAny(), It.IsAny())) .ReturnsAsync(TestData.GetEstateResponseWithOperator1); this.EstateClient.Setup(e => e.GetMerchant(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) - .ReturnsAsync(TestData.GetMerchantResponseWithEmptyOperators); + .ReturnsAsync(TestData.GetMerchantResponseWithOperator1); + this.EstateClient.Setup(e => e.GetMerchantContracts(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) + .ReturnsAsync(TestData.MerchantContractResponses); + + this.EventStoreContext.Setup(e => e.GetPartitionStateFromProjection(It.IsAny(), It.IsAny(), It.IsAny())) + .ReturnsAsync(JsonConvert.SerializeObject(TestData.MerchantBalanceProjectionState)); - (String responseMessage, TransactionResponseCode responseCode) response = await this.TransactionValidationService.ValidateSaleTransaction(TestData.EstateId, + var result = await this.TransactionValidationService.ValidateSaleTransaction(TestData.EstateId, TestData.MerchantId, TestData.ContractId, - TestData.ProductId, + Guid.Empty, TestData.DeviceIdentifier, TestData.OperatorId, TestData.TransactionAmount, CancellationToken.None); - response.responseCode.ShouldBe(TransactionResponseCode.NoMerchantOperators); + result.IsFailed.ShouldBeTrue(); + result.Data.ResponseCode.ShouldBe(TransactionResponseCode.InvalidProductIdValue); } - [Fact] - public async Task TransactionValidationService_ValidateSaleTransaction_MerchantOperatorListNull_ResponseIsNoMerchantOperators() { + [Theory] + [InlineData(0)] + [InlineData(-1)] + public async Task TransactionValidationService_ValidateSaleTransaction_InvalidTransactionAmount_ResponseIsInvalidSaleTransactionAmount(Decimal transactionAmount) + { this.SecurityServiceClient.Setup(s => s.GetToken(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(Result.Success(TestData.TokenResponse())); this.EstateClient.Setup(e => e.GetEstate(It.IsAny(), It.IsAny(), It.IsAny())) .ReturnsAsync(TestData.GetEstateResponseWithOperator1); this.EstateClient.Setup(e => e.GetMerchant(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) - .ReturnsAsync(TestData.GetMerchantResponseWithNullOperators); + .ReturnsAsync(TestData.GetMerchantResponseWithOperator1); + this.EstateClient.Setup(e => e.GetMerchantContracts(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) + .ReturnsAsync(TestData.MerchantContractResponses); - (String responseMessage, TransactionResponseCode responseCode) response = await this.TransactionValidationService.ValidateSaleTransaction(TestData.EstateId, + var result = await this.TransactionValidationService.ValidateSaleTransaction(TestData.EstateId, TestData.MerchantId, TestData.ContractId, TestData.ProductId, TestData.DeviceIdentifier, TestData.OperatorId, - TestData.TransactionAmount, + transactionAmount, CancellationToken.None); - response.responseCode.ShouldBe(TransactionResponseCode.NoMerchantOperators); + result.IsFailed.ShouldBeTrue(); + result.Data.ResponseCode.ShouldBe(TransactionResponseCode.InvalidSaleTransactionAmount); } [Fact] - public async Task TransactionValidationService_ValidateSaleTransaction_MerchantOperatorIsDeleted_ResponseIsOperatorNotEnabledForMerchant() + public async Task TransactionValidationService_ValidateSaleTransaction_MerchantDeviceListEmpty_ResponseIsNoValidDevices() { this.SecurityServiceClient.Setup(s => s.GetToken(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(Result.Success(TestData.TokenResponse())); this.EstateClient.Setup(e => e.GetEstate(It.IsAny(), It.IsAny(), It.IsAny())) .ReturnsAsync(TestData.GetEstateResponseWithOperator1); this.EstateClient.Setup(e => e.GetMerchant(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) - .ReturnsAsync(TestData.GetMerchantResponseWithOperator1Deleted); + .ReturnsAsync(TestData.GetMerchantResponseWithNoDevices); - (String responseMessage, TransactionResponseCode responseCode) response = await this.TransactionValidationService.ValidateSaleTransaction(TestData.EstateId, + var result = await this.TransactionValidationService.ValidateSaleTransaction(TestData.EstateId, TestData.MerchantId, TestData.ContractId, TestData.ProductId, - TestData.DeviceIdentifier, + TestData.DeviceIdentifier1, TestData.OperatorId, TestData.TransactionAmount, CancellationToken.None); - response.responseCode.ShouldBe(TransactionResponseCode.OperatorNotEnabledForMerchant); + result.IsFailed.ShouldBeTrue(); + result.Data.ResponseCode.ShouldBe(TransactionResponseCode.NoValidDevices); } [Fact] - public async Task TransactionValidationService_ValidateSaleTransaction_OperatorNotConfiguredFroMerchant_ResponseIsOperatorNotValidForMerchant() { + public async Task TransactionValidationService_ValidateSaleTransaction_MerchantDeviceListNull_ResponseIsNoValidDevices() + { this.SecurityServiceClient.Setup(s => s.GetToken(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(Result.Success(TestData.TokenResponse())); this.EstateClient.Setup(e => e.GetEstate(It.IsAny(), It.IsAny(), It.IsAny())) .ReturnsAsync(TestData.GetEstateResponseWithOperator1); this.EstateClient.Setup(e => e.GetMerchant(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) - .ReturnsAsync(TestData.GetMerchantResponseWithOperator2); + .ReturnsAsync(TestData.GetMerchantResponseWithNullDevices); - (String responseMessage, TransactionResponseCode responseCode) response = await this.TransactionValidationService.ValidateSaleTransaction(TestData.EstateId, + var result = await this.TransactionValidationService.ValidateSaleTransaction(TestData.EstateId, TestData.MerchantId, TestData.ContractId, TestData.ProductId, - TestData.DeviceIdentifier, + TestData.DeviceIdentifier1, TestData.OperatorId, TestData.TransactionAmount, CancellationToken.None); - response.responseCode.ShouldBe(TransactionResponseCode.OperatorNotValidForMerchant); + result.IsFailed.ShouldBeTrue(); + result.Data.ResponseCode.ShouldBe(TransactionResponseCode.NoValidDevices); } - [Fact] - public async Task TransactionValidationService_ValidateSaleTransaction_ProductIdNotConfigured_ResponseIsProductNotValidForMerchant() { + public async Task TransactionValidationService_ValidateSaleTransaction_MerchantDoesNotHaveSuppliedContract_ResponseIsContractNotValidForMerchant() + { this.SecurityServiceClient.Setup(s => s.GetToken(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(Result.Success(TestData.TokenResponse())); this.EstateClient.Setup(e => e.GetEstate(It.IsAny(), It.IsAny(), It.IsAny())) @@ -739,33 +810,35 @@ public async Task TransactionValidationService_ValidateSaleTransaction_ProductId this.EventStoreContext.Setup(e => e.GetPartitionStateFromProjection(It.IsAny(), It.IsAny(), It.IsAny())) .ReturnsAsync(JsonConvert.SerializeObject(TestData.MerchantBalanceProjectionState)); - (String responseMessage, TransactionResponseCode responseCode) response = await this.TransactionValidationService.ValidateSaleTransaction(TestData.EstateId, + var result = await this.TransactionValidationService.ValidateSaleTransaction(TestData.EstateId, TestData.MerchantId, - TestData.ContractId, - TestData.ProductId1, + TestData.ContractId1, + TestData.ProductId, TestData.DeviceIdentifier, TestData.OperatorId, TestData.TransactionAmount, CancellationToken.None); - response.responseCode.ShouldBe(TransactionResponseCode.ProductNotValidForMerchant); + result.IsFailed.ShouldBeTrue(); + result.Data.ResponseCode.ShouldBe(TransactionResponseCode.ContractNotValidForMerchant); } [Fact] - public async Task TransactionValidationService_ValidateSaleTransaction_SuccessfulSale() { + public async Task TransactionValidationService_ValidateSaleTransaction_MerchantHasNoContracts_ResponseIsMerchantDoesNotHaveEnoughCredit() + { this.SecurityServiceClient.Setup(s => s.GetToken(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(Result.Success(TestData.TokenResponse())); this.EstateClient.Setup(e => e.GetEstate(It.IsAny(), It.IsAny(), It.IsAny())) .ReturnsAsync(TestData.GetEstateResponseWithOperator1); - this.EstateClient.Setup(e => e.GetMerchant(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) - .ReturnsAsync(TestData.GetMerchantResponseWithOperator1); - this.EstateClient.Setup(e => e.GetMerchantContracts(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) - .ReturnsAsync(TestData.MerchantContractResponses); + this.EstateClient.SetupSequence(e => e.GetMerchant(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) + .ReturnsAsync(TestData.GetMerchantResponseWithOperator1) + .ReturnsAsync(TestData.GetMerchantResponseWithOperator1AndEmptyContracts); + this.EventStoreContext.Setup(e => e.GetPartitionStateFromProjection(It.IsAny(), It.IsAny(), It.IsAny())) - .ReturnsAsync(JsonConvert.SerializeObject(TestData.MerchantBalanceProjectionState)); + .ReturnsAsync(JsonConvert.SerializeObject(TestData.MerchantBalanceProjectionState)); - (String responseMessage, TransactionResponseCode responseCode) response = await this.TransactionValidationService.ValidateSaleTransaction(TestData.EstateId, + var result = await this.TransactionValidationService.ValidateSaleTransaction(TestData.EstateId, TestData.MerchantId, TestData.ContractId, TestData.ProductId, @@ -774,264 +847,338 @@ public async Task TransactionValidationService_ValidateSaleTransaction_Successfu TestData.TransactionAmount, CancellationToken.None); - response.responseCode.ShouldBe(TransactionResponseCode.Success); + result.IsFailed.ShouldBeTrue(); + result.Data.ResponseCode.ShouldBe(TransactionResponseCode.MerchantHasNoContractsConfigured); } -} - -public class TransactionValidationServiceTests_New { - private readonly TransactionValidationService TransactionValidationService; - private readonly Mock SecurityServiceClient; - - private readonly Mock> StateRepository; - private readonly Mock EstateClient; - private readonly Mock EventStoreContext; - public TransactionValidationServiceTests_New() { - IConfigurationRoot configurationRoot = new ConfigurationBuilder().AddInMemoryCollection(TestData.DefaultAppSettings).Build(); - ConfigurationReader.Initialise(configurationRoot); - - Logger.Initialise(NullLogger.Instance); - this.EstateClient = new Mock(); - this.SecurityServiceClient = new Mock(); - this.StateRepository = new Mock>(); - this.EventStoreContext = new Mock(); + [Fact] + public async Task TransactionValidationService_ValidateSaleTransaction_MerchantHasNullContracts_ResponseIsMerchantDoesNotHaveEnoughCredit() + { this.SecurityServiceClient.Setup(s => s.GetToken(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(Result.Success(TestData.TokenResponse())); - this.TransactionValidationService = new TransactionValidationService(this.EstateClient.Object, - this.SecurityServiceClient.Object, - this.StateRepository.Object, - this.EventStoreContext.Object); - } - - [Fact] - public async Task ValidateLogonTransactionX_ValidationSuccessful_CorrectResponseReturned() { this.EstateClient.Setup(e => e.GetEstate(It.IsAny(), It.IsAny(), It.IsAny())) - .ReturnsAsync(Result.Success(TestData.GetEstateResponseWithOperator1)); - this.EstateClient.Setup(e => e.GetMerchant(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) - .ReturnsAsync(Result.Success(TestData.GetMerchantResponseWithOperator1)); - - Result result = await this.TransactionValidationService.ValidateLogonTransactionX(TestData.EstateId, TestData.MerchantId, - TestData.DeviceIdentifier, CancellationToken.None); - - result.IsSuccess.ShouldBeTrue(); - result.Data.ResponseCode.ShouldBe(TransactionResponseCode.Success); - } + .ReturnsAsync(TestData.GetEstateResponseWithOperator1); + this.EstateClient.SetupSequence(e => e.GetMerchant(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) + .ReturnsAsync(TestData.GetMerchantResponseWithOperator1) + .ReturnsAsync(TestData.GetMerchantResponseWithOperator1AndNullContracts); - [Fact] - public async Task ValidateLogonTransactionX_InvalidEstate_CorrectResponseReturned() { - this.EstateClient.Setup(e => e.GetEstate(It.IsAny(), It.IsAny(), It.IsAny())) - .ReturnsAsync(Result.NotFound("Estate not found")); + this.EventStoreContext.Setup(e => e.GetPartitionStateFromProjection(It.IsAny(), It.IsAny(), It.IsAny())) + .ReturnsAsync(JsonConvert.SerializeObject(TestData.MerchantBalanceProjectionState)); - Result result = await this.TransactionValidationService.ValidateLogonTransactionX(TestData.EstateId, TestData.MerchantId, - TestData.DeviceIdentifier, CancellationToken.None); + var result = await this.TransactionValidationService.ValidateSaleTransaction(TestData.EstateId, + TestData.MerchantId, + TestData.ContractId, + TestData.ProductId, + TestData.DeviceIdentifier, + TestData.OperatorId, + TestData.TransactionAmount, + CancellationToken.None); result.IsFailed.ShouldBeTrue(); - result.Data.ResponseCode.ShouldBe(TransactionResponseCode.InvalidEstateId); + result.Data.ResponseCode.ShouldBe(TransactionResponseCode.MerchantHasNoContractsConfigured); } [Fact] - public async Task ValidateLogonTransactionX_FailureWhileGettingEstate_CorrectResponseReturned() + public async Task TransactionValidationService_ValidateSaleTransaction_MerchantNotEnoughCredit_ResponseIsMerchantDoesNotHaveEnoughCredit() { + this.SecurityServiceClient.Setup(s => s.GetToken(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(Result.Success(TestData.TokenResponse())); + this.EstateClient.Setup(e => e.GetEstate(It.IsAny(), It.IsAny(), It.IsAny())) - .ReturnsAsync(Result.Failure("Failure Message")); + .ReturnsAsync(TestData.GetEstateResponseWithOperator1); + this.EstateClient.Setup(e => e.GetMerchant(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) + .ReturnsAsync(TestData.GetMerchantResponseWithOperator1); + this.EstateClient.Setup(e => e.GetMerchantContracts(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) + .ReturnsAsync(TestData.MerchantContractResponses); + this.EventStoreContext.Setup(e => e.GetPartitionStateFromProjection(It.IsAny(), It.IsAny(), It.IsAny())) + .ReturnsAsync(JsonConvert.SerializeObject(TestData.MerchantBalanceProjectionStateNoCredit)); - Result result = await this.TransactionValidationService.ValidateLogonTransactionX(TestData.EstateId, TestData.MerchantId, - TestData.DeviceIdentifier, CancellationToken.None); + var result = await this.TransactionValidationService.ValidateSaleTransaction(TestData.EstateId, + TestData.MerchantId, + TestData.ContractId, + TestData.ProductId, + TestData.DeviceIdentifier, + TestData.OperatorId, + TestData.TransactionAmount, + CancellationToken.None); result.IsFailed.ShouldBeTrue(); - result.Data.ResponseCode.ShouldBe(TransactionResponseCode.UnknownFailure); + result.Data.ResponseCode.ShouldBe(TransactionResponseCode.MerchantDoesNotHaveEnoughCredit); } [Fact] - public async Task ValidateLogonTransactionX_InvalidMerchant_CorrectResponseReturned() + public async Task TransactionValidationService_ValidateSaleTransaction_MerchantNotFound_ResponseIsInvalidMerchantId() { + this.SecurityServiceClient.Setup(s => s.GetToken(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(Result.Success(TestData.TokenResponse())); + this.EstateClient.Setup(e => e.GetEstate(It.IsAny(), It.IsAny(), It.IsAny())) - .ReturnsAsync(Result.Success(TestData.GetEstateResponseWithOperator1)); + .ReturnsAsync(TestData.GetEstateResponseWithOperator1); this.EstateClient.Setup(e => e.GetMerchant(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) - .ReturnsAsync(Result.NotFound("Merchant Not Found")); + .ReturnsAsync(Result.NotFound()); - Result result = await this.TransactionValidationService.ValidateLogonTransactionX(TestData.EstateId, TestData.MerchantId, - TestData.DeviceIdentifier, CancellationToken.None); + var result = await this.TransactionValidationService.ValidateSaleTransaction(TestData.EstateId, + TestData.MerchantId, + TestData.ContractId, + TestData.ProductId, + TestData.DeviceIdentifier, + TestData.OperatorId, + TestData.TransactionAmount, + CancellationToken.None); result.IsFailed.ShouldBeTrue(); result.Data.ResponseCode.ShouldBe(TransactionResponseCode.InvalidMerchantId); } [Fact] - public async Task ValidateLogonTransactionX_FailureWhileGettingMerchant_CorrectResponseReturned() + public async Task TransactionValidationService_ValidateSaleTransaction_FailedGettingMerchant_ResponseIsInvalidMerchantId() { + this.SecurityServiceClient.Setup(s => s.GetToken(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(Result.Success(TestData.TokenResponse())); + this.EstateClient.Setup(e => e.GetEstate(It.IsAny(), It.IsAny(), It.IsAny())) - .ReturnsAsync(Result.Success()); + .ReturnsAsync(TestData.GetEstateResponseWithOperator1); this.EstateClient.Setup(e => e.GetMerchant(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) - .ReturnsAsync(Result.Failure("Merchant Not Found")); + .ReturnsAsync(Result.Failure()); - Result result = await this.TransactionValidationService.ValidateLogonTransactionX(TestData.EstateId, TestData.MerchantId, - TestData.DeviceIdentifier, CancellationToken.None); + var result = await this.TransactionValidationService.ValidateSaleTransaction(TestData.EstateId, + TestData.MerchantId, + TestData.ContractId, + TestData.ProductId, + TestData.DeviceIdentifier, + TestData.OperatorId, + TestData.TransactionAmount, + CancellationToken.None); result.IsFailed.ShouldBeTrue(); result.Data.ResponseCode.ShouldBe(TransactionResponseCode.UnknownFailure); } [Fact] - public async Task ValidateLogonTransactionX_InvalidDeviceId_CorrectResponseReturned() + public async Task TransactionValidationService_ValidateSaleTransaction_MerchantNotFoundOnGetContract_ResponseIsInvalidMerchantId() { + this.SecurityServiceClient.Setup(s => s.GetToken(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(Result.Success(TestData.TokenResponse())); + this.EstateClient.Setup(e => e.GetEstate(It.IsAny(), It.IsAny(), It.IsAny())) - .ReturnsAsync(Result.Success(TestData.GetEstateResponseWithOperator1)); - this.EstateClient.Setup(e => e.GetMerchant(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) - .ReturnsAsync(Result.Success(TestData.GetMerchantResponseWithOperator1)); + .ReturnsAsync(TestData.GetEstateResponseWithOperator1); + this.EstateClient.SetupSequence(e => e.GetMerchant(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(TestData.GetMerchantResponseWithOperator1) + .ReturnsAsync(Result.NotFound()); + //this.EstateClient.Setup(e => e.GetMerchantContracts(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) + // .ThrowsAsync(new Exception("Exception", new KeyNotFoundException("Invalid Merchant"))); - Result result = await this.TransactionValidationService.ValidateLogonTransactionX(TestData.EstateId, TestData.MerchantId, - TestData.DeviceIdentifier1, CancellationToken.None); + 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, + TestData.ProductId, + TestData.DeviceIdentifier, + TestData.OperatorId, + TestData.TransactionAmount, + CancellationToken.None); result.IsFailed.ShouldBeTrue(); - result.Data.ResponseCode.ShouldBe(TransactionResponseCode.InvalidDeviceIdentifier); + result.Data.ResponseCode.ShouldBe(TransactionResponseCode.InvalidMerchantId); } [Fact] - public async Task ValidateLogonTransactionX_MerchantHasNoDevices_CorrectResponseReturned() + public async Task TransactionValidationService_ValidateSaleTransaction_FailedGettingMerchantOnGetContract_ResponseIsInvalidMerchantId() { - this.EstateClient.Setup(e => e.GetEstate(It.IsAny(), It.IsAny(), It.IsAny())) - .ReturnsAsync(Result.Success(TestData.GetEstateResponseWithOperator1)); - this.EstateClient.Setup(e => e.GetMerchant(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) - .ReturnsAsync(Result.Success(TestData.GetMerchantResponseWithNoDevices)); - - Result result = await this.TransactionValidationService.ValidateLogonTransactionX(TestData.EstateId, TestData.MerchantId, - TestData.DeviceIdentifier1, CancellationToken.None); - - result.IsSuccess.ShouldBeTrue(); - result.Data.ResponseCode.ShouldBe(TransactionResponseCode.SuccessNeedToAddDevice); - } + this.SecurityServiceClient.Setup(s => s.GetToken(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(Result.Success(TestData.TokenResponse())); - [Fact] - public async Task ValidateLogonTransactionX_MerchantHasNullDevices_CorrectResponseReturned() - { this.EstateClient.Setup(e => e.GetEstate(It.IsAny(), It.IsAny(), It.IsAny())) - .ReturnsAsync(Result.Success(TestData.GetEstateResponseWithOperator1)); - this.EstateClient.Setup(e => e.GetMerchant(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) - .ReturnsAsync(Result.Success(TestData.GetMerchantResponseWithNullDevices)); - - Result result = await this.TransactionValidationService.ValidateLogonTransactionX(TestData.EstateId, TestData.MerchantId, - TestData.DeviceIdentifier1, CancellationToken.None); - - result.IsSuccess.ShouldBeTrue(); - result.Data.ResponseCode.ShouldBe(TransactionResponseCode.SuccessNeedToAddDevice); - } + .ReturnsAsync(TestData.GetEstateResponseWithOperator1); + this.EstateClient.SetupSequence(e => e.GetMerchant(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(TestData.GetMerchantResponseWithOperator1) + .ReturnsAsync(Result.Failure()); + //this.EstateClient.Setup(e => e.GetMerchantContracts(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) + // .ThrowsAsync(new Exception("Exception", new KeyNotFoundException("Invalid Merchant"))); - [Fact] - public async Task ValidateReconciliationTransactionX_ValidationSuccessful_CorrectResponseReturned() - { - this.EstateClient.Setup(e => e.GetEstate(It.IsAny(), It.IsAny(), It.IsAny())) - .ReturnsAsync(Result.Success(TestData.GetEstateResponseWithOperator1)); - this.EstateClient.Setup(e => e.GetMerchant(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) - .ReturnsAsync(Result.Success(TestData.GetMerchantResponseWithOperator1)); + this.EventStoreContext.Setup(e => e.GetPartitionStateFromProjection(It.IsAny(), It.IsAny(), It.IsAny())) + .ReturnsAsync(JsonConvert.SerializeObject(TestData.MerchantBalanceProjectionState)); - Result result = await this.TransactionValidationService.ValidateReconciliationTransactionX(TestData.EstateId, TestData.MerchantId, - TestData.DeviceIdentifier, CancellationToken.None); + var result = await this.TransactionValidationService.ValidateSaleTransaction(TestData.EstateId, + TestData.MerchantId, + TestData.ContractId, + TestData.ProductId, + TestData.DeviceIdentifier, + TestData.OperatorId, + TestData.TransactionAmount, + CancellationToken.None); - result.IsSuccess.ShouldBeTrue(); - result.Data.ResponseCode.ShouldBe(TransactionResponseCode.Success); + result.IsFailed.ShouldBeTrue(); + result.Data.ResponseCode.ShouldBe(TransactionResponseCode.UnknownFailure); } [Fact] - public async Task ValidateReconciliationTransactionX_InvalidEstate_CorrectResponseReturned() + public async Task TransactionValidationService_ValidateSaleTransaction_MerchantOperatorListEmpty_ResponseIsNoMerchantOperators() { + this.SecurityServiceClient.Setup(s => s.GetToken(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(Result.Success(TestData.TokenResponse())); + this.EstateClient.Setup(e => e.GetEstate(It.IsAny(), It.IsAny(), It.IsAny())) - .ReturnsAsync(Result.NotFound("Estate not found")); + .ReturnsAsync(TestData.GetEstateResponseWithOperator1); + this.EstateClient.Setup(e => e.GetMerchant(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) + .ReturnsAsync(TestData.GetMerchantResponseWithEmptyOperators); - Result result = await this.TransactionValidationService.ValidateReconciliationTransactionX(TestData.EstateId, TestData.MerchantId, - TestData.DeviceIdentifier, CancellationToken.None); + var result = await this.TransactionValidationService.ValidateSaleTransaction(TestData.EstateId, + TestData.MerchantId, + TestData.ContractId, + TestData.ProductId, + TestData.DeviceIdentifier, + TestData.OperatorId, + TestData.TransactionAmount, + CancellationToken.None); result.IsFailed.ShouldBeTrue(); - result.Data.ResponseCode.ShouldBe(TransactionResponseCode.InvalidEstateId); + result.Data.ResponseCode.ShouldBe(TransactionResponseCode.NoMerchantOperators); } [Fact] - public async Task ValidateReconciliationTransactionX_FailureWhileGettingEstate_CorrectResponseReturned() + public async Task TransactionValidationService_ValidateSaleTransaction_MerchantOperatorListNull_ResponseIsNoMerchantOperators() { + this.SecurityServiceClient.Setup(s => s.GetToken(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(Result.Success(TestData.TokenResponse())); + this.EstateClient.Setup(e => e.GetEstate(It.IsAny(), It.IsAny(), It.IsAny())) - .ReturnsAsync(Result.Failure("Failure Message")); + .ReturnsAsync(TestData.GetEstateResponseWithOperator1); + this.EstateClient.Setup(e => e.GetMerchant(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) + .ReturnsAsync(TestData.GetMerchantResponseWithNullOperators); - Result result = await this.TransactionValidationService.ValidateReconciliationTransactionX(TestData.EstateId, TestData.MerchantId, - TestData.DeviceIdentifier, CancellationToken.None); + var result = await this.TransactionValidationService.ValidateSaleTransaction(TestData.EstateId, + TestData.MerchantId, + TestData.ContractId, + TestData.ProductId, + TestData.DeviceIdentifier, + TestData.OperatorId, + TestData.TransactionAmount, + CancellationToken.None); result.IsFailed.ShouldBeTrue(); - result.Data.ResponseCode.ShouldBe(TransactionResponseCode.UnknownFailure); + result.Data.ResponseCode.ShouldBe(TransactionResponseCode.NoMerchantOperators); } [Fact] - public async Task ValidateReconciliationTransactionX_InvalidMerchant_CorrectResponseReturned() + public async Task TransactionValidationService_ValidateSaleTransaction_MerchantOperatorIsDeleted_ResponseIsOperatorNotEnabledForMerchant() { + this.SecurityServiceClient.Setup(s => s.GetToken(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(Result.Success(TestData.TokenResponse())); + this.EstateClient.Setup(e => e.GetEstate(It.IsAny(), It.IsAny(), It.IsAny())) - .ReturnsAsync(Result.Success(TestData.GetEstateResponseWithOperator1)); + .ReturnsAsync(TestData.GetEstateResponseWithOperator1); this.EstateClient.Setup(e => e.GetMerchant(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) - .ReturnsAsync(Result.NotFound("Merchant Not Found")); + .ReturnsAsync(TestData.GetMerchantResponseWithOperator1Deleted); - Result result = await this.TransactionValidationService.ValidateReconciliationTransactionX(TestData.EstateId, TestData.MerchantId, - TestData.DeviceIdentifier, CancellationToken.None); + var result = await this.TransactionValidationService.ValidateSaleTransaction(TestData.EstateId, + TestData.MerchantId, + TestData.ContractId, + TestData.ProductId, + TestData.DeviceIdentifier, + TestData.OperatorId, + TestData.TransactionAmount, + CancellationToken.None); result.IsFailed.ShouldBeTrue(); - result.Data.ResponseCode.ShouldBe(TransactionResponseCode.InvalidMerchantId); + result.Data.ResponseCode.ShouldBe(TransactionResponseCode.OperatorNotEnabledForMerchant); } [Fact] - public async Task ValidateReconciliationTransactionX_FailureWhileGettingMerchant_CorrectResponseReturned() + public async Task TransactionValidationService_ValidateSaleTransaction_OperatorNotConfiguredFroMerchant_ResponseIsOperatorNotValidForMerchant() { + this.SecurityServiceClient.Setup(s => s.GetToken(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(Result.Success(TestData.TokenResponse())); + this.EstateClient.Setup(e => e.GetEstate(It.IsAny(), It.IsAny(), It.IsAny())) - .ReturnsAsync(Result.Success()); + .ReturnsAsync(TestData.GetEstateResponseWithOperator1); this.EstateClient.Setup(e => e.GetMerchant(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) - .ReturnsAsync(Result.Failure("Merchant Not Found")); - - Result result = await this.TransactionValidationService.ValidateReconciliationTransactionX(TestData.EstateId, TestData.MerchantId, - TestData.DeviceIdentifier, CancellationToken.None); + .ReturnsAsync(TestData.GetMerchantResponseWithOperator2); + var result = await this.TransactionValidationService.ValidateSaleTransaction(TestData.EstateId, + TestData.MerchantId, + TestData.ContractId, + TestData.ProductId, + TestData.DeviceIdentifier, + TestData.OperatorId, + TestData.TransactionAmount, + CancellationToken.None); result.IsFailed.ShouldBeTrue(); - result.Data.ResponseCode.ShouldBe(TransactionResponseCode.UnknownFailure); + result.Data.ResponseCode.ShouldBe(TransactionResponseCode.OperatorNotValidForMerchant); } + [Fact] - public async Task ValidateReconciliationTransactionX_InvalidDeviceId_CorrectResponseReturned() + public async Task TransactionValidationService_ValidateSaleTransaction_ProductIdNotConfigured_ResponseIsProductNotValidForMerchant() { + this.SecurityServiceClient.Setup(s => s.GetToken(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(Result.Success(TestData.TokenResponse())); + this.EstateClient.Setup(e => e.GetEstate(It.IsAny(), It.IsAny(), It.IsAny())) - .ReturnsAsync(Result.Success(TestData.GetEstateResponseWithOperator1)); + .ReturnsAsync(TestData.GetEstateResponseWithOperator1); this.EstateClient.Setup(e => e.GetMerchant(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) - .ReturnsAsync(Result.Success(TestData.GetMerchantResponseWithOperator1)); + .ReturnsAsync(TestData.GetMerchantResponseWithOperator1); + this.EstateClient.Setup(e => e.GetMerchantContracts(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) + .ReturnsAsync(TestData.MerchantContractResponses); - Result result = await this.TransactionValidationService.ValidateReconciliationTransactionX(TestData.EstateId, TestData.MerchantId, - TestData.DeviceIdentifier1, CancellationToken.None); + 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, + TestData.ProductId1, + TestData.DeviceIdentifier, + TestData.OperatorId, + TestData.TransactionAmount, + CancellationToken.None); result.IsFailed.ShouldBeTrue(); - result.Data.ResponseCode.ShouldBe(TransactionResponseCode.InvalidDeviceIdentifier); + result.Data.ResponseCode.ShouldBe(TransactionResponseCode.ProductNotValidForMerchant); } [Fact] - public async Task ValidateReconciliationTransactionX_MerchantHasNoDevices_CorrectResponseReturned() + public async Task TransactionValidationService_ValidateSaleTransaction_SuccessfulSale() { + this.SecurityServiceClient.Setup(s => s.GetToken(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(Result.Success(TestData.TokenResponse())); + this.EstateClient.Setup(e => e.GetEstate(It.IsAny(), It.IsAny(), It.IsAny())) - .ReturnsAsync(Result.Success(TestData.GetEstateResponseWithOperator1)); + .ReturnsAsync(TestData.GetEstateResponseWithOperator1); this.EstateClient.Setup(e => e.GetMerchant(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) - .ReturnsAsync(Result.Success(TestData.GetMerchantResponseWithNoDevices)); + .ReturnsAsync(TestData.GetMerchantResponseWithOperator1); + this.EstateClient.Setup(e => e.GetMerchantContracts(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) + .ReturnsAsync(TestData.MerchantContractResponses); - Result result = await this.TransactionValidationService.ValidateReconciliationTransactionX(TestData.EstateId, TestData.MerchantId, - TestData.DeviceIdentifier1, CancellationToken.None); + this.EventStoreContext.Setup(e => e.GetPartitionStateFromProjection(It.IsAny(), It.IsAny(), It.IsAny())) + .ReturnsAsync(JsonConvert.SerializeObject(TestData.MerchantBalanceProjectionState)); - result.IsFailed.ShouldBeTrue(); - result.Data.ResponseCode.ShouldBe(TransactionResponseCode.NoValidDevices); + var result = await this.TransactionValidationService.ValidateSaleTransaction(TestData.EstateId, + TestData.MerchantId, + TestData.ContractId, + TestData.ProductId, + TestData.DeviceIdentifier, + TestData.OperatorId, + TestData.TransactionAmount, + CancellationToken.None); + result.IsSuccess.ShouldBeTrue(); + result.Data.ResponseCode.ShouldBe(TransactionResponseCode.Success); } [Fact] - public async Task ValidateReconciliationTransactionX_MerchantHasNullDevices_CorrectResponseReturned() + public async Task TransactionValidationService_ValidateSaleTransaction_FailedGettingMerchantBalance_ResponseIsInvalidMerchantId() { + this.SecurityServiceClient.Setup(s => s.GetToken(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(Result.Success(TestData.TokenResponse())); + this.EstateClient.Setup(e => e.GetEstate(It.IsAny(), It.IsAny(), It.IsAny())) - .ReturnsAsync(Result.Success(TestData.GetEstateResponseWithOperator1)); - this.EstateClient.Setup(e => e.GetMerchant(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) - .ReturnsAsync(Result.Success(TestData.GetMerchantResponseWithNullDevices)); + .ReturnsAsync(TestData.GetEstateResponseWithOperator1); + this.EstateClient.SetupSequence(e => e.GetMerchant(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(TestData.GetMerchantResponseWithOperator1) + .ReturnsAsync(Result.Success(TestData.GetMerchantResponseWithOperator1)); + + this.EventStoreContext.Setup(e => e.GetPartitionStateFromProjection(It.IsAny(), It.IsAny(), It.IsAny())) + .ReturnsAsync(Result.Failure()); - Result result = await this.TransactionValidationService.ValidateReconciliationTransactionX(TestData.EstateId, TestData.MerchantId, - TestData.DeviceIdentifier1, CancellationToken.None); + var result = await this.TransactionValidationService.ValidateSaleTransaction(TestData.EstateId, + TestData.MerchantId, + TestData.ContractId, + TestData.ProductId, + TestData.DeviceIdentifier, + TestData.OperatorId, + TestData.TransactionAmount, + CancellationToken.None); result.IsFailed.ShouldBeTrue(); - result.Data.ResponseCode.ShouldBe(TransactionResponseCode.NoValidDevices); + result.Data.ResponseCode.ShouldBe(TransactionResponseCode.UnknownFailure); } } diff --git a/TransactionProcessor.BusinessLogic.Tests/Services/VoucherDomainServiceTests.cs b/TransactionProcessor.BusinessLogic.Tests/Services/VoucherDomainServiceTests.cs index a593be8b..8256ca11 100644 --- a/TransactionProcessor.BusinessLogic.Tests/Services/VoucherDomainServiceTests.cs +++ b/TransactionProcessor.BusinessLogic.Tests/Services/VoucherDomainServiceTests.cs @@ -117,7 +117,8 @@ public async Task VoucherDomainService_IssueVoucher_InvalidEstate_ErrorThrown() voucherAggregateRepository.Setup(v => v.GetLatestVersion(It.IsAny(), It.IsAny())).ReturnsAsync(new VoucherAggregate()); securityServiceClient.Setup(s => s.GetToken(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(Result.Success(TestData.TokenResponse())); estateClient.Setup(e => e.GetEstate(It.IsAny(), It.IsAny(), It.IsAny())) - .ThrowsAsync(new Exception("Exception", new KeyNotFoundException("Invalid Estate"))); + //.ThrowsAsync(new Exception("Exception", new KeyNotFoundException("Invalid Estate"))); + .ReturnsAsync(Result.Failure()); EstateManagementGenericContext context = await this.GetContext(Guid.NewGuid().ToString("N")); @@ -232,7 +233,8 @@ public async Task VoucherDomainService_RedeemVoucher_InvalidEstate_ErrorThrown() .ReturnsAsync(Result.Success(TestData.GetVoucherAggregateWithRecipientMobile())); securityServiceClient.Setup(s => s.GetToken(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(Result.Success(TestData.TokenResponse())); estateClient.Setup(e => e.GetEstate(It.IsAny(), It.IsAny(), It.IsAny())) - .ThrowsAsync(new Exception("Exception", new KeyNotFoundException("Invalid Estate"))); + //.ThrowsAsync(new Exception("Exception", new KeyNotFoundException("Invalid Estate"))); + .ReturnsAsync(Result.Failure()); EstateManagementGenericContext context = await this.GetContext(Guid.NewGuid().ToString("N")); context.Vouchers.Add(new EstateManagement.Database.Entities.Voucher { diff --git a/TransactionProcessor.BusinessLogic/Common/MemoryCacheWrapper.cs b/TransactionProcessor.BusinessLogic/Common/MemoryCacheWrapper.cs index 93a21dc3..93fb5612 100644 --- a/TransactionProcessor.BusinessLogic/Common/MemoryCacheWrapper.cs +++ b/TransactionProcessor.BusinessLogic/Common/MemoryCacheWrapper.cs @@ -1,6 +1,7 @@ using Microsoft.Extensions.Caching.Memory; using System; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Text; using System.Threading.Tasks; @@ -13,6 +14,7 @@ public interface IMemoryCacheWrapper void Set(Object key, T cache, MemoryCacheEntryOptions entryOptions); } + [ExcludeFromCodeCoverage] public class MemoryCacheWrapper : IMemoryCacheWrapper { private readonly IMemoryCache MemoryCache; diff --git a/TransactionProcessor.BusinessLogic/EventHandling/TransactionDomainEventHandler.cs b/TransactionProcessor.BusinessLogic/EventHandling/TransactionDomainEventHandler.cs index bf976e7a..8d578a92 100644 --- a/TransactionProcessor.BusinessLogic/EventHandling/TransactionDomainEventHandler.cs +++ b/TransactionProcessor.BusinessLogic/EventHandling/TransactionDomainEventHandler.cs @@ -170,7 +170,7 @@ private async Task HandleSpecificDomainEvent(MerchantFeeSettledEvent dom private async Task HandleSpecificDomainEvent(CustomerEmailReceiptRequestedEvent domainEvent, CancellationToken cancellationToken) { - return Result.Success(); + return Result.Failure("Not Implemented"); this.TokenResponse = await Helpers.GetToken(this.TokenResponse, this.SecurityServiceClient, cancellationToken); diff --git a/TransactionProcessor.BusinessLogic/Manager/FeeCalculationManager.cs b/TransactionProcessor.BusinessLogic/Manager/FeeCalculationManager.cs index 808cfce7..161260ce 100644 --- a/TransactionProcessor.BusinessLogic/Manager/FeeCalculationManager.cs +++ b/TransactionProcessor.BusinessLogic/Manager/FeeCalculationManager.cs @@ -41,8 +41,7 @@ public List CalculateFees(List feeList FeeCalculatedDateTime = calculationDateTime == DateTime.MinValue ? DateTime.Now : calculationDateTime }); } - - if (transactionFeeToCalculate.CalculationType == CalculationType.Fixed) + else if (transactionFeeToCalculate.CalculationType == CalculationType.Fixed) { // fixed value fee calculatedFees.Add(new CalculatedFee diff --git a/TransactionProcessor.BusinessLogic/OperatorInterfaces/PataPawaPostPay/PataPawaPostPayProxy.cs b/TransactionProcessor.BusinessLogic/OperatorInterfaces/PataPawaPostPay/PataPawaPostPayProxy.cs index 55f17e7f..dd3ca6b1 100644 --- a/TransactionProcessor.BusinessLogic/OperatorInterfaces/PataPawaPostPay/PataPawaPostPayProxy.cs +++ b/TransactionProcessor.BusinessLogic/OperatorInterfaces/PataPawaPostPay/PataPawaPostPayProxy.cs @@ -1,4 +1,5 @@ -using SimpleResults; +using System.Diagnostics.CodeAnalysis; +using SimpleResults; namespace TransactionProcessor.BusinessLogic.OperatorInterfaces.PataPawaPostPay { @@ -75,6 +76,7 @@ public async Task> ProcessLogonMessage(String accessTok new MemoryCacheEntryOptions().SetPriority(CacheItemPriority.NeverRemove).SetSlidingExpiration(TimeSpan.FromHours(1)) .RegisterPostEvictionCallback(PostEvictionCallback); + [ExcludeFromCodeCoverage] private void PostEvictionCallback(Object key, Object value, EvictionReason reason, diff --git a/TransactionProcessor.BusinessLogic/Requests/FloatActivityCommands.cs b/TransactionProcessor.BusinessLogic/Requests/FloatActivityCommands.cs index 5c2ac6b8..f33cc71c 100644 --- a/TransactionProcessor.BusinessLogic/Requests/FloatActivityCommands.cs +++ b/TransactionProcessor.BusinessLogic/Requests/FloatActivityCommands.cs @@ -1,9 +1,11 @@ using System; +using System.Diagnostics.CodeAnalysis; using MediatR; using SimpleResults; namespace TransactionProcessor.BusinessLogic.Requests; +[ExcludeFromCodeCoverage] public record FloatActivityCommands { public record RecordCreditPurchaseCommand(Guid EstateId, Guid FloatId, DateTime CreditPurchasedDateTime, Decimal Amount) : IRequest; diff --git a/TransactionProcessor.BusinessLogic/Requests/FloatCommands.cs b/TransactionProcessor.BusinessLogic/Requests/FloatCommands.cs index d32e12c0..8e165143 100644 --- a/TransactionProcessor.BusinessLogic/Requests/FloatCommands.cs +++ b/TransactionProcessor.BusinessLogic/Requests/FloatCommands.cs @@ -1,9 +1,11 @@ using System; +using System.Diagnostics.CodeAnalysis; using MediatR; using SimpleResults; namespace TransactionProcessor.BusinessLogic.Requests; +[ExcludeFromCodeCoverage] public record FloatCommands { public record CreateFloatForContractProductCommand(Guid EstateId, Guid ContractId, diff --git a/TransactionProcessor.BusinessLogic/Requests/MerchantQueries.cs b/TransactionProcessor.BusinessLogic/Requests/MerchantQueries.cs index f48d6bad..30f1cd8b 100644 --- a/TransactionProcessor.BusinessLogic/Requests/MerchantQueries.cs +++ b/TransactionProcessor.BusinessLogic/Requests/MerchantQueries.cs @@ -1,12 +1,13 @@ using System; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using MediatR; using SimpleResults; using TransactionProcessor.ProjectionEngine.Models; using TransactionProcessor.ProjectionEngine.State; namespace TransactionProcessor.BusinessLogic.Requests; - +[ExcludeFromCodeCoverage] public record MerchantQueries { public record GetMerchantBalanceQuery(Guid EstateId, Guid MerchantId) : IRequest>; diff --git a/TransactionProcessor.BusinessLogic/Requests/SettlementCommands.cs b/TransactionProcessor.BusinessLogic/Requests/SettlementCommands.cs index 88359a4e..347f1146 100644 --- a/TransactionProcessor.BusinessLogic/Requests/SettlementCommands.cs +++ b/TransactionProcessor.BusinessLogic/Requests/SettlementCommands.cs @@ -1,10 +1,11 @@ using System; +using System.Diagnostics.CodeAnalysis; using MediatR; using SimpleResults; using TransactionProcessor.Models; namespace TransactionProcessor.BusinessLogic.Requests; - +[ExcludeFromCodeCoverage] public record SettlementCommands { public record ProcessSettlementCommand(DateTime SettlementDate, Guid MerchantId, Guid EstateId) : IRequest>; diff --git a/TransactionProcessor.BusinessLogic/Requests/SettlementQueries.cs b/TransactionProcessor.BusinessLogic/Requests/SettlementQueries.cs index 93015582..ecfa8ecb 100644 --- a/TransactionProcessor.BusinessLogic/Requests/SettlementQueries.cs +++ b/TransactionProcessor.BusinessLogic/Requests/SettlementQueries.cs @@ -1,10 +1,11 @@ using System; +using System.Diagnostics.CodeAnalysis; using MediatR; using SimpleResults; using TransactionProcessor.SettlementAggregates; namespace TransactionProcessor.BusinessLogic.Requests; - +[ExcludeFromCodeCoverage] public record SettlementQueries { public record GetPendingSettlementQuery(DateTime SettlementDate, Guid MerchantId, Guid EstateId) : IRequest>; diff --git a/TransactionProcessor.BusinessLogic/Requests/TransactionCommands.cs b/TransactionProcessor.BusinessLogic/Requests/TransactionCommands.cs index 84dc4c9d..18a74383 100644 --- a/TransactionProcessor.BusinessLogic/Requests/TransactionCommands.cs +++ b/TransactionProcessor.BusinessLogic/Requests/TransactionCommands.cs @@ -1,11 +1,13 @@ using System; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using MediatR; using SimpleResults; using TransactionProcessor.Models; namespace TransactionProcessor.BusinessLogic.Requests; +[ExcludeFromCodeCoverage] public record TransactionCommands { public record ProcessLogonTransactionCommand(Guid TransactionId, Guid EstateId, diff --git a/TransactionProcessor.BusinessLogic/Requests/VoucherCommands.cs b/TransactionProcessor.BusinessLogic/Requests/VoucherCommands.cs index b89a95c2..c60bd198 100644 --- a/TransactionProcessor.BusinessLogic/Requests/VoucherCommands.cs +++ b/TransactionProcessor.BusinessLogic/Requests/VoucherCommands.cs @@ -1,10 +1,12 @@ using System; +using System.Diagnostics.CodeAnalysis; using MediatR; using SimpleResults; using TransactionProcessor.Models; namespace TransactionProcessor.BusinessLogic.Requests; +[ExcludeFromCodeCoverage] public record VoucherCommands { public record IssueVoucherCommand(Guid VoucherId, Guid OperatorId, @@ -17,9 +19,4 @@ public record IssueVoucherCommand(Guid VoucherId, public record RedeemVoucherCommand(Guid EstateId, String VoucherCode, DateTime RedeemedDateTime) : IRequest>; -} - -public record VoucherQueries { - public record GetVoucherByVoucherCodeQuery(Guid EstateId,String VoucherCode) : IRequest>; - public record GetVoucherByTransactionIdQuery(Guid EstateId, Guid TransactionId) : IRequest>; } \ No newline at end of file diff --git a/TransactionProcessor.BusinessLogic/Requests/VoucherQueries.cs b/TransactionProcessor.BusinessLogic/Requests/VoucherQueries.cs new file mode 100644 index 00000000..27542c80 --- /dev/null +++ b/TransactionProcessor.BusinessLogic/Requests/VoucherQueries.cs @@ -0,0 +1,12 @@ +using System; +using System.Diagnostics.CodeAnalysis; +using MediatR; +using SimpleResults; + +namespace TransactionProcessor.BusinessLogic.Requests; + +[ExcludeFromCodeCoverage] +public record VoucherQueries { + public record GetVoucherByVoucherCodeQuery(Guid EstateId,String VoucherCode) : IRequest>; + public record GetVoucherByTransactionIdQuery(Guid EstateId, Guid TransactionId) : IRequest>; +} \ No newline at end of file diff --git a/TransactionProcessor.BusinessLogic/Services/ITransactionValidationService.cs b/TransactionProcessor.BusinessLogic/Services/ITransactionValidationService.cs index 0081edcf..19a1f621 100644 --- a/TransactionProcessor.BusinessLogic/Services/ITransactionValidationService.cs +++ b/TransactionProcessor.BusinessLogic/Services/ITransactionValidationService.cs @@ -1,4 +1,5 @@ -using SimpleResults; +using System.Diagnostics.CodeAnalysis; +using SimpleResults; namespace TransactionProcessor.BusinessLogic.Services; @@ -8,37 +9,17 @@ namespace TransactionProcessor.BusinessLogic.Services; public interface ITransactionValidationService{ #region Methods - - Task<(String responseMessage, TransactionResponseCode responseCode)> ValidateLogonTransaction(Guid estateId, - Guid merchantId, - String deviceIdentifier, - CancellationToken cancellationToken); - - Task> ValidateLogonTransactionX(Guid estateId, + + Task> ValidateLogonTransaction(Guid estateId, Guid merchantId, String deviceIdentifier, CancellationToken cancellationToken); - - Task<(String responseMessage, TransactionResponseCode responseCode)> ValidateReconciliationTransaction(Guid estateId, - Guid merchantId, - String deviceIdentifier, - CancellationToken cancellationToken); - - Task> ValidateReconciliationTransactionX(Guid estateId, + Task> ValidateReconciliationTransaction(Guid estateId, Guid merchantId, String deviceIdentifier, CancellationToken cancellationToken); - Task<(String responseMessage, TransactionResponseCode responseCode)> ValidateSaleTransaction(Guid estateId, - Guid merchantId, - Guid contractId, - Guid productId, - String deviceIdentifier, - Guid operatorId, - Decimal? transactionAmount, - CancellationToken cancellationToken); - - Task> ValidateSaleTransactionX(Guid estateId, + Task> ValidateSaleTransaction(Guid estateId, Guid merchantId, Guid contractId, Guid productId, @@ -50,4 +31,5 @@ Task> ValidateSaleTransactionX(Guid estateId #endregion } +[ExcludeFromCodeCoverage] public record TransactionValidationResult(TransactionResponseCode ResponseCode, String ResponseMessage); \ No newline at end of file diff --git a/TransactionProcessor.BusinessLogic/Services/SettlementDomainService.cs b/TransactionProcessor.BusinessLogic/Services/SettlementDomainService.cs index 9f1a5c5a..1531f1ef 100644 --- a/TransactionProcessor.BusinessLogic/Services/SettlementDomainService.cs +++ b/TransactionProcessor.BusinessLogic/Services/SettlementDomainService.cs @@ -206,14 +206,10 @@ public async Task AddSettledFeeToSettlement(SettlementCommands.AddSettle Guid aggregateId = Helpers.CalculateSettlementAggregateId(command.SettledDate.Date, command.MerchantId, command.EstateId); Result result = await ApplySettlementUpdates(async (SettlementAggregate settlementAggregate) => { - - if (settlementAggregate == null) { - Logger.LogInformation("Settlement aggregate is null"); - } - + var getMerchantResult = await this.EstateClient.GetMerchant(this.TokenResponse.AccessToken, command.EstateId, command.MerchantId, cancellationToken); if (getMerchantResult.IsFailed) { - Logger.LogInformation("getMerchantResult.IsFailed"); + return ResultHelpers.CreateFailure(getMerchantResult); } var merchant = getMerchantResult.Data; diff --git a/TransactionProcessor.BusinessLogic/Services/TransactionDomainService.cs b/TransactionProcessor.BusinessLogic/Services/TransactionDomainService.cs index 974675f7..a5e3e99e 100644 --- a/TransactionProcessor.BusinessLogic/Services/TransactionDomainService.cs +++ b/TransactionProcessor.BusinessLogic/Services/TransactionDomainService.cs @@ -193,9 +193,9 @@ public async Task> ProcessLogonTransacti null); // Logon transaction has no amount Result validationResult = - await this.TransactionValidationService.ValidateLogonTransactionX(command.EstateId, command.MerchantId, command.DeviceIdentifier, cancellationToken); + await this.TransactionValidationService.ValidateLogonTransaction(command.EstateId, command.MerchantId, command.DeviceIdentifier, cancellationToken); - if (validationResult.IsSuccess) { + if (validationResult.IsSuccess && (validationResult.Data.ResponseCode == TransactionResponseCode.Success || validationResult.Data.ResponseCode == TransactionResponseCode.SuccessNeedToAddDevice)) { if (validationResult.Data.ResponseCode == TransactionResponseCode.SuccessNeedToAddDevice) { await this.AddDeviceToMerchant(command.EstateId, command.MerchantId, command.DeviceIdentifier, cancellationToken); } @@ -234,13 +234,13 @@ public async Task> ProcessRecon Result result = await ApplyUpdates( async (ReconciliationAggregate reconciliationAggregate) => { Result validationResult = - await this.TransactionValidationService.ValidateReconciliationTransactionX(command.EstateId, command.MerchantId, command.DeviceIdentifier, cancellationToken); + await this.TransactionValidationService.ValidateReconciliationTransaction(command.EstateId, command.MerchantId, command.DeviceIdentifier, cancellationToken); reconciliationAggregate.StartReconciliation(command.TransactionDateTime, command.EstateId, command.MerchantId); reconciliationAggregate.RecordOverallTotals(command.TransactionCount, command.TransactionValue); - if (validationResult.IsSuccess) + if (validationResult.IsSuccess && validationResult.Data.ResponseCode == TransactionResponseCode.Success) { // Record the successful validation reconciliationAggregate.Authorise(((Int32)validationResult.Data.ResponseCode).ToString().PadLeft(4, '0'), validationResult.Data.ResponseMessage); @@ -282,7 +282,7 @@ public async Task> ProcessSaleTransaction command.AdditionalTransactionMetadata.ExtractFieldFromMetadata("Amount"); Result validationResult = - await this.TransactionValidationService.ValidateSaleTransactionX(command.EstateId, command.MerchantId, + await this.TransactionValidationService.ValidateSaleTransaction(command.EstateId, command.MerchantId, command.ContractId, command.ProductId, command.DeviceIdentifier, command.OperatorId, transactionAmount, cancellationToken); Logger.LogInformation($"Validation response is [{JsonConvert.SerializeObject(validationResult)}]"); diff --git a/TransactionProcessor.BusinessLogic/Services/TransactionValidationService.cs b/TransactionProcessor.BusinessLogic/Services/TransactionValidationService.cs index 7fbb5295..5242974d 100644 --- a/TransactionProcessor.BusinessLogic/Services/TransactionValidationService.cs +++ b/TransactionProcessor.BusinessLogic/Services/TransactionValidationService.cs @@ -61,35 +61,36 @@ public TransactionValidationService(IEstateClient estateClient, #region Methods - public async Task<(String responseMessage, TransactionResponseCode responseCode)> ValidateLogonTransaction(Guid estateId, - Guid merchantId, - String deviceIdentifier, - CancellationToken cancellationToken){ - try{ - (EstateResponse estate, EstateManagement.DataTransferObjects.Responses.Merchant.MerchantResponse merchant) validateTransactionResponse = await this.ValidateMerchant(estateId, merchantId, cancellationToken); - EstateManagement.DataTransferObjects.Responses.Merchant.MerchantResponse merchant = validateTransactionResponse.merchant; - - // Device Validation - if (merchant.Devices == null || merchant.Devices.Any() == false){ - return ("SUCCESS", TransactionResponseCode.SuccessNeedToAddDevice); - } - - // Validate the device - KeyValuePair device = merchant.Devices.SingleOrDefault(d => d.Value == deviceIdentifier); - - if (device.Key == Guid.Empty){ - // Device not found,throw error - throw new TransactionValidationException($"Device Identifier {deviceIdentifier} not valid for Merchant {merchant.MerchantName}", - TransactionResponseCode.InvalidDeviceIdentifier); - } - - // If we get here everything is good - return ("SUCCESS", TransactionResponseCode.Success); - } - catch(TransactionValidationException tvex){ - return (tvex.Message, tvex.ResponseCode); - } - } + //[Obsolete("ValidateLogonTransaction is deprecated, please use ValidateLogonTransactionX instead.")] + //public async Task<(String responseMessage, TransactionResponseCode responseCode)> ValidateLogonTransaction(Guid estateId, + // Guid merchantId, + // String deviceIdentifier, + // CancellationToken cancellationToken){ + // try{ + // (EstateResponse estate, EstateManagement.DataTransferObjects.Responses.Merchant.MerchantResponse merchant) validateTransactionResponse = await this.ValidateMerchant(estateId, merchantId, cancellationToken); + // EstateManagement.DataTransferObjects.Responses.Merchant.MerchantResponse merchant = validateTransactionResponse.merchant; + + // // Device Validation + // if (merchant.Devices == null || merchant.Devices.Any() == false){ + // return ("SUCCESS", TransactionResponseCode.SuccessNeedToAddDevice); + // } + + // // Validate the device + // KeyValuePair device = merchant.Devices.SingleOrDefault(d => d.Value == deviceIdentifier); + + // if (device.Key == Guid.Empty){ + // // Device not found,throw error + // throw new TransactionValidationException($"Device Identifier {deviceIdentifier} not valid for Merchant {merchant.MerchantName}", + // TransactionResponseCode.InvalidDeviceIdentifier); + // } + + // // If we get here everything is good + // return ("SUCCESS", TransactionResponseCode.Success); + // } + // catch(TransactionValidationException tvex){ + // return (tvex.Message, tvex.ResponseCode); + // } + //} internal static Result CreateFailedResult(T resultData) { return new Result @@ -99,7 +100,7 @@ internal static Result CreateFailedResult(T resultData) { }; } - public async Task> ValidateLogonTransactionX(Guid estateId, + public async Task> ValidateLogonTransaction(Guid estateId, Guid merchantId, String deviceIdentifier, CancellationToken cancellationToken) { @@ -145,7 +146,7 @@ public async Task> ValidateLogonTransactionX return Result.Success(new TransactionValidationResult(TransactionResponseCode.Success, "SUCCESS")); } - public async Task> ValidateReconciliationTransactionX(Guid estateId, + public async Task> ValidateReconciliationTransaction(Guid estateId, Guid merchantId, String deviceIdentifier, CancellationToken cancellationToken) @@ -198,172 +199,7 @@ public async Task> ValidateReconciliationTra return Result.Success(new TransactionValidationResult(TransactionResponseCode.Success, "SUCCESS")); } - public async Task<(String responseMessage, TransactionResponseCode responseCode)> ValidateReconciliationTransaction(Guid estateId, - Guid merchantId, - String deviceIdentifier, - CancellationToken cancellationToken){ - try{ - (EstateResponse estate, EstateManagement.DataTransferObjects.Responses.Merchant.MerchantResponse merchant) validateTransactionResponse = await this.ValidateMerchant(estateId, merchantId, cancellationToken); - EstateManagement.DataTransferObjects.Responses.Merchant.MerchantResponse merchant = validateTransactionResponse.merchant; - - // Device Validation - if (merchant.Devices == null || merchant.Devices.Any() == false){ - throw new TransactionValidationException($"Merchant {merchant.MerchantName} has no valid Devices for this transaction.", - TransactionResponseCode.NoValidDevices); - } - - // Validate the device - KeyValuePair device = merchant.Devices.SingleOrDefault(d => d.Value == deviceIdentifier); - - if (device.Key == Guid.Empty){ - // Device not found,throw error - throw new TransactionValidationException($"Device Identifier {deviceIdentifier} not valid for Merchant {merchant.MerchantName}", - TransactionResponseCode.InvalidDeviceIdentifier); - } - - // If we get here everything is good - return ("SUCCESS", TransactionResponseCode.Success); - } - catch(TransactionValidationException tvex){ - return (tvex.Message, tvex.ResponseCode); - } - } - - public async Task<(String responseMessage, TransactionResponseCode responseCode)> ValidateSaleTransaction(Guid estateId, - Guid merchantId, - Guid contractId, - Guid productId, - String deviceIdentifier, - Guid operatorId, - Decimal? transactionAmount, - CancellationToken cancellationToken){ - try{ - (EstateResponse estate, EstateManagement.DataTransferObjects.Responses.Merchant.MerchantResponse merchant) validateTransactionResponse = await this.ValidateMerchant(estateId, merchantId, cancellationToken); - EstateResponse estate = validateTransactionResponse.estate; - EstateManagement.DataTransferObjects.Responses.Merchant.MerchantResponse merchant = validateTransactionResponse.merchant; - - // Operator Validation (Estate) - if (estate.Operators == null || estate.Operators.Any() == false){ - throw new TransactionValidationException($"Estate {estate.EstateName} has no operators defined", TransactionResponseCode.NoEstateOperators); - } - - // Operators have been configured for the estate - EstateOperatorResponse estateOperatorRecord = estate.Operators.SingleOrDefault(o => o.OperatorId == operatorId); - if (estateOperatorRecord == null){ - throw new TransactionValidationException($"Operator {operatorId} not configured for Estate [{estate.EstateName}]", - TransactionResponseCode.OperatorNotValidForEstate); - } - - // Check the operator is enabled and not deleted - if (estateOperatorRecord.IsDeleted){ - throw new TransactionValidationException($"Operator {operatorId} not enabled for Estate [{estate.EstateName}]", - TransactionResponseCode.OperatorNotEnabledForEstate); - } - - // Device Validation - if (merchant.Devices == null || merchant.Devices.Any() == false){ - throw new TransactionValidationException($"Merchant {merchant.MerchantName} has no valid Devices for this transaction.", - TransactionResponseCode.NoValidDevices); - } - - // Validate the device - KeyValuePair device = merchant.Devices.SingleOrDefault(d => d.Value == deviceIdentifier); - - if (device.Key == Guid.Empty){ - // Device not found,throw error - throw new TransactionValidationException($"Device Identifier {deviceIdentifier} not valid for Merchant {merchant.MerchantName}", - TransactionResponseCode.InvalidDeviceIdentifier); - } - - // Operator Validation (Merchant) - if (merchant.Operators == null || merchant.Operators.Any() == false){ - throw new TransactionValidationException($"Merchant {merchant.MerchantName} has no operators defined", TransactionResponseCode.NoMerchantOperators); - } - - { - // Operators have been configured for the estate - EstateManagement.DataTransferObjects.Responses.Merchant.MerchantOperatorResponse merchantOperatorRecord = merchant.Operators.SingleOrDefault(o => o.OperatorId == operatorId); - if (merchantOperatorRecord == null){ - throw new TransactionValidationException($"Operator {operatorId} not configured for Merchant [{merchant.MerchantName}]", - TransactionResponseCode.OperatorNotValidForMerchant); - } - - // Check the operator is enabled and not deleted - if (merchantOperatorRecord.IsDeleted) - { - throw new TransactionValidationException($"Operator {operatorId} not enabled for Merchant [{merchant.MerchantName}]", - TransactionResponseCode.OperatorNotEnabledForMerchant); - } - } - - // Contract and Product Validation - if (contractId == Guid.Empty){ - throw new TransactionValidationException($"Contract Id [{contractId}] must be set for a sale transaction", - TransactionResponseCode.InvalidContractIdValue); - } - - List merchantContracts = null; - try{ - merchantContracts = await this.GetMerchantContracts(estateId, merchantId, cancellationToken); - } - catch(Exception ex) when(ex.InnerException != null && ex.InnerException.GetType() == typeof(KeyNotFoundException)){ - throw new TransactionValidationException($"Merchant Id [{merchantId}] is not a valid merchant for estate [{estate.EstateName}]", - TransactionResponseCode.InvalidMerchantId); - } - catch(Exception e){ - throw new TransactionValidationException($"Exception occurred while getting Merchant Id [{merchantId}] Contracts Exception [{e.Message}]", TransactionResponseCode.UnknownFailure); - } - - if (merchantContracts == null || merchantContracts.Any() == false){ - throw new TransactionValidationException($"Merchant {merchant.MerchantName} has no contracts configured", TransactionResponseCode.MerchantHasNoContractsConfigured); - } - - // Check the contract and product id against the merchant - EstateManagement.DataTransferObjects.Responses.Merchant.MerchantContractResponse contract = merchantContracts.SingleOrDefault(c => c.ContractId == contractId); - - if (contract == null){ - throw new TransactionValidationException($"Contract Id [{contractId}] not valid for Merchant [{merchant.MerchantName}]", - TransactionResponseCode.ContractNotValidForMerchant); - } - - if (productId == Guid.Empty){ - throw new TransactionValidationException($"Product Id [{productId}] must be set for a sale transaction", - TransactionResponseCode.InvalidProductIdValue); - } - - Guid contractProduct = contract.ContractProducts.SingleOrDefault(p => p == productId); - - if (contractProduct == Guid.Empty){ - throw new TransactionValidationException($"Product Id [{productId}] not valid for Merchant [{merchant.MerchantName}]", - TransactionResponseCode.ProductNotValidForMerchant); - } - - // Check the amount - if (transactionAmount.HasValue){ - if (transactionAmount <= 0){ - throw new TransactionValidationException("Transaction Amount must be greater than 0", TransactionResponseCode.InvalidSaleTransactionAmount); - } - - String state = await this.EventStoreContext.GetPartitionStateFromProjection("MerchantBalanceProjection", $"MerchantBalance-{merchantId:N}", cancellationToken); - MerchantBalanceProjectionState1 projectionState = JsonConvert.DeserializeObject(state); - - // Check the merchant has enough balance to perform the sale - if (projectionState.merchant.balance < transactionAmount){ - throw new - TransactionValidationException($"Merchant [{merchant.MerchantName}] does not have enough credit available [{projectionState.merchant.balance:0.00}] to perform transaction amount [{transactionAmount}]", - TransactionResponseCode.MerchantDoesNotHaveEnoughCredit); - } - } - - // If we get here everything is good - return ("SUCCESS", TransactionResponseCode.Success); - } - catch(TransactionValidationException tvex){ - return (tvex.Message, tvex.ResponseCode); - } - } - - public async Task> ValidateSaleTransactionX(Guid estateId, + public async Task> ValidateSaleTransaction(Guid estateId, Guid merchantId, Guid contractId, Guid productId, @@ -552,33 +388,6 @@ private async Task> GetEstate(Guid estateId, return ResultHelpers.CreateFailure(result); return result.Data.Contracts; } - - // TODO: refactor thit to a result as well - private async Task<(EstateResponse estate, EstateManagement.DataTransferObjects.Responses.Merchant.MerchantResponse merchant)> ValidateMerchant(Guid estateId, - Guid merchantId, - CancellationToken cancellationToken){ - - // Validate the Estate Record is a valid estate - var getEstateResult = await this.GetEstate(estateId, cancellationToken); - if (getEstateResult.IsFailed && getEstateResult.Status == ResultStatus.NotFound) - throw new TransactionValidationException(getEstateResult.Message, TransactionResponseCode.InvalidEstateId); - if (getEstateResult.IsFailed && getEstateResult.Status != ResultStatus.NotFound) { - throw new TransactionValidationException(getEstateResult.Message, TransactionResponseCode.UnknownFailure); - } - - // get the merchant record and validate the device - var getMerchantResult = await this.GetMerchant(estateId, merchantId, cancellationToken); - // TODO: shud we use the result message here... - if (getMerchantResult.IsFailed && getMerchantResult.Status == ResultStatus.NotFound) - throw new TransactionValidationException($"Merchant Id [{merchantId}] is not a valid merchant for estate [{getEstateResult.Data.EstateName}]", - TransactionResponseCode.InvalidMerchantId); - if (getMerchantResult.IsFailed && getMerchantResult.Status != ResultStatus.NotFound) - { - throw new TransactionValidationException(getMerchantResult.Message, TransactionResponseCode.UnknownFailure); - } - - return (getEstateResult.Data, getMerchantResult.Data); - } #endregion } \ No newline at end of file diff --git a/TransactionProcessor.Float.DomainEvents/FloatActivityAggregateDomainEvents.cs b/TransactionProcessor.Float.DomainEvents/FloatActivityAggregateDomainEvents.cs index 1f0971b3..f8f12bae 100644 --- a/TransactionProcessor.Float.DomainEvents/FloatActivityAggregateDomainEvents.cs +++ b/TransactionProcessor.Float.DomainEvents/FloatActivityAggregateDomainEvents.cs @@ -1,17 +1,20 @@ using Shared.DomainDrivenDesign.EventSourcing; using System; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Text; using System.Threading.Tasks; namespace TransactionProcessor.Float.DomainEvents { + [ExcludeFromCodeCoverage] public record FloatAggregateCreditedEvent(Guid FloatId, Guid EstateId, DateTime ActivityDateTime, Decimal Amount) : DomainEvent(FloatId, Guid.NewGuid()); + [ExcludeFromCodeCoverage] public record FloatAggregateDebitedEvent(Guid FloatId, Guid EstateId, DateTime ActivityDateTime, diff --git a/TransactionProcessor.FloatAggregate.Tests/FloatActivityAggregateTests.cs b/TransactionProcessor.FloatAggregate.Tests/FloatActivityAggregateTests.cs new file mode 100644 index 00000000..dc9f6317 --- /dev/null +++ b/TransactionProcessor.FloatAggregate.Tests/FloatActivityAggregateTests.cs @@ -0,0 +1,28 @@ +using Shouldly; +using TransactionProcessor.Testing; +using Xunit; + +namespace TransactionProcessor.FloatAggregate.Tests; + +public class FloatActivityAggregateTests { + [Fact] + public void FloatActivityAggregate_CanBeCreated_IsCreated() + { + FloatActivityAggregate aggregate = FloatActivityAggregate.Create(TestData.FloatAggregateId); + + aggregate.AggregateId.ShouldBe(TestData.FloatAggregateId); + } + + [Fact] + public void FloatActivityAggregate_RecordCreditPurchase_PurchaseRecorded() { + FloatActivityAggregate aggregate = FloatActivityAggregate.Create(TestData.FloatAggregateId); + aggregate.RecordCreditPurchase(TestData.EstateId, TestData.CreditPurchasedDateTime, TestData.FloatCreditAmount); + } + + [Fact] + public void FloatActivityAggregate_RecordTransactionAgainstFloat_TransactionRecorded() + { + FloatActivityAggregate aggregate = FloatActivityAggregate.Create(TestData.FloatAggregateId); + aggregate.RecordTransactionAgainstFloat(TestData.EstateId, TestData.TransactionDateTime, TestData.TransactionAmount); + } +} \ No newline at end of file diff --git a/TransactionProcessor.FloatAggregate/FloatActivityAggregate.cs b/TransactionProcessor.FloatAggregate/FloatActivityAggregate.cs index f6b08132..57921898 100644 --- a/TransactionProcessor.FloatAggregate/FloatActivityAggregate.cs +++ b/TransactionProcessor.FloatAggregate/FloatActivityAggregate.cs @@ -42,7 +42,7 @@ protected override Object GetMetadata() { return new { - this.EstateId + }; } @@ -64,8 +64,4 @@ public static FloatActivityAggregate Create(Guid aggregateId) { return new FloatActivityAggregate(aggregateId); } - - public Guid EstateId { get; internal set; } - - public Decimal Balance { get; internal set; } } \ No newline at end of file diff --git a/TransactionProcessor.ProjectionEngine.Tests/ProjectionHandlerTests.cs b/TransactionProcessor.ProjectionEngine.Tests/ProjectionHandlerTests.cs index 931ccef9..354c6d95 100644 --- a/TransactionProcessor.ProjectionEngine.Tests/ProjectionHandlerTests.cs +++ b/TransactionProcessor.ProjectionEngine.Tests/ProjectionHandlerTests.cs @@ -1,4 +1,7 @@ -using SimpleResults; +using EstateManagement.Merchant.DomainEvents; +using SimpleResults; +using TransactionProcessor.ProjectionEngine.Models; +using TransactionProcessor.Transaction.DomainEvents; namespace TransactionProcessor.ProjectionEngine.Tests; @@ -105,4 +108,177 @@ public async Task ProjectionHandler_Handle_StateFoundInRepository_ChangesMade_Ev var result = await ph.Handle(TestData.MerchantCreatedEvent, CancellationToken.None); result.IsSuccess.ShouldBeTrue(); } + + [Fact] + public async Task ProjectionHandler_Handle_LoadFails_FailedResult() + { + Mock> repo = new Mock>(); + Mock> projection = new Mock>(); + Mock> stateDispatcher = new Mock>(); + ProjectionHandler.ProjectionHandler ph = new ProjectionHandler.ProjectionHandler(repo.Object, projection.Object, + stateDispatcher.Object); + MerchantBalanceState state = new MerchantBalanceState(); + MerchantBalanceState newState = new MerchantBalanceState(); + newState = newState.HandleMerchantCreated(TestData.MerchantCreatedEvent); + projection.Setup(p => p.ShouldIHandleEvent(It.IsAny())).Returns(true); + projection.Setup(p => p.Handle(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(Result.Success(newState)); + + repo.Setup(r => r.Load(It.IsAny(), It.IsAny())).ReturnsAsync(Result.Failure()); + //repo.Setup(r => r.Save(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(Result.Success(state)); + + //stateDispatcher.Setup(d => d.Dispatch(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(Result.Success()); + var result = await ph.Handle(TestData.MerchantCreatedEvent, CancellationToken.None); + result.IsFailed.ShouldBeTrue(); + } + + [Fact] + public async Task ProjectionHandler_Handle_SaveFails_FailedResult() + { + Mock> repo = new Mock>(); + Mock> projection = new Mock>(); + Mock> stateDispatcher = new Mock>(); + ProjectionHandler.ProjectionHandler ph = new ProjectionHandler.ProjectionHandler(repo.Object, projection.Object, + stateDispatcher.Object); + MerchantBalanceState state = new MerchantBalanceState(); + MerchantBalanceState newState = new MerchantBalanceState(); + newState = newState.HandleMerchantCreated(TestData.MerchantCreatedEvent); + projection.Setup(p => p.ShouldIHandleEvent(It.IsAny())).Returns(true); + projection.Setup(p => p.Handle(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(Result.Success(newState)); + + repo.Setup(r => r.Load(It.IsAny(), It.IsAny())).ReturnsAsync(state); + repo.Setup(r => r.Save(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(Result.Failure()); + + //stateDispatcher.Setup(d => d.Dispatch(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(Result.Success()); + var result = await ph.Handle(TestData.MerchantCreatedEvent, CancellationToken.None); + result.IsFailed.ShouldBeTrue(); + } + + [Fact] + public async Task ProjectionHandler_Handle_DispatchFails_FailedResult() + { + Mock> repo = new Mock>(); + Mock> projection = new Mock>(); + Mock> stateDispatcher = new Mock>(); + ProjectionHandler.ProjectionHandler ph = new ProjectionHandler.ProjectionHandler(repo.Object, projection.Object, + stateDispatcher.Object); + MerchantBalanceState state = new MerchantBalanceState(); + MerchantBalanceState newState = new MerchantBalanceState(); + newState = newState.HandleMerchantCreated(TestData.MerchantCreatedEvent); + projection.Setup(p => p.ShouldIHandleEvent(It.IsAny())).Returns(true); + projection.Setup(p => p.Handle(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(Result.Success(newState)); + + repo.Setup(r => r.Load(It.IsAny(), It.IsAny())).ReturnsAsync(state); + repo.Setup(r => r.Save(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(Result.Success(state)); + + stateDispatcher.Setup(d => d.Dispatch(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(Result.Failure); + var result = await ph.Handle(TestData.MerchantCreatedEvent, CancellationToken.None); + result.IsFailed.ShouldBeTrue(); + } +} + +public class VoucherStateDispatcherTests { + private readonly IStateDispatcher Dispatcher; + + public VoucherStateDispatcherTests() { + this.Dispatcher = new VoucherStateDispatcher(); + } + + [Fact] + public async Task MerchantBalanceStateDispatcher_TransactionHasBeenCompletedEvent_NotAuthorised_ResultSuccessful() + { + VoucherState state = new(); + + IDomainEvent domainEvent = TestData.TransactionHasBeenCompletedEvent; + + var result = await this.Dispatcher.Dispatch(state, domainEvent, CancellationToken.None); + result.IsSuccess.ShouldBeTrue(); + } +} + +public class MerchantBalanceStateDispatcherTests +{ + private readonly IStateDispatcher Dispatcher; + private readonly Mock Repository; + + public MerchantBalanceStateDispatcherTests() { + this.Repository = new Mock(); + this.Dispatcher = new MerchantBalanceStateDispatcher(this.Repository.Object); + } + + [Theory] + [InlineData(typeof(MerchantCreatedEvent))] + [InlineData(typeof(ManualDepositMadeEvent))] + [InlineData(typeof(AutomaticDepositMadeEvent))] + [InlineData(typeof(WithdrawalMadeEvent))] + [InlineData(typeof(TransactionHasBeenCompletedEvent))] + [InlineData(typeof(SettledMerchantFeeAddedToTransactionEvent))] + public async Task MerchantBalanceStateDispatcher_EventIsDispatched_ResultSuccessful(Type type) { + MerchantBalanceState state = new(); + + this.Repository.Setup(t => t.AddMerchantBalanceChangedEntry(It.IsAny(), It.IsAny())).ReturnsAsync(Result.Success); + + IDomainEvent domainEvent = type.Name switch { + nameof(MerchantCreatedEvent) => TestData.MerchantCreatedEvent, + nameof(ManualDepositMadeEvent) => TestData.ManualDepositMadeEvent, + nameof(AutomaticDepositMadeEvent) => TestData.AutomaticDepositMadeEvent, + nameof(WithdrawalMadeEvent) => TestData.WithdrawalMadeEvent, + nameof(TransactionHasBeenCompletedEvent) => TestData.TransactionHasBeenCompletedEvent, + nameof(SettledMerchantFeeAddedToTransactionEvent) => TestData.SettledMerchantFeeAddedToTransactionEvent(DateTime.Now), + _ => null + }; + + if (domainEvent != null) { + var result = await this.Dispatcher.Dispatch(state, domainEvent, CancellationToken.None); + result.IsSuccess.ShouldBeTrue(); + this.Repository.Verify(t => t.AddMerchantBalanceChangedEntry(It.IsAny(), It.IsAny()), Times.Once); + } + } + + [Fact] + public async Task MerchantBalanceStateDispatcher_TransactionHasBeenCompletedEvent_NotAuthorised_ResultSuccessful() + { + MerchantBalanceState state = new(); + + this.Repository.Setup(t => t.AddMerchantBalanceChangedEntry(It.IsAny(), It.IsAny())).ReturnsAsync(Result.Success); + + IDomainEvent domainEvent = TestData.TransactionHasBeenCompletedEvent with { + IsAuthorised = false + }; + var result = await this.Dispatcher.Dispatch(state, domainEvent, CancellationToken.None); + result.IsSuccess.ShouldBeTrue(); + this.Repository.Verify(t => t.AddMerchantBalanceChangedEntry(It.IsAny(), It.IsAny()), Times.Never); + } + + [Fact] + public async Task MerchantBalanceStateDispatcher_TransactionHasBeenCompletedEvent_AmountIsZero_ResultSuccessful() + { + MerchantBalanceState state = new(); + + this.Repository.Setup(t => t.AddMerchantBalanceChangedEntry(It.IsAny(), It.IsAny())).ReturnsAsync(Result.Success); + + IDomainEvent domainEvent = TestData.TransactionHasBeenCompletedEvent with + { + TransactionAmount = 0 + }; + var result = await this.Dispatcher.Dispatch(state, domainEvent, CancellationToken.None); + result.IsSuccess.ShouldBeTrue(); + this.Repository.Verify(t => t.AddMerchantBalanceChangedEntry(It.IsAny(), It.IsAny()), Times.Never); + } + + [Fact] + public async Task MerchantBalanceStateDispatcher_TransactionHasBeenCompletedEvent_AmountIsNegative_ResultSuccessful() + { + MerchantBalanceState state = new(); + + this.Repository.Setup(t => t.AddMerchantBalanceChangedEntry(It.IsAny(), It.IsAny())).ReturnsAsync(Result.Success); + + IDomainEvent domainEvent = TestData.TransactionHasBeenCompletedEvent with + { + TransactionAmount = -1 + }; + var result = await this.Dispatcher.Dispatch(state, domainEvent, CancellationToken.None); + result.IsSuccess.ShouldBeTrue(); + this.Repository.Verify(t => t.AddMerchantBalanceChangedEntry(It.IsAny(), It.IsAny()), Times.Once); + } + } \ No newline at end of file diff --git a/TransactionProcessor.ProjectionEngine.Tests/TestData.cs b/TransactionProcessor.ProjectionEngine.Tests/TestData.cs index 48ab509d..79199bff 100644 --- a/TransactionProcessor.ProjectionEngine.Tests/TestData.cs +++ b/TransactionProcessor.ProjectionEngine.Tests/TestData.cs @@ -1,3 +1,5 @@ +using TransactionProcessor.Models; + namespace TransactionProcessor.ProjectionEngine.Tests { using EstateManagement.Merchant.DomainEvents; @@ -214,5 +216,34 @@ public static TransactionHasStartedEvent GetTransactionHasStartedEvent(Decimal? public static VoucherIssuedEvent VoucherIssuedEvent => new VoucherIssuedEvent(TestData.VoucherId,TestData.EstateId, TestData.IssuedDateTime, TestData.RecipientEmail, TestData.RecipientMobile); public static VoucherFullyRedeemedEvent VoucherFullyRedeemedEvent => new VoucherFullyRedeemedEvent(TestData.VoucherId, TestData.EstateId, TestData.RedeemedDateTime); + + public static TransactionHasBeenCompletedEvent TransactionHasBeenCompletedEvent => new TransactionHasBeenCompletedEvent(TestData.TransactionId, + TestData.EstateId, + TestData.MerchantId, + TestData.ResponseCode, + TestData.ResponseMessage, + TestData.IsAuthorised, + TestData.TransactionDateTime, + TestData.TransactionAmount, + TestData.TransactionDateTime); + + public static Guid SettlementAggregateId = Guid.Parse("BAEBA232-CD7F-46F5-AE2E-3204FE69A441"); + public static Guid TransactionFeeId = Guid.Parse("B83FCCCE-0D45-4FC2-8952-ED277A124BDB"); + public static DateTime TransactionFeeCalculateDateTime = new DateTime(2021, 3, 18); + public static DateTime SettlementDate = new DateTime(2021, 9, 22, 1, 2, 3); + public static Decimal CalculatedFeeValue = 0.5m; + public static SettledMerchantFeeAddedToTransactionEvent SettledMerchantFeeAddedToTransactionEvent(DateTime settlementDueDate) => new(TestData.SettlementAggregateId, + TestData.EstateId, + TestData.MerchantId, + TestData.CalculatedFeeValue, + (Int32)CalculationType.Fixed, + TestData.TransactionFeeId, + TestData.CalculatedFeeValue, + TestData.TransactionFeeCalculateDateTime, + TestData.SettlementDate, + TestData.SettlementAggregateId, + TestData.TransactionDateTime); + + public static Boolean IsAuthorised = true; } } diff --git a/TransactionProcessor.ProjectionEngine.Tests/TransactionProcessor.ProjectionEngine.Tests.csproj b/TransactionProcessor.ProjectionEngine.Tests/TransactionProcessor.ProjectionEngine.Tests.csproj index 11ba802c..fa260a33 100644 --- a/TransactionProcessor.ProjectionEngine.Tests/TransactionProcessor.ProjectionEngine.Tests.csproj +++ b/TransactionProcessor.ProjectionEngine.Tests/TransactionProcessor.ProjectionEngine.Tests.csproj @@ -26,6 +26,7 @@ + diff --git a/TransactionProcessor.ProjectionEngine/State/MerchantBalanceState.cs b/TransactionProcessor.ProjectionEngine/State/MerchantBalanceState.cs index 48e3451f..612382c6 100644 --- a/TransactionProcessor.ProjectionEngine/State/MerchantBalanceState.cs +++ b/TransactionProcessor.ProjectionEngine/State/MerchantBalanceState.cs @@ -1,4 +1,6 @@ -namespace TransactionProcessor.ProjectionEngine.State; +using System.Diagnostics.CodeAnalysis; + +namespace TransactionProcessor.ProjectionEngine.State; public record MerchantBalanceState : State { @@ -30,19 +32,26 @@ public record MerchantBalanceState : State public Int32 CompletedTransactionCount { get; init; } } +[ExcludeFromCodeCoverage] public record AuthorisedSales(int count, decimal value, DateTime? lastSale); +[ExcludeFromCodeCoverage] public record DeclinedSales(int count, decimal value, DateTime? lastSale); +[ExcludeFromCodeCoverage] public record Deposits(int count, decimal value, DateTime? lastDeposit); +[ExcludeFromCodeCoverage] public record Fees(int count, decimal value); +[ExcludeFromCodeCoverage] public record Merchant(string Id, string Name, int numberOfEventsProcessed, decimal balance, Deposits deposits, Withdrawals withdrawals, AuthorisedSales authorisedSales, DeclinedSales declinedSales, Fees fees); +[ExcludeFromCodeCoverage] public record MerchantBalanceProjectionState1(Merchant merchant); +[ExcludeFromCodeCoverage] public record Withdrawals(int count, decimal value, DateTime? lastWithdrawal); diff --git a/TransactionProcessor.SettlementAggregates.Tests/SettlementAggregateTests.cs b/TransactionProcessor.SettlementAggregates.Tests/SettlementAggregateTests.cs index 5bd05c8a..f7a05720 100644 --- a/TransactionProcessor.SettlementAggregates.Tests/SettlementAggregateTests.cs +++ b/TransactionProcessor.SettlementAggregates.Tests/SettlementAggregateTests.cs @@ -88,7 +88,21 @@ public void SettlementAggregate_AddFee_AggregateNotCreated_ErrorThrown() } [Fact] - public void SettlementAggregate_AddFee_DuplicateFee_NoErrorThrown() + public void SettlementAggregate_AddFee_DuplicateFee_SettledFee_NoErrorThrown() + { + SettlementAggregate aggregate = SettlementAggregate.Create(TestData.SettlementAggregateId); + aggregate.Create(TestData.EstateId, TestData.MerchantId, TestData.SettlementDate); + aggregate.AddFee(TestData.MerchantId, TestData.TransactionId, TestData.CalculatedFeeMerchantFee()); + aggregate.MarkFeeAsSettled(TestData.MerchantId, TestData.TransactionId, TestData.CalculatedFeeMerchantFee().FeeId, TestData.SettlementDate); + Should.NotThrow(() => + { + aggregate.AddFee(TestData.MerchantId, TestData.TransactionId, TestData.CalculatedFeeMerchantFee()); + }); + aggregate.GetNumberOfFeesSettled().ShouldBe(1); + } + + [Fact] + public void SettlementAggregate_AddFee_DuplicateFee_PendingSettlement_NoErrorThrown() { SettlementAggregate aggregate = SettlementAggregate.Create(TestData.SettlementAggregateId); aggregate.Create(TestData.EstateId, TestData.MerchantId, TestData.SettlementDate); @@ -174,21 +188,37 @@ public void SettlementAggregate_MarkFeeAsSettled_FeeAlreadySettled_NoErrorThrown aggregate.MarkFeeAsSettled(TestData.MerchantId, TestData.TransactionId, TestData.CalculatedFeeMerchantFee().FeeId, TestData.SettlementDate); } - //[Fact] - //public void SettlementAggregate_ImmediatelyMarkFeeAsSettled_FeeIsSettledAndSettlementNotCompleted() - //{ - // SettlementAggregate aggregate = SettlementAggregate.Create(TestData.SettlementAggregateId); - // aggregate.Create(TestData.EstateId, TestData.MerchantId, TestData.SettlementDate); - // aggregate.AddFee(TestData.MerchantId, TestData.TransactionId, TestData.CalculatedFeeMerchantFee()); + [Fact] + public void SettlementAggregate_ImmediatelyMarkFeeAsSettled_FeeIsSettledAndSettlementNotCompleted() + { + SettlementAggregate aggregate = SettlementAggregate.Create(TestData.SettlementAggregateId); + aggregate.Create(TestData.EstateId, TestData.MerchantId, TestData.SettlementDate); + aggregate.AddFee(TestData.MerchantId, TestData.TransactionId, TestData.CalculatedFeeMerchantFee()); + + aggregate.GetNumberOfFeesPendingSettlement().ShouldBe(1); + + aggregate.ImmediatelyMarkFeeAsSettled(TestData.MerchantId, TestData.TransactionId, TestData.CalculatedFeeMerchantFee().FeeId); + + aggregate.GetNumberOfFeesPendingSettlement().ShouldBe(0); + aggregate.GetNumberOfFeesSettled().ShouldBe(1); + aggregate.SettlementComplete.ShouldBeFalse(); + } - // aggregate.GetNumberOfFeesPendingSettlement().ShouldBe(1); + [Fact] + public void SettlementAggregate_ImmediatelyMarkFeeAsSettled_FeeIsAlreadySettled() + { + SettlementAggregate aggregate = SettlementAggregate.Create(TestData.SettlementAggregateId); + aggregate.Create(TestData.EstateId, TestData.MerchantId, TestData.SettlementDate); + aggregate.AddFee(TestData.MerchantId, TestData.TransactionId, TestData.CalculatedFeeMerchantFee()); - // aggregate.ImmediatelyMarkFeeAsSettled(TestData.MerchantId, TestData.TransactionId, TestData.CalculatedFeeMerchantFee().FeeId); + aggregate.GetNumberOfFeesPendingSettlement().ShouldBe(1); - // aggregate.GetNumberOfFeesPendingSettlement().ShouldBe(0); - // aggregate.GetNumberOfFeesSettled().ShouldBe(1); - // aggregate.SettlementComplete.ShouldBeFalse(); - //} + aggregate.ImmediatelyMarkFeeAsSettled(TestData.MerchantId, TestData.TransactionId, TestData.CalculatedFeeMerchantFee().FeeId); + + aggregate.GetNumberOfFeesPendingSettlement().ShouldBe(0); + aggregate.GetNumberOfFeesSettled().ShouldBe(1); + aggregate.SettlementComplete.ShouldBeFalse(); + } [Fact] public void SettlementAggregate_StartProcessing_ProcessingStarted() @@ -254,5 +284,14 @@ public void SettlementAggregate_ManuallyComplete_SettlementNotCreated_ErrorThron aggregate.ManuallyComplete(); }); } + + [Fact] + public void SettlementAggregate_GetFeesToBeSettled_ListIsEmpty() + { + SettlementAggregate aggregate = SettlementAggregate.Create(TestData.SettlementAggregateId); + aggregate.Create(TestData.EstateId, TestData.MerchantId, TestData.SettlementDate); + var fees = aggregate.GetFeesToBeSettled(); + fees.ShouldBeEmpty(); + } } } \ No newline at end of file diff --git a/TransactionProcessor.Testing/TestData.cs b/TransactionProcessor.Testing/TestData.cs index eef719b9..9435b727 100644 --- a/TransactionProcessor.Testing/TestData.cs +++ b/TransactionProcessor.Testing/TestData.cs @@ -328,7 +328,11 @@ public static Dictionary AdditionalTransactionMetaDataForPataPaw ["AppSettings:EstateManagementApi"] = "http://127.0.0.1", ["AppSettings:SecurityService"] = "http://127.0.0.1", ["AppSettings:ContractProductFeeCacheExpiryInHours"] = "", - ["AppSettings:ContractProductFeeCacheEnabled"] = "" + ["AppSettings:ContractProductFeeCacheEnabled"] = "", + ["AppSettings:DatabaseEngine"] = "SqlServer", + ["ConnectionStrings:HealthCheck"] = "HealthCheck", + ["ConnectionStrings:EstateReportingReadModel"] = "", + ["ConnectionStrings:TransactionProcessorReadModel"] = "" }; public static EstateResponse GetEmptyEstateResponse => @@ -441,7 +445,38 @@ public static Dictionary AdditionalTransactionMetaDataForPataPaw TestData.ProductId } } - } + }, + SettlementSchedule = SettlementSchedule.Monthly + }; + + public static EstateManagement.DataTransferObjects.Responses.Merchant.MerchantResponse GetMerchantResponseWithOperator1ImmediateSettlement => + new EstateManagement.DataTransferObjects.Responses.Merchant.MerchantResponse + { + EstateId = TestData.EstateId, + MerchantId = TestData.MerchantId, + MerchantName = TestData.MerchantName, + Devices = new Dictionary + { + {TestData.DeviceId, TestData.DeviceIdentifier} + }, + Operators = new List + { + new EstateManagement.DataTransferObjects.Responses.Merchant.MerchantOperatorResponse + { + OperatorId = TestData.OperatorId, + MerchantNumber = TestData.MerchantNumber, + TerminalNumber = TestData.TerminalNumber + } + }, + Contracts = new List{ + new MerchantContractResponse{ + ContractId = TestData.ContractId, + ContractProducts = new List(){ + TestData.ProductId + } + } + }, + SettlementSchedule = SettlementSchedule.Immediate }; public static EstateManagement.DataTransferObjects.Responses.Merchant.MerchantResponse GetMerchantResponseWithOperator1AndNullContracts => @@ -608,7 +643,17 @@ public static Dictionary AdditionalTransactionMetaDataForPataPaw { EstateId = TestData.EstateId, MerchantId = TestData.MerchantId, - MerchantName = TestData.MerchantName + MerchantName = TestData.MerchantName, + SettlementSchedule = SettlementSchedule.Monthly + }; + + public static EstateManagement.DataTransferObjects.Responses.Merchant.MerchantResponse MerchantWithImmediateSettlement => + new EstateManagement.DataTransferObjects.Responses.Merchant.MerchantResponse + { + EstateId = TestData.EstateId, + MerchantId = TestData.MerchantId, + MerchantName = TestData.MerchantName, + SettlementSchedule = SettlementSchedule.Immediate }; public static TransactionCommands.ProcessLogonTransactionCommand ProcessLogonTransactionCommand => @@ -632,6 +677,25 @@ public static Dictionary AdditionalTransactionMetaDataForPataPaw ResponseCode = TestData.ResponseCode }; + public static MerchantQueries.GetMerchantBalanceQuery GetMerchantBalanceQuery => new(EstateId, MerchantId); + + public static MerchantQueries.GetMerchantLiveBalanceQuery GetMerchantLiveBalanceQuery => new(MerchantId); + + public static MerchantQueries.GetMerchantBalanceHistoryQuery GetMerchantBalanceHistoryQuery => new MerchantQueries.GetMerchantBalanceHistoryQuery(EstateId, MerchantId, DateTime.MinValue, DateTime.MaxValue); + + public static SettlementCommands.AddMerchantFeePendingSettlementCommand AddMerchantFeePendingSettlementCommand => new(TransactionId, CalculatedFeeValue, TransactionFeeCalculateDateTime, CalculationType.Fixed, TransactionFeeId, CalculatedFeeValue, TransactionFeeSettlementDueDate, MerchantId, EstateId); + public static SettlementCommands.AddSettledFeeToSettlementCommand AddSettledFeeToSettlementCommand => new(SettlementDate,MerchantId,EstateId,TransactionFeeId, TransactionId); + + public static FloatActivityCommands.RecordCreditPurchaseCommand RecordCreditPurchaseCommand => new(EstateId, FloatAggregateId, CreditPurchasedDateTime, FloatCreditAmount); + + public static TransactionCommands.CalculateFeesForTransactionCommand CalculateFeesForTransactionCommand => new(TransactionId, TransactionDateTime, EstateId, MerchantId); + + public static TransactionCommands.AddSettledMerchantFeeCommand AddSettledMerchantFeeCommand => new(TransactionId, CalculatedFeeValue, TransactionFeeCalculateDateTime, CalculationType.Percentage, TransactionFeeId, TransactionFeeValue, SettlementDate, SettlementAggregateId); + + public static VoucherQueries.GetVoucherByVoucherCodeQuery GetVoucherByVoucherCodeQuery => new(EstateId, VoucherCode); + public static VoucherQueries.GetVoucherByTransactionIdQuery GetVoucherByTransactionIdQuery => new(EstateId, TransactionId); + + public static SettlementQueries.GetPendingSettlementQuery GetPendingSettlementQuery => new(SettlementDate, MerchantId, EstateId); public static TransactionCommands.ProcessSaleTransactionCommand ProcessSaleTransactionCommand => new(TestData.TransactionId, TestData.EstateId, diff --git a/TransactionProcessor/Bootstrapper/MediatorRegistry.cs b/TransactionProcessor/Bootstrapper/MediatorRegistry.cs index e234393e..e7b27f78 100644 --- a/TransactionProcessor/Bootstrapper/MediatorRegistry.cs +++ b/TransactionProcessor/Bootstrapper/MediatorRegistry.cs @@ -53,6 +53,7 @@ public MediatorRegistry() this.AddSingleton, FloatRequestHandler>(); this.AddSingleton, FloatRequestHandler>(); + this.AddSingleton, FloatRequestHandler>(); this.AddSingleton>, MerchantRequestHandler>(); this.AddSingleton>, MerchantRequestHandler>(); diff --git a/TransactionProcessor/Bootstrapper/MiscRegistry.cs b/TransactionProcessor/Bootstrapper/MiscRegistry.cs index 01725326..5788b83d 100644 --- a/TransactionProcessor/Bootstrapper/MiscRegistry.cs +++ b/TransactionProcessor/Bootstrapper/MiscRegistry.cs @@ -37,9 +37,9 @@ public MiscRegistry() this.AddSingleton(); this.AddSingleton(); - bool logRequests = ConfigurationReaderExtensions.GetValueOrDefault("MiddlewareLogging", "LogRequests", true); - bool logResponses = ConfigurationReaderExtensions.GetValueOrDefault("MiddlewareLogging", "LogResponses", true); - LogLevel middlewareLogLevel = ConfigurationReaderExtensions.GetValueOrDefault("MiddlewareLogging", "MiddlewareLogLevel", LogLevel.Warning); + bool logRequests = ConfigurationReader.GetValueOrDefault("MiddlewareLogging", "LogRequests", true); + bool logResponses = ConfigurationReader.GetValueOrDefault("MiddlewareLogging", "LogResponses", true); + LogLevel middlewareLogLevel = ConfigurationReader.GetValueOrDefault("MiddlewareLogging", "MiddlewareLogLevel", LogLevel.Warning); RequestResponseMiddlewareLoggingConfig config = new RequestResponseMiddlewareLoggingConfig(middlewareLogLevel, logRequests, logResponses); @@ -50,25 +50,25 @@ public MiscRegistry() #endregion } - public static class ConfigurationReaderExtensions - { - public static T GetValueOrDefault(String sectionName, String keyName, T defaultValue) - { - try - { - var value = ConfigurationReader.GetValue(sectionName, keyName); + //public static class ConfigurationReaderExtensions + //{ + // public static T GetValueOrDefault(String sectionName, String keyName, T defaultValue) + // { + // try + // { + // var value = ConfigurationReader.GetValue(sectionName, keyName); - if (String.IsNullOrEmpty(value)) - { - return defaultValue; - } + // if (String.IsNullOrEmpty(value)) + // { + // return defaultValue; + // } - return (T)Convert.ChangeType(value, typeof(T)); - } - catch (KeyNotFoundException kex) - { - return defaultValue; - } - } - } + // return (T)Convert.ChangeType(value, typeof(T)); + // } + // catch (KeyNotFoundException kex) + // { + // return defaultValue; + // } + // } + //} } \ No newline at end of file diff --git a/TransactionProcessor/Controllers/FloatController.cs b/TransactionProcessor/Controllers/FloatController.cs index e5f006bd..b08d6c90 100644 --- a/TransactionProcessor/Controllers/FloatController.cs +++ b/TransactionProcessor/Controllers/FloatController.cs @@ -1,4 +1,5 @@ using Microsoft.AspNetCore.Mvc; +using Shared.Results; using SimpleResults; namespace TransactionProcessor.Controllers diff --git a/TransactionProcessor/Controllers/MerchantController.cs b/TransactionProcessor/Controllers/MerchantController.cs index 53a13d83..77759718 100644 --- a/TransactionProcessor/Controllers/MerchantController.cs +++ b/TransactionProcessor/Controllers/MerchantController.cs @@ -1,5 +1,6 @@ using MediatR; using Microsoft.CodeAnalysis.Elfie.Diagnostics; +using Shared.Results; using SimpleResults; using TransactionProcessor.BusinessLogic.Requests; diff --git a/TransactionProcessor/Controllers/ResultExtensions.cs b/TransactionProcessor/Controllers/ResultExtensions.cs deleted file mode 100644 index d4f9387b..00000000 --- a/TransactionProcessor/Controllers/ResultExtensions.cs +++ /dev/null @@ -1,63 +0,0 @@ -using System; -using System.Net; -using Microsoft.AspNetCore.Mvc; -using SimpleResults; - -namespace TransactionProcessor.Controllers; - -public static class ResultExtensions -{ - public static IActionResult ToActionResultX(this Result result) - { - if (result.IsSuccess) - return new OkObjectResult(result); - - return result.Status switch - { - ResultStatus.Invalid => new BadRequestObjectResult(result), - ResultStatus.NotFound => new NotFoundObjectResult(result), - ResultStatus.Unauthorized => new UnauthorizedObjectResult(result), - ResultStatus.Conflict => new ConflictObjectResult(result), - ResultStatus.Failure => CreateObjectResult(result, HttpStatusCode.InternalServerError), - ResultStatus.CriticalError => CreateObjectResult(result, HttpStatusCode.InternalServerError), - ResultStatus.Forbidden => new ForbidResult(), - _ => CreateObjectResult(result, HttpStatusCode.NotImplemented) - - }; - } - - internal static IActionResult ToActionResultX(this Result result) - { - if (result.IsSuccess) - return new OkObjectResult(result); - - return result.Status switch - { - ResultStatus.Invalid => new BadRequestObjectResult(result), - ResultStatus.NotFound => new NotFoundObjectResult(result), - ResultStatus.Unauthorized => new UnauthorizedObjectResult(result), - ResultStatus.Conflict => new ConflictObjectResult(result), - ResultStatus.Failure => CreateObjectResult(result, HttpStatusCode.InternalServerError), - ResultStatus.CriticalError => CreateObjectResult(result, HttpStatusCode.InternalServerError), - ResultStatus.Forbidden => new ForbidResult(), - _ => CreateObjectResult(result, HttpStatusCode.NotImplemented) - - }; - } - - internal static ObjectResult CreateObjectResult(Result result, - HttpStatusCode statusCode) - { - ObjectResult or = new ObjectResult(result); - or.StatusCode = (Int32)statusCode; - return or; - } - - internal static ObjectResult CreateObjectResult(Result result, - HttpStatusCode statusCode) - { - ObjectResult or = new ObjectResult(result); - or.StatusCode = (Int32)statusCode; - return or; - } -} \ No newline at end of file diff --git a/TransactionProcessor/Controllers/SettlementController.cs b/TransactionProcessor/Controllers/SettlementController.cs index feec697a..b4e9c3f8 100644 --- a/TransactionProcessor/Controllers/SettlementController.cs +++ b/TransactionProcessor/Controllers/SettlementController.cs @@ -1,5 +1,6 @@ using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; +using Shared.Results; using SimpleResults; namespace TransactionProcessor.Controllers diff --git a/TransactionProcessor/Extensions.cs b/TransactionProcessor/Extensions.cs index e982c1a2..481f0f3e 100644 --- a/TransactionProcessor/Extensions.cs +++ b/TransactionProcessor/Extensions.cs @@ -32,32 +32,35 @@ namespace TransactionProcessor using TransactionProcessor.BusinessLogic.OperatorInterfaces; [ExcludeFromCodeCoverage] - public static class Extensions - { - static Action log = (tt, subType, message) => { - String logMessage = $"{subType} - {message}"; - switch (tt) - { - case TraceEventType.Critical: - Logger.LogCritical(new Exception(logMessage)); - break; - case TraceEventType.Error: - Logger.LogError(new Exception(logMessage)); - break; - case TraceEventType.Warning: - Logger.LogWarning(logMessage); - break; - case TraceEventType.Information: - Logger.LogInformation(logMessage); - break; - case TraceEventType.Verbose: - Logger.LogDebug(logMessage); - break; - } - }; - - static Action mainLog = (tt, message) => Extensions.log(tt, "MAIN", message); - static Action orderedLog = (tt, message) => Extensions.log(tt, "ORDERED", message); + public static class Extensions { + static Action log = (tt, + subType, + message) => { + String logMessage = $"{subType} - {message}"; + switch (tt) { + case TraceEventType.Critical: + Logger.LogCritical(new Exception(logMessage)); + break; + case TraceEventType.Error: + Logger.LogError(new Exception(logMessage)); + break; + case TraceEventType.Warning: + Logger.LogWarning(logMessage); + break; + case TraceEventType.Information: + Logger.LogInformation(logMessage); + break; + case TraceEventType.Verbose: + Logger.LogDebug(logMessage); + break; + } + }; + + static Action mainLog = (tt, + message) => Extensions.log(tt, "MAIN", message); + + static Action orderedLog = (tt, + message) => Extensions.log(tt, "ORDERED", message); public static void PreWarm(this IApplicationBuilder applicationBuilder) { TypeProvider.LoadDomainEventsTypeDynamically(); @@ -71,10 +74,7 @@ public static void PreWarm(this IApplicationBuilder applicationBuilder) { IDomainEventHandlerResolver mainEventHandlerResolver = Startup.Container.GetInstance("Main"); IDomainEventHandlerResolver orderedEventHandlerResolver = Startup.Container.GetInstance("Ordered"); - Dictionary eventHandlerResolvers = new Dictionary { - {"Main", mainEventHandlerResolver}, - {"Ordered", orderedEventHandlerResolver} - }; + Dictionary eventHandlerResolvers = new Dictionary { { "Main", mainEventHandlerResolver }, { "Ordered", orderedEventHandlerResolver } }; Func subscriptionRepositoryResolver = Startup.Container.GetInstance>(); @@ -82,87 +82,31 @@ public static void PreWarm(this IApplicationBuilder applicationBuilder) { String connectionString = Startup.Configuration.GetValue("EventStoreSettings:ConnectionString"); EventStoreClientSettings eventStoreClientSettings = EventStoreClientSettings.Create(connectionString); - applicationBuilder.ConfigureSubscriptionService(subscriptionWorkersRoot, - eventStoreConnectionString, - eventHandlerResolvers, - Extensions.log, - subscriptionRepositoryResolver).Wait(CancellationToken.None); - - //LoadContractData(CancellationToken.None).Wait(CancellationToken.None); - + applicationBuilder.ConfigureSubscriptionService(subscriptionWorkersRoot, eventStoreConnectionString, eventHandlerResolvers, Extensions.log, subscriptionRepositoryResolver).Wait(CancellationToken.None); } - /*private static async Task LoadContractData(CancellationToken cancellationToken){ - IEstateClient estateClient = Startup.Container.GetRequiredService(); - ISecurityServiceClient securityServiceClient = Startup.Container.GetRequiredService(); - IEventStoreContext eventStoreContext = Startup.Container.GetRequiredService(); - - var clientId = ConfigurationReader.GetValue("AppSettings", "ClientId"); - var clientSecret = ConfigurationReader.GetValue("AppSettings", "ClientSecret"); - var token = await securityServiceClient.GetToken(clientId, clientSecret, cancellationToken); - - List> contractResponses = new(); - - Stopwatch sw = Stopwatch.StartNew(); - // get a list of the contracts from ES projection - String state = await eventStoreContext.GetStateFromProjection("ContractList",cancellationToken); - ContractList contractList = JsonConvert.DeserializeObject(state); - contractList.Contracts.AddRange(contractList.Contracts); - contractList.Contracts.AddRange(contractList.Contracts); - contractList.Contracts.AddRange(contractList.Contracts); - contractList.Contracts.AddRange(contractList.Contracts); - contractList.Contracts.AddRange(contractList.Contracts); - contractList.Contracts.AddRange(contractList.Contracts); - - List>> tasks = new (); - foreach (var contract in contractList.Contracts){ - //ContractResponse contractResponse = await estateClient.GetContract(token.AccessToken, contract.EstateId, contract.ContractId, cancellationToken); - //contractResponses.Add(contractResponse); - tasks.Add(estateClient.GetContract(token.AccessToken, contract.EstateId, contract.ContractId, cancellationToken)); - } - - Result[] t = await Task.WhenAll(tasks); - - contractResponses = t.ToList(); - if (contractResponses.Any(c => c.IsSuccess)){ - IMemoryCache memoryCache = Startup.Container.GetRequiredService(); - // // Build up the cache - Dictionary<(Guid, Guid), List> productfees = contractResponses.Select(c => c.Data) - .SelectMany(contractResponse => contractResponse.Products.Select(contractResponseProduct => - new{ - //Key = (contractResponse.EstateId, contractResponseProduct.ProductId), - Key = (Guid.NewGuid(),Guid.NewGuid()), - Value = contractResponseProduct.TransactionFees - })) - .ToDictionary(x => x.Key, x => x.Value); - memoryCache.Set("TransactionFeeCache", productfees); - } - sw.Stop(); - Logger.LogWarning($"Contract Data loaded an cached [{sw.ElapsedMilliseconds} ms"); - }*/ } - public class AutoLogonWorkerService : BackgroundService{ - protected override async Task ExecuteAsync(CancellationToken stoppingToken){ + [ExcludeFromCodeCoverage] + public class AutoLogonWorkerService : BackgroundService { + protected override async Task ExecuteAsync(CancellationToken stoppingToken) { + + while (stoppingToken.IsCancellationRequested == false) { - while (stoppingToken.IsCancellationRequested == false){ - - if (Startup.AutoApiLogonOperators.Any()){ - foreach (String autoApiLogonOperator in Startup.AutoApiLogonOperators){ + if (Startup.AutoApiLogonOperators.Any()) { + foreach (String autoApiLogonOperator in Startup.AutoApiLogonOperators) { OperatorLogon(autoApiLogonOperator); } } - String fileProfilePollingWindowInSeconds ="5"; + String fileProfilePollingWindowInSeconds = "5"; // Delay for configured seconds before polling for files again await Task.Delay(TimeSpan.FromSeconds(int.Parse(fileProfilePollingWindowInSeconds)), stoppingToken); } } - private static void OperatorLogon(String operatorId) - { - try - { + private static void OperatorLogon(String operatorId) { + try { Logger.LogInformation($"About to do auto logon for operator Id [{operatorId}]"); Func resolver = Startup.ServiceProvider.GetService>(); IOperatorProxy proxy = resolver(operatorId); @@ -170,31 +114,17 @@ private static void OperatorLogon(String operatorId) Result logonResult = proxy.ProcessLogonMessage(null, CancellationToken.None).Result; if (logonResult.IsSuccess) { - Logger.LogInformation( - $"Auto logon for operator Id [{operatorId}] status [{logonResult.Data.IsSuccessful}]"); + Logger.LogInformation($"Auto logon for operator Id [{operatorId}] status [{logonResult.Data.IsSuccessful}]"); } - if (logonResult.IsFailed) - { - Logger.LogWarning( - $"Auto logon for operator Id [{operatorId}] status [{logonResult.Message}]"); + + if (logonResult.IsFailed) { + Logger.LogWarning($"Auto logon for operator Id [{operatorId}] status [{logonResult.Message}]"); } } - catch (Exception ex) - { + catch (Exception ex) { Logger.LogWarning($"Auto logon for operator Id [{operatorId}] failed."); Logger.LogWarning(ex.ToString()); } } } - - public class Contract - { - public Guid EstateId { get; set; } - public Guid ContractId { get; set; } - } - - public class ContractList - { - public List Contracts { get; set; } - } } \ No newline at end of file