From 55121aa8ef4dc0894a6c5d87f0cf581b11cd4a3c Mon Sep 17 00:00:00 2001 From: Stuart Ferguson Date: Sat, 18 Feb 2023 11:41:01 +0000 Subject: [PATCH 1/2] Tests updated and added TxnValiationService --- .../Services/SettlementDomainServiceTests.cs | 8 +- .../Services/TransactionDomainServiceTests.cs | 1363 ++++------------- .../TransactionValidationServiceTests.cs | 839 ++++++++++ ...actionProcessor.BusinessLogic.Tests.csproj | 2 +- .../Services/ITransactionValidationService.cs | 30 + .../Services/TransactionDomainService.cs | 471 +----- .../Services/TransactionResponseCode.cs | 3 +- .../Services/TransactionValidationService.cs | 314 ++++ .../TransactionAggregateTests.cs | 2 - .../TransactionAggregate.cs | 7 +- .../Bootstrapper/DomainServiceRegistry.cs | 1 + 11 files changed, 1571 insertions(+), 1469 deletions(-) create mode 100644 TransactionProcessor.BusinessLogic.Tests/Services/TransactionValidationServiceTests.cs create mode 100644 TransactionProcessor.BusinessLogic/Services/ITransactionValidationService.cs create mode 100644 TransactionProcessor.BusinessLogic/Services/TransactionValidationService.cs diff --git a/TransactionProcessor.BusinessLogic.Tests/Services/SettlementDomainServiceTests.cs b/TransactionProcessor.BusinessLogic.Tests/Services/SettlementDomainServiceTests.cs index e0e54481..1c1254d7 100644 --- a/TransactionProcessor.BusinessLogic.Tests/Services/SettlementDomainServiceTests.cs +++ b/TransactionProcessor.BusinessLogic.Tests/Services/SettlementDomainServiceTests.cs @@ -41,7 +41,7 @@ public SettlementDomainServiceTests() { } [Fact] - public async Task TransactionDomainService_ProcessSettlement_SettlementIsProcessed() + public async Task SettlementDomainService_ProcessSettlement_SettlementIsProcessed() { settlementAggregateRepository.Setup(s => s.GetLatestVersion(It.IsAny(), It.IsAny())) .ReturnsAsync(TestData.GetSettlementAggregateWithPendingMerchantFees(10)); @@ -59,7 +59,7 @@ public async Task TransactionDomainService_ProcessSettlement_SettlementIsProcess } [Fact] - public async Task TransactionDomainService_ProcessSettlement_SettlementAggregateNotCreated_NothingProcessed() + public async Task SettlementDomainService_ProcessSettlement_SettlementAggregateNotCreated_NothingProcessed() { settlementAggregateRepository.Setup(s => s.GetLatestVersion(It.IsAny(), It.IsAny())) .ReturnsAsync(TestData.GetEmptySettlementAggregate); @@ -75,7 +75,7 @@ public async Task TransactionDomainService_ProcessSettlement_SettlementAggregate } [Fact] - public async Task TransactionDomainService_ProcessSettlement_SettlementAggregateNoFeesToSettles_NothingProcessed() + public async Task SettlementDomainService_ProcessSettlement_SettlementAggregateNoFeesToSettles_NothingProcessed() { settlementAggregateRepository.Setup(s => s.GetLatestVersion(It.IsAny(), It.IsAny())) .ReturnsAsync(TestData.GetCreatedSettlementAggregate); @@ -91,7 +91,7 @@ public async Task TransactionDomainService_ProcessSettlement_SettlementAggregate } [Fact] - public async Task TransactionDomainService_ProcessSettlement_AddSettledFeeThrownException_SettlementProcessed() + public async Task SettlementDomainService_ProcessSettlement_AddSettledFeeThrownException_SettlementProcessed() { settlementAggregateRepository.Setup(s => s.GetLatestVersion(It.IsAny(), It.IsAny())) .ReturnsAsync(TestData.GetSettlementAggregateWithPendingMerchantFees(10)); diff --git a/TransactionProcessor.BusinessLogic.Tests/Services/TransactionDomainServiceTests.cs b/TransactionProcessor.BusinessLogic.Tests/Services/TransactionDomainServiceTests.cs index c3d2aaf8..cdee6911 100644 --- a/TransactionProcessor.BusinessLogic.Tests/Services/TransactionDomainServiceTests.cs +++ b/TransactionProcessor.BusinessLogic.Tests/Services/TransactionDomainServiceTests.cs @@ -1,5 +1,4 @@ -namespace TransactionProcessor.BusinessLogic.Tests.Services -{ +namespace TransactionProcessor.BusinessLogic.Tests.Services{ using System; using System.Collections.Generic; using System.Threading; @@ -12,8 +11,6 @@ using Microsoft.Extensions.Configuration; using Models; using Moq; - using ProjectionEngine.Repository; - using ProjectionEngine.State; using ReconciliationAggregate; using SecurityService.Client; using Shared.DomainDrivenDesign.EventSourcing; @@ -25,47 +22,46 @@ using TransactionAggregate; using Xunit; - public class TransactionDomainServiceTests - { + public class TransactionDomainServiceTests{ #region Fields - private readonly Mock estateClient; + private readonly Mock EstateClient; - private readonly Mock operatorProxy; + private readonly Mock OperatorProxy; - private readonly Mock> reconciliationAggregateRepository; + private readonly Mock> ReconciliationAggregateRepository; - private readonly Mock securityServiceClient; + private readonly Mock SecurityServiceClient; - private readonly Mock> stateRepository; + private readonly Mock> TransactionAggregateRepository; - private readonly Mock> transactionAggregateRepository; + private readonly TransactionDomainService TransactionDomainService; - private readonly TransactionDomainService transactionDomainService; + private readonly Mock TransactionValidationService; #endregion #region Constructors - public TransactionDomainServiceTests() { + public TransactionDomainServiceTests(){ IConfigurationRoot configurationRoot = new ConfigurationBuilder().AddInMemoryCollection(TestData.DefaultAppSettings).Build(); ConfigurationReader.Initialise(configurationRoot); Logger.Initialise(NullLogger.Instance); - this.transactionAggregateRepository = new Mock>(); - this.estateClient = new Mock(); - this.securityServiceClient = new Mock(); - this.operatorProxy = new Mock(); - this.reconciliationAggregateRepository = new Mock>(); - Func operatorProxyResolver = operatorName => { return this.operatorProxy.Object; }; - this.stateRepository = new Mock>(); - this.transactionDomainService = new TransactionDomainService(this.transactionAggregateRepository.Object, - this.estateClient.Object, - this.securityServiceClient.Object, + this.TransactionAggregateRepository = new Mock>(); + this.EstateClient = new Mock(); + this.SecurityServiceClient = new Mock(); + this.OperatorProxy = new Mock(); + this.ReconciliationAggregateRepository = new Mock>(); + Func operatorProxyResolver = operatorName => { return this.OperatorProxy.Object; }; + this.TransactionValidationService = new Mock(); + this.TransactionDomainService = new TransactionDomainService(this.TransactionAggregateRepository.Object, + this.EstateClient.Object, operatorProxyResolver, - this.reconciliationAggregateRepository.Object, - this.stateRepository.Object); + this.ReconciliationAggregateRepository.Object, + this.TransactionValidationService.Object, + this.SecurityServiceClient.Object); } #endregion @@ -73,1147 +69,390 @@ public TransactionDomainServiceTests() { #region Methods [Fact] - public async Task TransactionDomainService_ProcessLogonTransaction_LogonFailed_TransactionIsProcessed() { - this.securityServiceClient.Setup(s => s.GetToken(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(TestData.TokenResponse); - - this.estateClient.Setup(e => e.GetEstate(It.IsAny(), It.IsAny(), It.IsAny())) - .ThrowsAsync(new Exception("Exception", new KeyNotFoundException("Estate Not Found"))); - - this.transactionAggregateRepository.Setup(t => t.GetLatestVersion(It.IsAny(), It.IsAny())) + public async Task TransactionDomainService_ProcessLogonTransaction_DeviceNeedsAdded_TransactionIsProcessed(){ + this.TransactionAggregateRepository.Setup(t => t.GetLatestVersion(It.IsAny(), It.IsAny())) .ReturnsAsync(TestData.GetEmptyTransactionAggregate); - this.stateRepository.Setup(p => p.Load(It.IsAny(), It.IsAny(), It.IsAny())) - .ReturnsAsync(TestData.MerchantBalanceProjectionState); - - ProcessLogonTransactionResponse response = await this.transactionDomainService.ProcessLogonTransaction(TestData.TransactionId, - TestData.EstateId, - TestData.MerchantId, - TestData.TransactionDateTime, - TestData.TransactionNumber, - TestData.DeviceIdentifier, - CancellationToken.None); + this.EstateClient.Setup(e => e.AddDeviceToMerchant(It.IsAny(), + It.IsAny(), + It.IsAny(), + It.IsAny(), + It.IsAny())) + .ReturnsAsync(new AddMerchantDeviceResponse{ + DeviceId = TestData.DeviceId, + MerchantId = TestData.MerchantId, + EstateId = TestData.TransactionId, + }); + + this.SecurityServiceClient.Setup(s => s.GetToken(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(TestData.TokenResponse); + + this.TransactionValidationService.Setup(t => t.ValidateLogonTransaction(It.IsAny(), + It.IsAny(), + It.IsAny(), + It.IsAny())).ReturnsAsync(("SUCCESS", TransactionResponseCode.SuccessNeedToAddDevice)); + + ProcessLogonTransactionResponse response = await this.TransactionDomainService.ProcessLogonTransaction(TestData.TransactionId, + TestData.EstateId, + TestData.MerchantId, + TestData.TransactionDateTime, + TestData.TransactionNumber, + TestData.DeviceIdentifier, + CancellationToken.None); response.EstateId.ShouldBe(TestData.EstateId); response.MerchantId.ShouldBe(TestData.MerchantId); - response.ResponseCode.ShouldNotBe("0000"); - response.ResponseMessage.ShouldNotBe("SUCCESS"); + response.ResponseCode.ShouldBe("0001"); response.TransactionId.ShouldBe(TestData.TransactionId); } [Fact] - public async Task TransactionDomainService_ProcessLogonTransaction_TransactionIsProcessed() { - this.securityServiceClient.Setup(s => s.GetToken(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(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.transactionAggregateRepository.Setup(t => t.GetLatestVersion(It.IsAny(), It.IsAny())) + public async Task TransactionDomainService_ProcessLogonTransaction_TransactionIsProcessed(){ + this.TransactionAggregateRepository.Setup(t => t.GetLatestVersion(It.IsAny(), It.IsAny())) .ReturnsAsync(TestData.GetEmptyTransactionAggregate); - this.stateRepository.Setup(p => p.Load(It.IsAny(), It.IsAny(), It.IsAny())) - .ReturnsAsync(TestData.MerchantBalanceProjectionState); + this.TransactionValidationService.Setup(t => t.ValidateLogonTransaction(It.IsAny(), + It.IsAny(), + It.IsAny(), + It.IsAny())).ReturnsAsync(("SUCCESS", TransactionResponseCode.Success)); - ProcessLogonTransactionResponse response = await this.transactionDomainService.ProcessLogonTransaction(TestData.TransactionId, - TestData.EstateId, - TestData.MerchantId, - TestData.TransactionDateTime, - TestData.TransactionNumber, - TestData.DeviceIdentifier, - CancellationToken.None); + ProcessLogonTransactionResponse response = await this.TransactionDomainService.ProcessLogonTransaction(TestData.TransactionId, + TestData.EstateId, + TestData.MerchantId, + TestData.TransactionDateTime, + TestData.TransactionNumber, + TestData.DeviceIdentifier, + CancellationToken.None); response.EstateId.ShouldBe(TestData.EstateId); response.MerchantId.ShouldBe(TestData.MerchantId); response.ResponseCode.ShouldBe("0000"); - response.ResponseMessage.ShouldBe("SUCCESS"); response.TransactionId.ShouldBe(TestData.TransactionId); } - [Fact] - public async Task TransactionDomainService_ProcessReconciliationTransaction_TransactionIsProcessed() { - this.securityServiceClient.Setup(s => s.GetToken(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(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); + [Theory] + [InlineData(TransactionResponseCode.InvalidEstateId)] + [InlineData(TransactionResponseCode.InvalidMerchantId)] + [InlineData(TransactionResponseCode.InvalidDeviceIdentifier)] + public async Task TransactionDomainService_ProcessLogonTransaction_ValidationFailed_TransactionIsProcessed(TransactionResponseCode responseCode){ + this.TransactionAggregateRepository.Setup(t => t.GetLatestVersion(It.IsAny(), It.IsAny())) + .ReturnsAsync(TestData.GetEmptyTransactionAggregate); - this.reconciliationAggregateRepository.Setup(r => r.GetLatestVersion(It.IsAny(), It.IsAny())) - .ReturnsAsync(new ReconciliationAggregate()); + this.TransactionValidationService.Setup(t => t.ValidateLogonTransaction(It.IsAny(), + It.IsAny(), + It.IsAny(), + It.IsAny())).ReturnsAsync((responseCode.ToString(), responseCode)); - ProcessReconciliationTransactionResponse response = await this.transactionDomainService.ProcessReconciliationTransaction(TestData.TransactionId, - TestData.EstateId, - TestData.MerchantId, - TestData.DeviceIdentifier, - TestData.TransactionDateTime, - TestData.ReconciliationTransactionCount, - TestData.ReconciliationTransactionValue, - CancellationToken.None); + ProcessLogonTransactionResponse response = await this.TransactionDomainService.ProcessLogonTransaction(TestData.TransactionId, + TestData.EstateId, + TestData.MerchantId, + TestData.TransactionDateTime, + TestData.TransactionNumber, + TestData.DeviceIdentifier, + CancellationToken.None); response.EstateId.ShouldBe(TestData.EstateId); response.MerchantId.ShouldBe(TestData.MerchantId); - response.ResponseCode.ShouldBe("0000"); - response.ResponseMessage.ShouldBe("SUCCESS"); + response.ResponseCode.ShouldBe(((Int32)responseCode).ToString().PadLeft(4, '0')); response.TransactionId.ShouldBe(TestData.TransactionId); } [Fact] - public async Task TransactionDomainService_ProcessReconciliationTransaction_ValidationFailed_TransactionIsProcessed() { - this.securityServiceClient.Setup(s => s.GetToken(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(TestData.TokenResponse); + public async Task TransactionDomainService_ProcessReconciliationTransaction_ReconciliationIsProcessed(){ + this.ReconciliationAggregateRepository.Setup(r => r.GetLatestVersion(It.IsAny(), It.IsAny())) + .ReturnsAsync(new ReconciliationAggregate()); - this.estateClient.Setup(e => e.GetEstate(It.IsAny(), It.IsAny(), It.IsAny())) - .ThrowsAsync(new Exception("Exception", new KeyNotFoundException("Invalid Merchant"))); + this.TransactionValidationService.Setup(t => t.ValidateReconciliationTransaction(It.IsAny(), + It.IsAny(), + It.IsAny(), + It.IsAny())).ReturnsAsync(("SUCCESS", TransactionResponseCode.Success)); + + ProcessReconciliationTransactionResponse response = await this.TransactionDomainService.ProcessReconciliationTransaction(TestData.TransactionId, + TestData.EstateId, + TestData.MerchantId, + TestData.DeviceIdentifier, + TestData.TransactionDateTime, + TestData.ReconciliationTransactionCount, + TestData.ReconciliationTransactionValue, + CancellationToken.None); + ; - this.reconciliationAggregateRepository.Setup(r => r.GetLatestVersion(It.IsAny(), It.IsAny())) + response.EstateId.ShouldBe(TestData.EstateId); + response.MerchantId.ShouldBe(TestData.MerchantId); + response.ResponseCode.ShouldBe("0000"); + response.TransactionId.ShouldBe(TestData.TransactionId); + } + + [Theory] + [InlineData(TransactionResponseCode.InvalidEstateId)] + [InlineData(TransactionResponseCode.InvalidMerchantId)] + [InlineData(TransactionResponseCode.NoValidDevices)] + [InlineData(TransactionResponseCode.InvalidDeviceIdentifier)] + public async Task TransactionDomainService_ProcessReconciliationTransaction_ValidationFailed_ReconciliationIsProcessed(TransactionResponseCode responseCode){ + this.ReconciliationAggregateRepository.Setup(r => r.GetLatestVersion(It.IsAny(), It.IsAny())) .ReturnsAsync(new ReconciliationAggregate()); - ProcessReconciliationTransactionResponse response = await this.transactionDomainService.ProcessReconciliationTransaction(TestData.TransactionId, - TestData.EstateId, - TestData.MerchantId, - TestData.DeviceIdentifier, - TestData.TransactionDateTime, - TestData.ReconciliationTransactionCount, - TestData.ReconciliationTransactionValue, - CancellationToken.None); + this.TransactionValidationService.Setup(t => t.ValidateReconciliationTransaction(It.IsAny(), + It.IsAny(), + It.IsAny(), + It.IsAny())).ReturnsAsync((responseCode.ToString(), responseCode)); + + ProcessReconciliationTransactionResponse response = await this.TransactionDomainService.ProcessReconciliationTransaction(TestData.TransactionId, + TestData.EstateId, + TestData.MerchantId, + TestData.DeviceIdentifier, + TestData.TransactionDateTime, + TestData.ReconciliationTransactionCount, + TestData.ReconciliationTransactionValue, + CancellationToken.None); + ; response.EstateId.ShouldBe(TestData.EstateId); response.MerchantId.ShouldBe(TestData.MerchantId); - response.ResponseCode.ShouldNotBe("0000"); - response.ResponseMessage.ShouldNotBe("SUCCESS"); + response.ResponseCode.ShouldBe(((Int32)responseCode).ToString().PadLeft(4, '0')); response.TransactionId.ShouldBe(TestData.TransactionId); } [Fact] - public async Task TransactionDomainService_ProcessSaleTransaction_DeclinedByOperator_TransactionIsProcessed() { - this.securityServiceClient.Setup(s => s.GetToken(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(TestData.TokenResponse); + public async Task TransactionDomainService_ProcessSaleTransaction_DeclinedByOperator_TransactionIsProcessed(){ + this.SecurityServiceClient.Setup(s => s.GetToken(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(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())) + 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.transactionAggregateRepository.Setup(t => t.GetLatestVersion(It.IsAny(), It.IsAny())) + this.TransactionAggregateRepository.Setup(t => t.GetLatestVersion(It.IsAny(), It.IsAny())) .ReturnsAsync(TestData.GetEmptyTransactionAggregate); - this.operatorProxy.Setup(o => o.ProcessSaleMessage(It.IsAny(), + this.TransactionValidationService.Setup(t => t.ValidateSaleTransaction(It.IsAny(), + It.IsAny(), + It.IsAny(), + It.IsAny(), + It.IsAny(), + It.IsAny(), + It.IsAny(), + It.IsAny())).ReturnsAsync(("SUCCESS", TransactionResponseCode.Success)); + + this.OperatorProxy.Setup(o => o.ProcessSaleMessage(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny>(), - It.IsAny())).ReturnsAsync(new OperatorResponse { - ResponseMessage = TestData.OperatorResponseMessage, - IsSuccessful = false, - AuthorisationCode = - TestData.OperatorAuthorisationCode, - TransactionId = TestData.OperatorTransactionId, - ResponseCode = TestData.ResponseCode - }); - - this.stateRepository.Setup(p => p.Load(It.IsAny(), It.IsAny(), It.IsAny())) - .ReturnsAsync(TestData.MerchantBalanceProjectionState); - - ProcessSaleTransactionResponse response = await this.transactionDomainService.ProcessSaleTransaction(TestData.TransactionId, - TestData.EstateId, - TestData.MerchantId, - TestData.TransactionDateTime, - TestData.TransactionNumber, - TestData.DeviceIdentifier, - TestData.OperatorIdentifier1, - TestData.CustomerEmailAddress, - TestData - .AdditionalTransactionMetaDataForMobileTopup(), - TestData.ContractId, - TestData.ProductId, - TestData.TransactionSource, - CancellationToken.None); - + It.IsAny())).ReturnsAsync(new OperatorResponse{ + ResponseMessage = TestData.OperatorResponseMessage, + IsSuccessful = false, + AuthorisationCode = + TestData.OperatorAuthorisationCode, + TransactionId = TestData.OperatorTransactionId, + ResponseCode = TestData.ResponseCode + }); + + ProcessSaleTransactionResponse response = await this.TransactionDomainService.ProcessSaleTransaction(TestData.TransactionId, + TestData.EstateId, + TestData.MerchantId, + TestData.TransactionDateTime, + TestData.TransactionNumber, + TestData.DeviceIdentifier, + TestData.OperatorIdentifier1, + TestData.CustomerEmailAddress, + TestData + .AdditionalTransactionMetaDataForMobileTopup(), + TestData.ContractId, + TestData.ProductId, + TestData.TransactionSource, + CancellationToken.None); + response.EstateId.ShouldBe(TestData.EstateId); response.MerchantId.ShouldBe(TestData.MerchantId); - response.ResponseCode.ShouldNotBe("0000"); - response.ResponseMessage.ShouldNotBe("SUCCESS"); + response.ResponseCode.ShouldBe("1008"); response.TransactionId.ShouldBe(TestData.TransactionId); } [Fact] - public async Task TransactionDomainService_ProcessSaleTransaction_EstateValidationFailed_TransactionIsProcessed() { - this.securityServiceClient.Setup(s => s.GetToken(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(TestData.TokenResponse); - - this.estateClient.Setup(e => e.GetEstate(It.IsAny(), It.IsAny(), It.IsAny())) - .ThrowsAsync(new Exception("", new KeyNotFoundException())); - 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); + public async Task TransactionDomainService_ProcessSaleTransaction_ExceptionInOperatorProxy_TransactionIsProcessed(){ + this.SecurityServiceClient.Setup(s => s.GetToken(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(TestData.TokenResponse); - this.transactionAggregateRepository.Setup(t => t.GetLatestVersion(It.IsAny(), It.IsAny())) + this.TransactionAggregateRepository.Setup(t => t.GetLatestVersion(It.IsAny(), It.IsAny())) .ReturnsAsync(TestData.GetEmptyTransactionAggregate); - this.operatorProxy.Setup(o => o.ProcessSaleMessage(It.IsAny(), + this.TransactionValidationService.Setup(t => t.ValidateSaleTransaction(It.IsAny(), + It.IsAny(), + It.IsAny(), + It.IsAny(), + It.IsAny(), + It.IsAny(), + It.IsAny(), + It.IsAny())).ReturnsAsync(("SUCCESS", TransactionResponseCode.Success)); + + this.OperatorProxy.Setup(o => o.ProcessSaleMessage(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny>(), - It.IsAny())).ReturnsAsync(new OperatorResponse { - ResponseMessage = TestData.OperatorResponseMessage, - IsSuccessful = true, - AuthorisationCode = - TestData.OperatorAuthorisationCode, - TransactionId = TestData.OperatorTransactionId, - ResponseCode = TestData.ResponseCode - }); - - this.stateRepository.Setup(p => p.Load(It.IsAny(), It.IsAny(), It.IsAny())) - .ReturnsAsync(TestData.MerchantBalanceProjectionState); - - ProcessSaleTransactionResponse response = await this.transactionDomainService.ProcessSaleTransaction(TestData.TransactionId, - TestData.EstateId, - TestData.MerchantId, - TestData.TransactionDateTime, - TestData.TransactionNumber, - TestData.DeviceIdentifier, - TestData.OperatorIdentifier1, - TestData.CustomerEmailAddress, - TestData - .AdditionalTransactionMetaDataForMobileTopup(), - TestData.ContractId, - TestData.ProductId, - TestData.TransactionSource, - CancellationToken.None); - + It.IsAny())).ThrowsAsync(new Exception()); + + ProcessSaleTransactionResponse response = await this.TransactionDomainService.ProcessSaleTransaction(TestData.TransactionId, + TestData.EstateId, + TestData.MerchantId, + TestData.TransactionDateTime, + TestData.TransactionNumber, + TestData.DeviceIdentifier, + TestData.OperatorIdentifier1, + TestData.CustomerEmailAddress, + TestData + .AdditionalTransactionMetaDataForMobileTopup(), + TestData.ContractId, + TestData.ProductId, + TestData.TransactionSource, + CancellationToken.None); + response.EstateId.ShouldBe(TestData.EstateId); response.MerchantId.ShouldBe(TestData.MerchantId); - response.ResponseCode.ShouldNotBe("0000"); - response.ResponseMessage.ShouldNotBe("SUCCESS"); + response.ResponseCode.ShouldBe("1010"); response.TransactionId.ShouldBe(TestData.TransactionId); } [Fact] - public async Task TransactionDomainService_ProcessSaleTransaction_OperatorProxyThrowsException_TransactionIsProcessed() { - this.securityServiceClient.Setup(s => s.GetToken(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(TestData.TokenResponse); + public async Task TransactionDomainService_ProcessSaleTransaction_NullOperatorResponse_TransactionIsProcessed(){ + this.SecurityServiceClient.Setup(s => s.GetToken(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(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.transactionAggregateRepository.Setup(t => t.GetLatestVersion(It.IsAny(), It.IsAny())) + this.TransactionAggregateRepository.Setup(t => t.GetLatestVersion(It.IsAny(), It.IsAny())) .ReturnsAsync(TestData.GetEmptyTransactionAggregate); - this.operatorProxy.Setup(o => o.ProcessSaleMessage(It.IsAny(), - It.IsAny(), - It.IsAny(), - It.IsAny(), - It.IsAny(), - It.IsAny(), - It.IsAny>(), - It.IsAny())).ThrowsAsync(new Exception("Operator Error")); - - this.stateRepository.Setup(p => p.Load(It.IsAny(), It.IsAny(), It.IsAny())) - .ReturnsAsync(TestData.MerchantBalanceProjectionState); - - ProcessSaleTransactionResponse response = await this.transactionDomainService.ProcessSaleTransaction(TestData.TransactionId, - TestData.EstateId, - TestData.MerchantId, - TestData.TransactionDateTime, - TestData.TransactionNumber, - TestData.DeviceIdentifier, - TestData.OperatorIdentifier1, - TestData.CustomerEmailAddress, - TestData - .AdditionalTransactionMetaDataForMobileTopup(), - TestData.ContractId, - TestData.ProductId, - TestData.TransactionSource, - CancellationToken.None); - + this.TransactionValidationService.Setup(t => t.ValidateSaleTransaction(It.IsAny(), + It.IsAny(), + It.IsAny(), + It.IsAny(), + It.IsAny(), + It.IsAny(), + It.IsAny(), + It.IsAny())).ReturnsAsync(("SUCCESS", TransactionResponseCode.Success)); + + ProcessSaleTransactionResponse response = await this.TransactionDomainService.ProcessSaleTransaction(TestData.TransactionId, + TestData.EstateId, + TestData.MerchantId, + TestData.TransactionDateTime, + TestData.TransactionNumber, + TestData.DeviceIdentifier, + TestData.OperatorIdentifier1, + TestData.CustomerEmailAddress, + TestData + .AdditionalTransactionMetaDataForMobileTopup(), + TestData.ContractId, + TestData.ProductId, + TestData.TransactionSource, + CancellationToken.None); + response.EstateId.ShouldBe(TestData.EstateId); response.MerchantId.ShouldBe(TestData.MerchantId); response.ResponseCode.ShouldBe("1010"); - response.ResponseMessage.ShouldBe("OPERATOR COMMS ERROR"); 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(TestData.TokenResponse); + public async Task TransactionDomainService_ProcessSaleTransaction_TransactionIsProcessed(){ + this.SecurityServiceClient.Setup(s => s.GetToken(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(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())) + 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.transactionAggregateRepository.Setup(t => t.GetLatestVersion(It.IsAny(), It.IsAny())) + this.TransactionAggregateRepository.Setup(t => t.GetLatestVersion(It.IsAny(), It.IsAny())) .ReturnsAsync(TestData.GetEmptyTransactionAggregate); - this.operatorProxy.Setup(o => o.ProcessSaleMessage(It.IsAny(), + this.TransactionValidationService.Setup(t => t.ValidateSaleTransaction(It.IsAny(), + It.IsAny(), + It.IsAny(), + It.IsAny(), + It.IsAny(), + It.IsAny(), + It.IsAny(), + It.IsAny())).ReturnsAsync(("SUCCESS", TransactionResponseCode.Success)); + + this.OperatorProxy.Setup(o => o.ProcessSaleMessage(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny>(), - It.IsAny())).ReturnsAsync(new OperatorResponse { - ResponseMessage = TestData.OperatorResponseMessage, - IsSuccessful = true, - AuthorisationCode = - TestData.OperatorAuthorisationCode, - TransactionId = TestData.OperatorTransactionId, - ResponseCode = TestData.ResponseCode - }); - - this.stateRepository.Setup(p => p.Load(It.IsAny(), It.IsAny(), It.IsAny())) - .ReturnsAsync(TestData.MerchantBalanceProjectionState); - - ProcessSaleTransactionResponse response = await this.transactionDomainService.ProcessSaleTransaction(TestData.TransactionId, - TestData.EstateId, - TestData.MerchantId, - TestData.TransactionDateTime, - TestData.TransactionNumber, - TestData.DeviceIdentifier, - TestData.OperatorIdentifier1, - TestData.CustomerEmailAddress, - TestData - .AdditionalTransactionMetaDataForMobileTopup(), - TestData.ContractId, - TestData.ProductId, - TestData.TransactionSource, - CancellationToken.None); - + It.IsAny())).ReturnsAsync(new OperatorResponse{ + ResponseMessage = TestData.OperatorResponseMessage, + IsSuccessful = true, + AuthorisationCode = + TestData.OperatorAuthorisationCode, + TransactionId = TestData.OperatorTransactionId, + ResponseCode = TestData.ResponseCode + }); + + ProcessSaleTransactionResponse response = await this.TransactionDomainService.ProcessSaleTransaction(TestData.TransactionId, + TestData.EstateId, + TestData.MerchantId, + TestData.TransactionDateTime, + TestData.TransactionNumber, + TestData.DeviceIdentifier, + TestData.OperatorIdentifier1, + TestData.CustomerEmailAddress, + TestData + .AdditionalTransactionMetaDataForMobileTopup(), + TestData.ContractId, + TestData.ProductId, + TestData.TransactionSource, + CancellationToken.None); + response.EstateId.ShouldBe(TestData.EstateId); response.MerchantId.ShouldBe(TestData.MerchantId); response.ResponseCode.ShouldBe("0000"); - response.ResponseMessage.ShouldBe("SUCCESS"); response.TransactionId.ShouldBe(TestData.TransactionId); } - - [Fact] - public async Task TransactionDomainService_ResendTransactionReceipt_TransactionReceiptResendIsRequested() { - this.transactionAggregateRepository.Setup(t => t.GetLatestVersion(It.IsAny(), It.IsAny())) - .ReturnsAsync(TestData.GetCompletedAuthorisedSaleTransactionWithReceiptRequestedAggregate); - - Should.NotThrow(async () => { - await this.transactionDomainService.ResendTransactionReceipt(TestData.TransactionId, TestData.EstateId, CancellationToken.None); - }); - } - - [Fact] - public async Task TransactionDomainService_ValidateLogonTransaction_DeviceNotRegisteredToMerchant_ResponseIsInvalidDeviceIdentifier() { - this.securityServiceClient.Setup(s => s.GetToken(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(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); - - (String responseMessage, TransactionResponseCode responseCode) response = - await this.transactionDomainService.ValidateLogonTransaction(TestData.EstateId, TestData.MerchantId, TestData.DeviceIdentifier1, CancellationToken.None); - - response.responseCode.ShouldBe(TransactionResponseCode.InvalidDeviceIdentifier); - } - - [Fact] - public async Task TransactionDomainService_ValidateLogonTransaction_EstateClientGetEstateThrewOtherException_ResponseIsUnknownFailure() { - this.securityServiceClient.Setup(s => s.GetToken(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(TestData.TokenResponse); - - this.estateClient.Setup(e => e.GetEstate(It.IsAny(), It.IsAny(), It.IsAny())).ThrowsAsync(new Exception("Exception")); - - (String responseMessage, TransactionResponseCode responseCode) response = - await this.transactionDomainService.ValidateLogonTransaction(TestData.EstateId, TestData.MerchantId, TestData.DeviceIdentifier, CancellationToken.None); - - response.responseCode.ShouldBe(TransactionResponseCode.UnknownFailure); - } - - [Fact] - public async Task TransactionDomainService_ValidateLogonTransaction_EstateClientGetMerchantThrewOtherException_ResponseIsUnknownFailure() { - this.securityServiceClient.Setup(s => s.GetToken(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(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())) - .ThrowsAsync(new Exception("Exception")); - - (String responseMessage, TransactionResponseCode responseCode) response = - await this.transactionDomainService.ValidateLogonTransaction(TestData.EstateId, TestData.MerchantId, TestData.DeviceIdentifier, CancellationToken.None); - - response.responseCode.ShouldBe(TransactionResponseCode.UnknownFailure); - } - - [Fact] - public async Task TransactionDomainService_ValidateLogonTransaction_EstateNotFound_ResponseIsInvalidEstateId() { - this.securityServiceClient.Setup(s => s.GetToken(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(TestData.TokenResponse); - - this.estateClient.Setup(e => e.GetEstate(It.IsAny(), It.IsAny(), It.IsAny())) - .ThrowsAsync(new Exception("Exception", new KeyNotFoundException("Invalid Estate"))); - - (String responseMessage, TransactionResponseCode responseCode) response = - await this.transactionDomainService.ValidateLogonTransaction(TestData.EstateId, TestData.MerchantId, TestData.DeviceIdentifier, CancellationToken.None); - - response.responseCode.ShouldBe(TransactionResponseCode.InvalidEstateId); - } - - [Fact] - public async Task TransactionDomainService_ValidateLogonTransaction_MerchantDeviceListEmpty_SuccessfulLogon() { - this.securityServiceClient.Setup(s => s.GetToken(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(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.GetMerchantResponseWithNoDevices); - - (String responseMessage, TransactionResponseCode responseCode) response = - await this.transactionDomainService.ValidateLogonTransaction(TestData.EstateId, TestData.MerchantId, TestData.DeviceIdentifier, CancellationToken.None); - - response.responseCode.ShouldBe(TransactionResponseCode.Success); - this.estateClient.Verify(vf => vf.AddDeviceToMerchant(It.IsAny(), - It.IsAny(), - It.IsAny(), - It.IsAny(), - It.IsAny()), - Times.Once); - } - - [Fact] - public async Task TransactionDomainService_ValidateLogonTransaction_MerchantDeviceListNull_SuccessfulLogon() { - this.securityServiceClient.Setup(s => s.GetToken(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(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); - // TODO: Verify device was added... - - (String responseMessage, TransactionResponseCode responseCode) response = - await this.transactionDomainService.ValidateLogonTransaction(TestData.EstateId, TestData.MerchantId, TestData.DeviceIdentifier, CancellationToken.None); - - response.responseCode.ShouldBe(TransactionResponseCode.Success); - this.estateClient.Verify(vf => vf.AddDeviceToMerchant(It.IsAny(), - It.IsAny(), - It.IsAny(), - It.IsAny(), - It.IsAny()), - Times.Once); - } - - [Fact] - public async Task TransactionDomainService_ValidateLogonTransaction_MerchantNotFound_ResponseIsInvalidMerchantId() { - this.securityServiceClient.Setup(s => s.GetToken(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(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())) - .ThrowsAsync(new Exception("Exception", new KeyNotFoundException("Invalid Merchant"))); - - (String responseMessage, TransactionResponseCode responseCode) response = - await this.transactionDomainService.ValidateLogonTransaction(TestData.EstateId, TestData.MerchantId, TestData.DeviceIdentifier, CancellationToken.None); - - response.responseCode.ShouldBe(TransactionResponseCode.InvalidMerchantId); - } - - [Fact] - public async Task TransactionDomainService_ValidateLogonTransaction_SuccessfulLogon() { - this.securityServiceClient.Setup(s => s.GetToken(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(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); - - (String responseMessage, TransactionResponseCode responseCode) response = - await this.transactionDomainService.ValidateLogonTransaction(TestData.EstateId, TestData.MerchantId, TestData.DeviceIdentifier, CancellationToken.None); - - response.responseCode.ShouldBe(TransactionResponseCode.Success); - } - - [Fact] - public async Task TransactionDomainService_ValidateReconciliationTransaction_DeviceNotRegisteredToMerchant_ResponseIsInvalidDeviceIdentifier() { - this.securityServiceClient.Setup(s => s.GetToken(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(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); - - (String responseMessage, TransactionResponseCode responseCode) response = - await this.transactionDomainService.ValidateReconciliationTransaction(TestData.EstateId, - TestData.MerchantId, - TestData.DeviceIdentifier1, - CancellationToken.None); - - response.responseCode.ShouldBe(TransactionResponseCode.InvalidDeviceIdentifier); - } - - [Fact] - public async Task TransactionDomainService_ValidateReconciliationTransaction_EstateClientGetEstateThrewOtherException_ResponseIsUnknownFailure() { - this.securityServiceClient.Setup(s => s.GetToken(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(TestData.TokenResponse); - - this.estateClient.Setup(e => e.GetEstate(It.IsAny(), It.IsAny(), It.IsAny())).ThrowsAsync(new Exception("Exception")); - - (String responseMessage, TransactionResponseCode responseCode) response = - await this.transactionDomainService.ValidateReconciliationTransaction(TestData.EstateId, - TestData.MerchantId, - TestData.DeviceIdentifier, - CancellationToken.None); - - response.responseCode.ShouldBe(TransactionResponseCode.UnknownFailure); - } - - [Fact] - public async Task TransactionDomainService_ValidateReconciliationTransaction_EstateClientGetMerchantThrewOtherException_ResponseIsUnknownFailure() { - this.securityServiceClient.Setup(s => s.GetToken(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(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())) - .ThrowsAsync(new Exception("Exception")); - - (String responseMessage, TransactionResponseCode responseCode) response = - await this.transactionDomainService.ValidateReconciliationTransaction(TestData.EstateId, - TestData.MerchantId, - TestData.DeviceIdentifier, - CancellationToken.None); - - response.responseCode.ShouldBe(TransactionResponseCode.UnknownFailure); - } - - [Fact] - public async Task TransactionDomainService_ValidateReconciliationTransaction_EstateNotFound_ResponseIsInvalidEstateId() { - this.securityServiceClient.Setup(s => s.GetToken(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(TestData.TokenResponse); - - this.estateClient.Setup(e => e.GetEstate(It.IsAny(), It.IsAny(), It.IsAny())) - .ThrowsAsync(new Exception("Exception", new KeyNotFoundException("Invalid Estate"))); - - (String responseMessage, TransactionResponseCode responseCode) response = - await this.transactionDomainService.ValidateReconciliationTransaction(TestData.EstateId, - TestData.MerchantId, - TestData.DeviceIdentifier, - CancellationToken.None); - - response.responseCode.ShouldBe(TransactionResponseCode.InvalidEstateId); - } - - [Fact] - public async Task TransactionDomainService_ValidateReconciliationTransaction_MerchantDeviceListEmpty_ResponseIsResponseIsNoValidDevices() { - this.securityServiceClient.Setup(s => s.GetToken(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(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.GetMerchantResponseWithNoDevices); - - (String responseMessage, TransactionResponseCode responseCode) response = - await this.transactionDomainService.ValidateReconciliationTransaction(TestData.EstateId, - TestData.MerchantId, - TestData.DeviceIdentifier, - CancellationToken.None); - - response.responseCode.ShouldBe(TransactionResponseCode.NoValidDevices); - } - - [Fact] - public async Task TransactionDomainService_ValidateReconciliationTransaction_MerchantDeviceListNull_ResponseIsResponseIsNoValidDevices() { - this.securityServiceClient.Setup(s => s.GetToken(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(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); - - (String responseMessage, TransactionResponseCode responseCode) response = - await this.transactionDomainService.ValidateReconciliationTransaction(TestData.EstateId, - TestData.MerchantId, - TestData.DeviceIdentifier, - CancellationToken.None); - - response.responseCode.ShouldBe(TransactionResponseCode.NoValidDevices); - } - - [Fact] - public async Task TransactionDomainService_ValidateReconciliationTransaction_MerchantNotFound_ResponseIsInvalidMerchantId() { - this.securityServiceClient.Setup(s => s.GetToken(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(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())) - .ThrowsAsync(new Exception("Exception", new KeyNotFoundException("Invalid Merchant"))); - - (String responseMessage, TransactionResponseCode responseCode) response = - await this.transactionDomainService.ValidateReconciliationTransaction(TestData.EstateId, - TestData.MerchantId, - TestData.DeviceIdentifier, - CancellationToken.None); - - response.responseCode.ShouldBe(TransactionResponseCode.InvalidMerchantId); - } - - [Fact] - public async Task TransactionDomainService_ValidateReconciliationTransaction_SuccessfulReconciliation() { - this.securityServiceClient.Setup(s => s.GetToken(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(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); - - (String responseMessage, TransactionResponseCode responseCode) response = - await this.transactionDomainService.ValidateReconciliationTransaction(TestData.EstateId, - TestData.MerchantId, - TestData.DeviceIdentifier, - CancellationToken.None); - - response.responseCode.ShouldBe(TransactionResponseCode.Success); - } - - [Fact] - public async Task TransactionDomainService_ValidateSaleTransaction_DeviceNotRegisteredToMerchant_ResponseIsInvalidDeviceIdentifier() { - this.securityServiceClient.Setup(s => s.GetToken(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(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); - - (String responseMessage, TransactionResponseCode responseCode) response = await this.transactionDomainService.ValidateSaleTransaction(TestData.EstateId, - TestData.MerchantId, - TestData.ContractId, - TestData.ProductId, - TestData.DeviceIdentifier1, - TestData.OperatorIdentifier1, - TestData.TransactionAmount, - CancellationToken.None); - - response.responseCode.ShouldBe(TransactionResponseCode.InvalidDeviceIdentifier); - } - - [Fact] - public async Task TransactionDomainService_ValidateSaleTransaction_EstateClientGetEstateThrewOtherException_ResponseIsUnknownFailure() { - this.securityServiceClient.Setup(s => s.GetToken(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(TestData.TokenResponse); - - this.estateClient.Setup(e => e.GetEstate(It.IsAny(), It.IsAny(), It.IsAny())).ThrowsAsync(new Exception("Exception")); - - (String responseMessage, TransactionResponseCode responseCode) response = await this.transactionDomainService.ValidateSaleTransaction(TestData.EstateId, - TestData.MerchantId, - TestData.ContractId, - TestData.ProductId, - TestData.DeviceIdentifier, - TestData.OperatorIdentifier1, - TestData.TransactionAmount, - CancellationToken.None); - - response.responseCode.ShouldBe(TransactionResponseCode.UnknownFailure); - } - - [Fact] - public async Task TransactionDomainService_ValidateSaleTransaction_EstateClientGetMerchantThrewOtherException_ResponseIsUnknownFailure() { - this.securityServiceClient.Setup(s => s.GetToken(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(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())) - .ThrowsAsync(new Exception("Exception")); - - (String responseMessage, TransactionResponseCode responseCode) response = await this.transactionDomainService.ValidateSaleTransaction(TestData.EstateId, - TestData.MerchantId, - TestData.ContractId, - TestData.ProductId, - TestData.DeviceIdentifier, - TestData.OperatorIdentifier1, - TestData.TransactionAmount, - CancellationToken.None); - - response.responseCode.ShouldBe(TransactionResponseCode.UnknownFailure); - } - - [Fact] - public async Task TransactionDomainService_ValidateSaleTransaction_EstateClientThrownOtherExceptionFoundOnGetContract_ResponseIsUnknownFailure() { - this.securityServiceClient.Setup(s => s.GetToken(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(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())) - .ThrowsAsync(new Exception("Exception")); - - this.stateRepository.Setup(p => p.Load(It.IsAny(), It.IsAny(), It.IsAny())) - .ReturnsAsync(TestData.MerchantBalanceProjectionState); - - (String responseMessage, TransactionResponseCode responseCode) response = await this.transactionDomainService.ValidateSaleTransaction(TestData.EstateId, - TestData.MerchantId, - TestData.ContractId, - TestData.ProductId, - TestData.DeviceIdentifier, - TestData.OperatorIdentifier1, - TestData.TransactionAmount, - CancellationToken.None); - - response.responseCode.ShouldBe(TransactionResponseCode.UnknownFailure); - } - - [Fact] - public async Task TransactionDomainService_ValidateSaleTransaction_EstateFoundButHasNoOperators_ResponseIsInvalidEstateId() { - this.securityServiceClient.Setup(s => s.GetToken(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(TestData.TokenResponse); - - this.estateClient.Setup(e => e.GetEstate(It.IsAny(), It.IsAny(), It.IsAny())) - .ReturnsAsync(TestData.GetEstateResponseWithEmptyOperators); - - (String responseMessage, TransactionResponseCode responseCode) response = await this.transactionDomainService.ValidateSaleTransaction(TestData.EstateId, - TestData.MerchantId, - TestData.ContractId, - TestData.ProductId, - TestData.DeviceIdentifier, - TestData.OperatorIdentifier1, - TestData.TransactionAmount, - CancellationToken.None); - - response.responseCode.ShouldBe(TransactionResponseCode.NoEstateOperators); - } - - [Fact] - public async Task TransactionDomainService_ValidateSaleTransaction_EstateFoundButHasNullOperators_ResponseIsInvalidEstateId() { - this.securityServiceClient.Setup(s => s.GetToken(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(TestData.TokenResponse); - - this.estateClient.Setup(e => e.GetEstate(It.IsAny(), It.IsAny(), It.IsAny())) - .ReturnsAsync(TestData.GetEstateResponseWithNullOperators); - - (String responseMessage, TransactionResponseCode responseCode) response = await this.transactionDomainService.ValidateSaleTransaction(TestData.EstateId, - TestData.MerchantId, - TestData.ContractId, - TestData.ProductId, - TestData.DeviceIdentifier, - TestData.OperatorIdentifier1, - TestData.TransactionAmount, - CancellationToken.None); - - response.responseCode.ShouldBe(TransactionResponseCode.NoEstateOperators); - } - - [Fact] - public async Task TransactionDomainService_ValidateSaleTransaction_EstateFoundOperatorsNotConfiguredForEstate_ResponseIsOperatorNotValidForEstate() { - this.securityServiceClient.Setup(s => s.GetToken(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(TestData.TokenResponse); - - this.estateClient.Setup(e => e.GetEstate(It.IsAny(), It.IsAny(), It.IsAny())) - .ReturnsAsync(TestData.GetEstateResponseWithOperator1); - - (String responseMessage, TransactionResponseCode responseCode) response = await this.transactionDomainService.ValidateSaleTransaction(TestData.EstateId, - TestData.MerchantId, - TestData.ContractId, - TestData.ProductId, - TestData.DeviceIdentifier, - TestData.OperatorIdentifier2, - TestData.TransactionAmount, - CancellationToken.None); - - response.responseCode.ShouldBe(TransactionResponseCode.OperatorNotValidForEstate); - } - - [Fact] - public async Task TransactionDomainService_ValidateSaleTransaction_EstateNotFound_ResponseIsInvalidEstateId() { - this.securityServiceClient.Setup(s => s.GetToken(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(TestData.TokenResponse); - - this.estateClient.Setup(e => e.GetEstate(It.IsAny(), It.IsAny(), It.IsAny())) - .ThrowsAsync(new Exception("Exception", new KeyNotFoundException("Invalid Estate"))); - - (String responseMessage, TransactionResponseCode responseCode) response = await this.transactionDomainService.ValidateSaleTransaction(TestData.EstateId, - TestData.MerchantId, - TestData.ContractId, - TestData.ProductId, - TestData.DeviceIdentifier, - TestData.OperatorIdentifier1, - TestData.TransactionAmount, - CancellationToken.None); - - response.responseCode.ShouldBe(TransactionResponseCode.InvalidEstateId); - } - - [Fact] - public async Task TransactionDomainService_ValidateSaleTransaction_InvalidContractId_ResponseIsInvalidContractIdValue() { - this.securityServiceClient.Setup(s => s.GetToken(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(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.stateRepository.Setup(p => p.Load(It.IsAny(), It.IsAny(), It.IsAny())) - .ReturnsAsync(TestData.MerchantBalanceProjectionState); - - (String responseMessage, TransactionResponseCode responseCode) response = await this.transactionDomainService.ValidateSaleTransaction(TestData.EstateId, - TestData.MerchantId, - Guid.Empty, - TestData.ProductId, - TestData.DeviceIdentifier, - TestData.OperatorIdentifier1, - TestData.TransactionAmount, - CancellationToken.None); - - response.responseCode.ShouldBe(TransactionResponseCode.InvalidContractIdValue); - } - - [Fact] - public async Task TransactionDomainService_ValidateSaleTransaction_InvalidProductId_ResponseIsInvalidProductIdValue() { - this.securityServiceClient.Setup(s => s.GetToken(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(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.stateRepository.Setup(p => p.Load(It.IsAny(), It.IsAny(), It.IsAny())) - .ReturnsAsync(TestData.MerchantBalanceProjectionState); - - (String responseMessage, TransactionResponseCode responseCode) response = await this.transactionDomainService.ValidateSaleTransaction(TestData.EstateId, - TestData.MerchantId, - TestData.ContractId, - Guid.Empty, - TestData.DeviceIdentifier, - TestData.OperatorIdentifier1, - TestData.TransactionAmount, - CancellationToken.None); - - response.responseCode.ShouldBe(TransactionResponseCode.InvalidProductIdValue); - } [Theory] - [InlineData(0)] - [InlineData(-1)] - public async Task TransactionDomainService_ValidateSaleTransaction_InvalidTransactionAmount_ResponseIsInvalidSaleTransactionAmount(Decimal transactionAmount) { - this.securityServiceClient.Setup(s => s.GetToken(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(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); - - (String responseMessage, TransactionResponseCode responseCode) response = await this.transactionDomainService.ValidateSaleTransaction(TestData.EstateId, - TestData.MerchantId, - TestData.ContractId, - TestData.ProductId, - TestData.DeviceIdentifier, - TestData.OperatorIdentifier1, - transactionAmount, - CancellationToken.None); - - response.responseCode.ShouldBe(TransactionResponseCode.InvalidSaleTransactionAmount); - } - - [Fact] - public async Task TransactionDomainService_ValidateSaleTransaction_MerchantDeviceListEmpty_ResponseIsNoValidDevices() { - this.securityServiceClient.Setup(s => s.GetToken(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(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.GetMerchantResponseWithNoDevices); - - (String responseMessage, TransactionResponseCode responseCode) response = await this.transactionDomainService.ValidateSaleTransaction(TestData.EstateId, - TestData.MerchantId, - TestData.ContractId, - TestData.ProductId, - TestData.DeviceIdentifier1, - TestData.OperatorIdentifier1, - TestData.TransactionAmount, - CancellationToken.None); - - response.responseCode.ShouldBe(TransactionResponseCode.NoValidDevices); - } - - [Fact] - public async Task TransactionDomainService_ValidateSaleTransaction_MerchantDeviceListNull_ResponseIsNoValidDevices() { - this.securityServiceClient.Setup(s => s.GetToken(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(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); - - (String responseMessage, TransactionResponseCode responseCode) response = await this.transactionDomainService.ValidateSaleTransaction(TestData.EstateId, - TestData.MerchantId, - TestData.ContractId, - TestData.ProductId, - TestData.DeviceIdentifier1, - TestData.OperatorIdentifier1, - TestData.TransactionAmount, - CancellationToken.None); - - response.responseCode.ShouldBe(TransactionResponseCode.NoValidDevices); - } - - [Fact] - public async Task TransactionDomainService_ValidateSaleTransaction_MerchantDoesNotHaveSuppliedContract_ResponseIsContractNotValidForMerchant() { - this.securityServiceClient.Setup(s => s.GetToken(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(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.stateRepository.Setup(p => p.Load(It.IsAny(), It.IsAny(), It.IsAny())) - .ReturnsAsync(TestData.MerchantBalanceProjectionState); - - (String responseMessage, TransactionResponseCode responseCode) response = await this.transactionDomainService.ValidateSaleTransaction(TestData.EstateId, - TestData.MerchantId, - TestData.ContractId1, - TestData.ProductId, - TestData.DeviceIdentifier, - TestData.OperatorIdentifier1, - TestData.TransactionAmount, - CancellationToken.None); - - response.responseCode.ShouldBe(TransactionResponseCode.ContractNotValidForMerchant); - } - - [Fact] - public async Task TransactionDomainService_ValidateSaleTransaction_MerchantHasNoContracts_ResponseIsMerchantDoesNotHaveEnoughCredit() { - this.securityServiceClient.Setup(s => s.GetToken(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(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(new List()); - - this.stateRepository.Setup(p => p.Load(It.IsAny(), It.IsAny(), It.IsAny())) - .ReturnsAsync(TestData.MerchantBalanceProjectionState); - - (String responseMessage, TransactionResponseCode responseCode) response = await this.transactionDomainService.ValidateSaleTransaction(TestData.EstateId, - TestData.MerchantId, - TestData.ContractId, - TestData.ProductId, - TestData.DeviceIdentifier, - TestData.OperatorIdentifier1, - TestData.TransactionAmount, - CancellationToken.None); - - response.responseCode.ShouldBe(TransactionResponseCode.MerchantHasNoContractsConfigured); - } - - [Fact] - public async Task TransactionDomainService_ValidateSaleTransaction_MerchantHasNullContracts_ResponseIsMerchantDoesNotHaveEnoughCredit() { - this.securityServiceClient.Setup(s => s.GetToken(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(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); - List contracts = null; - this.estateClient.Setup(e => e.GetMerchantContracts(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) - .ReturnsAsync(contracts); - - this.stateRepository.Setup(p => p.Load(It.IsAny(), It.IsAny(), It.IsAny())) - .ReturnsAsync(TestData.MerchantBalanceProjectionState); - - (String responseMessage, TransactionResponseCode responseCode) response = await this.transactionDomainService.ValidateSaleTransaction(TestData.EstateId, - TestData.MerchantId, - TestData.ContractId, - TestData.ProductId, - TestData.DeviceIdentifier, - TestData.OperatorIdentifier1, - TestData.TransactionAmount, - CancellationToken.None); - - response.responseCode.ShouldBe(TransactionResponseCode.MerchantHasNoContractsConfigured); - } - - [Fact] - public async Task TransactionDomainService_ValidateSaleTransaction_MerchantNotEnoughCredit_ResponseIsMerchantDoesNotHaveEnoughCredit() { - this.securityServiceClient.Setup(s => s.GetToken(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(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.stateRepository.Setup(p => p.Load(It.IsAny(), It.IsAny(), It.IsAny())) - .ReturnsAsync(TestData.MerchantBalanceProjectionStateNoCredit); - - (String responseMessage, TransactionResponseCode responseCode) response = await this.transactionDomainService.ValidateSaleTransaction(TestData.EstateId, - TestData.MerchantId, - TestData.ContractId, - TestData.ProductId, - TestData.DeviceIdentifier, - TestData.OperatorIdentifier1, - TestData.TransactionAmount, - CancellationToken.None); - - response.responseCode.ShouldBe(TransactionResponseCode.MerchantDoesNotHaveEnoughCredit); - } - - [Fact] - public async Task TransactionDomainService_ValidateSaleTransaction_MerchantNotFound_ResponseIsInvalidMerchantId() { - this.securityServiceClient.Setup(s => s.GetToken(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(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())) - .ThrowsAsync(new Exception("Exception", new KeyNotFoundException("Invalid Merchant"))); - - (String responseMessage, TransactionResponseCode responseCode) response = await this.transactionDomainService.ValidateSaleTransaction(TestData.EstateId, - TestData.MerchantId, - TestData.ContractId, - TestData.ProductId, - TestData.DeviceIdentifier, - TestData.OperatorIdentifier1, - TestData.TransactionAmount, - CancellationToken.None); - - response.responseCode.ShouldBe(TransactionResponseCode.InvalidMerchantId); - } - - [Fact] - public async Task TransactionDomainService_ValidateSaleTransaction_MerchantNotFoundOnGetContract_ResponseIsInvalidMerchantId() { - this.securityServiceClient.Setup(s => s.GetToken(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(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())) - .ThrowsAsync(new Exception("Exception", new KeyNotFoundException("Invalid Merchant"))); - - this.stateRepository.Setup(p => p.Load(It.IsAny(), It.IsAny(), It.IsAny())) - .ReturnsAsync(TestData.MerchantBalanceProjectionState); - - (String responseMessage, TransactionResponseCode responseCode) response = await this.transactionDomainService.ValidateSaleTransaction(TestData.EstateId, - TestData.MerchantId, - TestData.ContractId, - TestData.ProductId, - TestData.DeviceIdentifier, - TestData.OperatorIdentifier1, - TestData.TransactionAmount, - CancellationToken.None); - - response.responseCode.ShouldBe(TransactionResponseCode.InvalidMerchantId); - } - - [Fact] - public async Task TransactionDomainService_ValidateSaleTransaction_MerchantOperatorListEmpty_ResponseIsNoMerchantOperators() { - this.securityServiceClient.Setup(s => s.GetToken(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(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); - - (String responseMessage, TransactionResponseCode responseCode) response = await this.transactionDomainService.ValidateSaleTransaction(TestData.EstateId, - TestData.MerchantId, - TestData.ContractId, - TestData.ProductId, - TestData.DeviceIdentifier, - TestData.OperatorIdentifier1, - TestData.TransactionAmount, - CancellationToken.None); - - response.responseCode.ShouldBe(TransactionResponseCode.NoMerchantOperators); - } - - [Fact] - public async Task TransactionDomainService_ValidateSaleTransaction_MerchantOperatorListNull_ResponseIsNoMerchantOperators() { - this.securityServiceClient.Setup(s => s.GetToken(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(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); - - (String responseMessage, TransactionResponseCode responseCode) response = await this.transactionDomainService.ValidateSaleTransaction(TestData.EstateId, - TestData.MerchantId, - TestData.ContractId, - TestData.ProductId, - TestData.DeviceIdentifier, - TestData.OperatorIdentifier1, - TestData.TransactionAmount, - CancellationToken.None); - - response.responseCode.ShouldBe(TransactionResponseCode.NoMerchantOperators); - } + [InlineData(TransactionResponseCode.InvalidEstateId)] + [InlineData(TransactionResponseCode.InvalidContractIdValue)] + [InlineData(TransactionResponseCode.InvalidProductIdValue)] + [InlineData(TransactionResponseCode.ContractNotValidForMerchant)] + [InlineData(TransactionResponseCode.ProductNotValidForMerchant)] + public async Task TransactionDomainService_ProcessSaleTransaction_ValidationFailed_TransactionIsProcessed(TransactionResponseCode responseCode){ + this.TransactionAggregateRepository.Setup(t => t.GetLatestVersion(It.IsAny(), It.IsAny())) + .ReturnsAsync(TestData.GetEmptyTransactionAggregate); - [Fact] - public async Task TransactionDomainService_ValidateSaleTransaction_OperatorNotConfiguredFroMerchant_ResponseIsOperatorNotValidForMerchant() { - this.securityServiceClient.Setup(s => s.GetToken(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(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); - - (String responseMessage, TransactionResponseCode responseCode) response = await this.transactionDomainService.ValidateSaleTransaction(TestData.EstateId, - TestData.MerchantId, - TestData.ContractId, - TestData.ProductId, - TestData.DeviceIdentifier, - TestData.OperatorIdentifier1, - TestData.TransactionAmount, - CancellationToken.None); - - response.responseCode.ShouldBe(TransactionResponseCode.OperatorNotValidForMerchant); - } + this.TransactionValidationService.Setup(t => t.ValidateSaleTransaction(It.IsAny(), + It.IsAny(), + It.IsAny(), + It.IsAny(), + It.IsAny(), + It.IsAny(), + It.IsAny(), + It.IsAny())).ReturnsAsync((responseCode.ToString(), responseCode)); + + ProcessSaleTransactionResponse response = await this.TransactionDomainService.ProcessSaleTransaction(TestData.TransactionId, + TestData.EstateId, + TestData.MerchantId, + TestData.TransactionDateTime, + TestData.TransactionNumber, + TestData.DeviceIdentifier, + TestData.OperatorIdentifier1, + TestData.CustomerEmailAddress, + TestData + .AdditionalTransactionMetaDataForMobileTopup(), + TestData.ContractId, + TestData.ProductId, + TestData.TransactionSource, + CancellationToken.None); - [Fact] - public async Task TransactionDomainService_ValidateSaleTransaction_ProductIdNotConfigured_ResponseIsProductNotValidForMerchant() { - this.securityServiceClient.Setup(s => s.GetToken(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(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.stateRepository.Setup(p => p.Load(It.IsAny(), It.IsAny(), It.IsAny())) - .ReturnsAsync(TestData.MerchantBalanceProjectionState); - - (String responseMessage, TransactionResponseCode responseCode) response = await this.transactionDomainService.ValidateSaleTransaction(TestData.EstateId, - TestData.MerchantId, - TestData.ContractId, - TestData.ProductId1, - TestData.DeviceIdentifier, - TestData.OperatorIdentifier1, - TestData.TransactionAmount, - CancellationToken.None); - - response.responseCode.ShouldBe(TransactionResponseCode.ProductNotValidForMerchant); + response.EstateId.ShouldBe(TestData.EstateId); + response.MerchantId.ShouldBe(TestData.MerchantId); + response.ResponseCode.ShouldBe(((Int32)responseCode).ToString().PadLeft(4, '0')); + response.TransactionId.ShouldBe(TestData.TransactionId); } [Fact] - public async Task TransactionDomainService_ValidateSaleTransaction_SuccessfulSale() { - this.securityServiceClient.Setup(s => s.GetToken(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(TestData.TokenResponse); + public async Task TransactionDomainService_ResendTransactionReceipt_TransactionReceiptResendIsRequested(){ + this.TransactionAggregateRepository.Setup(t => t.GetLatestVersion(It.IsAny(), It.IsAny())) + .ReturnsAsync(TestData.GetCompletedAuthorisedSaleTransactionWithReceiptRequestedAggregate); - 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.stateRepository.Setup(s => s.Load(It.IsAny(), It.IsAny(), It.IsAny())) - .ReturnsAsync(TestData.MerchantBalanceProjectionState); - - (String responseMessage, TransactionResponseCode responseCode) response = await this.transactionDomainService.ValidateSaleTransaction(TestData.EstateId, - TestData.MerchantId, - TestData.ContractId, - TestData.ProductId, - TestData.DeviceIdentifier, - TestData.OperatorIdentifier1, - TestData.TransactionAmount, - CancellationToken.None); - - response.responseCode.ShouldBe(TransactionResponseCode.Success); + Should.NotThrow(async () => { await this.TransactionDomainService.ResendTransactionReceipt(TestData.TransactionId, TestData.EstateId, CancellationToken.None); }); } #endregion diff --git a/TransactionProcessor.BusinessLogic.Tests/Services/TransactionValidationServiceTests.cs b/TransactionProcessor.BusinessLogic.Tests/Services/TransactionValidationServiceTests.cs new file mode 100644 index 00000000..6e8ee367 --- /dev/null +++ b/TransactionProcessor.BusinessLogic.Tests/Services/TransactionValidationServiceTests.cs @@ -0,0 +1,839 @@ +namespace TransactionProcessor.BusinessLogic.Tests.Services; + +using System; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using BusinessLogic.Services; +using EstateManagement.Client; +using EstateManagement.DataTransferObjects.Responses; +using Microsoft.Extensions.Configuration; +using Moq; +using ProjectionEngine.Repository; +using ProjectionEngine.State; +using SecurityService.Client; +using Shared.General; +using Shared.Logger; +using Shouldly; +using Testing; +using Xunit; + +public class TransactionValidationServiceTests{ + private readonly TransactionValidationService TransactionValidationService; + private readonly Mock SecurityServiceClient; + + private readonly Mock> StateRepository; + private readonly Mock EstateClient; + + public TransactionValidationServiceTests(){ + 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.TransactionValidationService = new TransactionValidationService(this.EstateClient.Object, + this.SecurityServiceClient.Object, + this.StateRepository.Object); + } + + [Fact] + public async Task TransactionValidationService_ValidateLogonTransaction_DeviceNotRegisteredToMerchant_ResponseIsInvalidDeviceIdentifier() { + this.SecurityServiceClient.Setup(s => s.GetToken(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(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); + + (String responseMessage, TransactionResponseCode responseCode) response = + await this.TransactionValidationService.ValidateLogonTransaction(TestData.EstateId, TestData.MerchantId, TestData.DeviceIdentifier1, CancellationToken.None); + + response.responseCode.ShouldBe(TransactionResponseCode.InvalidDeviceIdentifier); + } + + [Fact] + public async Task TransactionValidationService_ValidateLogonTransaction_EstateClientGetEstateThrewOtherException_ResponseIsUnknownFailure() { + this.SecurityServiceClient.Setup(s => s.GetToken(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(TestData.TokenResponse); + + this.EstateClient.Setup(e => e.GetEstate(It.IsAny(), It.IsAny(), It.IsAny())).ThrowsAsync(new Exception("Exception")); + + (String responseMessage, TransactionResponseCode responseCode) response = + await this.TransactionValidationService.ValidateLogonTransaction(TestData.EstateId, TestData.MerchantId, TestData.DeviceIdentifier, CancellationToken.None); + + response.responseCode.ShouldBe(TransactionResponseCode.UnknownFailure); + } + + [Fact] + public async Task TransactionValidationService_ValidateLogonTransaction_EstateClientGetMerchantThrewOtherException_ResponseIsUnknownFailure() { + this.SecurityServiceClient.Setup(s => s.GetToken(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(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())) + .ThrowsAsync(new Exception("Exception")); + + (String responseMessage, TransactionResponseCode responseCode) response = + await this.TransactionValidationService.ValidateLogonTransaction(TestData.EstateId, TestData.MerchantId, TestData.DeviceIdentifier, CancellationToken.None); + + response.responseCode.ShouldBe(TransactionResponseCode.UnknownFailure); + } + + [Fact] + public async Task TransactionValidationService_ValidateLogonTransaction_EstateNotFound_ResponseIsInvalidEstateId() { + this.SecurityServiceClient.Setup(s => s.GetToken(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(TestData.TokenResponse); + + this.EstateClient.Setup(e => e.GetEstate(It.IsAny(), It.IsAny(), It.IsAny())) + .ThrowsAsync(new Exception("Exception", new KeyNotFoundException("Invalid Estate"))); + + (String responseMessage, TransactionResponseCode responseCode) response = + await this.TransactionValidationService.ValidateLogonTransaction(TestData.EstateId, TestData.MerchantId, TestData.DeviceIdentifier, CancellationToken.None); + + response.responseCode.ShouldBe(TransactionResponseCode.InvalidEstateId); + } + + [Fact] + public async Task TransactionValidationService_ValidateLogonTransaction_MerchantDeviceListEmpty_SuccessfulLogon() { + this.SecurityServiceClient.Setup(s => s.GetToken(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(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.GetMerchantResponseWithNoDevices); + + (String responseMessage, TransactionResponseCode responseCode) response = + await this.TransactionValidationService.ValidateLogonTransaction(TestData.EstateId, TestData.MerchantId, TestData.DeviceIdentifier, CancellationToken.None); + + response.responseCode.ShouldBe(TransactionResponseCode.SuccessNeedToAddDevice); + } + + [Fact] + public async Task TransactionValidationService_ValidateLogonTransaction_MerchantDeviceListNull_SuccessfulLogon() { + this.SecurityServiceClient.Setup(s => s.GetToken(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(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); + // TODO: Verify device was added... + + (String responseMessage, TransactionResponseCode responseCode) response = + await this.TransactionValidationService.ValidateLogonTransaction(TestData.EstateId, TestData.MerchantId, TestData.DeviceIdentifier, CancellationToken.None); + + response.responseCode.ShouldBe(TransactionResponseCode.SuccessNeedToAddDevice); + } + + [Fact] + public async Task TransactionValidationService_ValidateLogonTransaction_MerchantNotFound_ResponseIsInvalidMerchantId() { + this.SecurityServiceClient.Setup(s => s.GetToken(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(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())) + .ThrowsAsync(new Exception("Exception", new KeyNotFoundException("Invalid Merchant"))); + + (String responseMessage, TransactionResponseCode responseCode) response = + await this.TransactionValidationService.ValidateLogonTransaction(TestData.EstateId, TestData.MerchantId, TestData.DeviceIdentifier, CancellationToken.None); + + response.responseCode.ShouldBe(TransactionResponseCode.InvalidMerchantId); + } + + [Fact] + public async Task TransactionValidationService_ValidateLogonTransaction_SuccessfulLogon() { + this.SecurityServiceClient.Setup(s => s.GetToken(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(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); + + (String responseMessage, TransactionResponseCode responseCode) response = + await this.TransactionValidationService.ValidateLogonTransaction(TestData.EstateId, TestData.MerchantId, TestData.DeviceIdentifier, CancellationToken.None); + + response.responseCode.ShouldBe(TransactionResponseCode.Success); + } + + [Fact] + public async Task TransactionValidationService_ValidateReconciliationTransaction_DeviceNotRegisteredToMerchant_ResponseIsInvalidDeviceIdentifier() { + this.SecurityServiceClient.Setup(s => s.GetToken(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(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); + + (String responseMessage, TransactionResponseCode responseCode) response = + await this.TransactionValidationService.ValidateReconciliationTransaction(TestData.EstateId, + TestData.MerchantId, + TestData.DeviceIdentifier1, + CancellationToken.None); + + response.responseCode.ShouldBe(TransactionResponseCode.InvalidDeviceIdentifier); + } + + [Fact] + public async Task TransactionValidationService_ValidateReconciliationTransaction_EstateClientGetEstateThrewOtherException_ResponseIsUnknownFailure() { + this.SecurityServiceClient.Setup(s => s.GetToken(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(TestData.TokenResponse); + + this.EstateClient.Setup(e => e.GetEstate(It.IsAny(), It.IsAny(), It.IsAny())).ThrowsAsync(new Exception("Exception")); + + (String responseMessage, TransactionResponseCode responseCode) response = + await this.TransactionValidationService.ValidateReconciliationTransaction(TestData.EstateId, + TestData.MerchantId, + TestData.DeviceIdentifier, + CancellationToken.None); + + response.responseCode.ShouldBe(TransactionResponseCode.UnknownFailure); + } + + [Fact] + public async Task TransactionValidationService_ValidateReconciliationTransaction_EstateClientGetMerchantThrewOtherException_ResponseIsUnknownFailure() { + this.SecurityServiceClient.Setup(s => s.GetToken(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(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())) + .ThrowsAsync(new Exception("Exception")); + + (String responseMessage, TransactionResponseCode responseCode) response = + await this.TransactionValidationService.ValidateReconciliationTransaction(TestData.EstateId, + TestData.MerchantId, + TestData.DeviceIdentifier, + CancellationToken.None); + + response.responseCode.ShouldBe(TransactionResponseCode.UnknownFailure); + } + + [Fact] + public async Task TransactionValidationService_ValidateReconciliationTransaction_EstateNotFound_ResponseIsInvalidEstateId() { + this.SecurityServiceClient.Setup(s => s.GetToken(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(TestData.TokenResponse); + + this.EstateClient.Setup(e => e.GetEstate(It.IsAny(), It.IsAny(), It.IsAny())) + .ThrowsAsync(new Exception("Exception", new KeyNotFoundException("Invalid Estate"))); + + (String responseMessage, TransactionResponseCode responseCode) response = + await this.TransactionValidationService.ValidateReconciliationTransaction(TestData.EstateId, + TestData.MerchantId, + TestData.DeviceIdentifier, + CancellationToken.None); + + response.responseCode.ShouldBe(TransactionResponseCode.InvalidEstateId); + } + + [Fact] + public async Task TransactionValidationService_ValidateReconciliationTransaction_MerchantDeviceListEmpty_ResponseIsResponseIsNoValidDevices() { + this.SecurityServiceClient.Setup(s => s.GetToken(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(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.GetMerchantResponseWithNoDevices); + + (String responseMessage, TransactionResponseCode responseCode) response = + await this.TransactionValidationService.ValidateReconciliationTransaction(TestData.EstateId, + TestData.MerchantId, + TestData.DeviceIdentifier, + CancellationToken.None); + + response.responseCode.ShouldBe(TransactionResponseCode.NoValidDevices); + } + + [Fact] + public async Task TransactionValidationService_ValidateReconciliationTransaction_MerchantDeviceListNull_ResponseIsResponseIsNoValidDevices() { + this.SecurityServiceClient.Setup(s => s.GetToken(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(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); + + (String responseMessage, TransactionResponseCode responseCode) response = + await this.TransactionValidationService.ValidateReconciliationTransaction(TestData.EstateId, + TestData.MerchantId, + TestData.DeviceIdentifier, + CancellationToken.None); + + response.responseCode.ShouldBe(TransactionResponseCode.NoValidDevices); + } + + [Fact] + public async Task TransactionValidationService_ValidateReconciliationTransaction_MerchantNotFound_ResponseIsInvalidMerchantId() { + this.SecurityServiceClient.Setup(s => s.GetToken(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(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())) + .ThrowsAsync(new Exception("Exception", new KeyNotFoundException("Invalid Merchant"))); + + (String responseMessage, TransactionResponseCode responseCode) response = + await this.TransactionValidationService.ValidateReconciliationTransaction(TestData.EstateId, + TestData.MerchantId, + TestData.DeviceIdentifier, + CancellationToken.None); + + response.responseCode.ShouldBe(TransactionResponseCode.InvalidMerchantId); + } + + [Fact] + public async Task TransactionValidationService_ValidateReconciliationTransaction_SuccessfulReconciliation() { + this.SecurityServiceClient.Setup(s => s.GetToken(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(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); + + (String responseMessage, TransactionResponseCode responseCode) response = + await this.TransactionValidationService.ValidateReconciliationTransaction(TestData.EstateId, + TestData.MerchantId, + TestData.DeviceIdentifier, + CancellationToken.None); + + response.responseCode.ShouldBe(TransactionResponseCode.Success); + } + + [Fact] + public async Task TransactionValidationService_ValidateSaleTransaction_DeviceNotRegisteredToMerchant_ResponseIsInvalidDeviceIdentifier() { + this.SecurityServiceClient.Setup(s => s.GetToken(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(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); + + (String responseMessage, TransactionResponseCode responseCode) response = await this.TransactionValidationService.ValidateSaleTransaction(TestData.EstateId, + TestData.MerchantId, + TestData.ContractId, + TestData.ProductId, + TestData.DeviceIdentifier1, + TestData.OperatorIdentifier1, + TestData.TransactionAmount, + CancellationToken.None); + + response.responseCode.ShouldBe(TransactionResponseCode.InvalidDeviceIdentifier); + } + + [Fact] + public async Task TransactionValidationService_ValidateSaleTransaction_EstateClientGetEstateThrewOtherException_ResponseIsUnknownFailure() { + this.SecurityServiceClient.Setup(s => s.GetToken(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(TestData.TokenResponse); + + this.EstateClient.Setup(e => e.GetEstate(It.IsAny(), It.IsAny(), It.IsAny())).ThrowsAsync(new Exception("Exception")); + + (String responseMessage, TransactionResponseCode responseCode) response = await this.TransactionValidationService.ValidateSaleTransaction(TestData.EstateId, + TestData.MerchantId, + TestData.ContractId, + TestData.ProductId, + TestData.DeviceIdentifier, + TestData.OperatorIdentifier1, + TestData.TransactionAmount, + CancellationToken.None); + + response.responseCode.ShouldBe(TransactionResponseCode.UnknownFailure); + } + + [Fact] + public async Task TransactionValidationService_ValidateSaleTransaction_EstateClientGetMerchantThrewOtherException_ResponseIsUnknownFailure() { + this.SecurityServiceClient.Setup(s => s.GetToken(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(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())) + .ThrowsAsync(new Exception("Exception")); + + (String responseMessage, TransactionResponseCode responseCode) response = await this.TransactionValidationService.ValidateSaleTransaction(TestData.EstateId, + TestData.MerchantId, + TestData.ContractId, + TestData.ProductId, + TestData.DeviceIdentifier, + TestData.OperatorIdentifier1, + TestData.TransactionAmount, + CancellationToken.None); + + response.responseCode.ShouldBe(TransactionResponseCode.UnknownFailure); + } + + [Fact] + public async Task TransactionValidationService_ValidateSaleTransaction_EstateClientThrownOtherExceptionFoundOnGetContract_ResponseIsUnknownFailure() { + this.SecurityServiceClient.Setup(s => s.GetToken(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(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())) + .ThrowsAsync(new Exception("Exception")); + + this.StateRepository.Setup(p => p.Load(It.IsAny(), It.IsAny(), It.IsAny())) + .ReturnsAsync(TestData.MerchantBalanceProjectionState); + + (String responseMessage, TransactionResponseCode responseCode) response = await this.TransactionValidationService.ValidateSaleTransaction(TestData.EstateId, + TestData.MerchantId, + TestData.ContractId, + TestData.ProductId, + TestData.DeviceIdentifier, + TestData.OperatorIdentifier1, + TestData.TransactionAmount, + CancellationToken.None); + + response.responseCode.ShouldBe(TransactionResponseCode.UnknownFailure); + } + + [Fact] + public async Task TransactionValidationService_ValidateSaleTransaction_EstateFoundButHasNoOperators_ResponseIsInvalidEstateId() { + this.SecurityServiceClient.Setup(s => s.GetToken(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(TestData.TokenResponse); + + this.EstateClient.Setup(e => e.GetEstate(It.IsAny(), It.IsAny(), It.IsAny())) + .ReturnsAsync(TestData.GetEstateResponseWithEmptyOperators); + + (String responseMessage, TransactionResponseCode responseCode) response = await this.TransactionValidationService.ValidateSaleTransaction(TestData.EstateId, + TestData.MerchantId, + TestData.ContractId, + TestData.ProductId, + TestData.DeviceIdentifier, + TestData.OperatorIdentifier1, + TestData.TransactionAmount, + CancellationToken.None); + + response.responseCode.ShouldBe(TransactionResponseCode.NoEstateOperators); + } + + [Fact] + public async Task TransactionValidationService_ValidateSaleTransaction_EstateFoundButHasNullOperators_ResponseIsInvalidEstateId() { + this.SecurityServiceClient.Setup(s => s.GetToken(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(TestData.TokenResponse); + + this.EstateClient.Setup(e => e.GetEstate(It.IsAny(), It.IsAny(), It.IsAny())) + .ReturnsAsync(TestData.GetEstateResponseWithNullOperators); + + (String responseMessage, TransactionResponseCode responseCode) response = await this.TransactionValidationService.ValidateSaleTransaction(TestData.EstateId, + TestData.MerchantId, + TestData.ContractId, + TestData.ProductId, + TestData.DeviceIdentifier, + TestData.OperatorIdentifier1, + TestData.TransactionAmount, + CancellationToken.None); + + response.responseCode.ShouldBe(TransactionResponseCode.NoEstateOperators); + } + + [Fact] + public async Task TransactionValidationService_ValidateSaleTransaction_EstateFoundOperatorsNotConfiguredForEstate_ResponseIsOperatorNotValidForEstate() { + this.SecurityServiceClient.Setup(s => s.GetToken(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(TestData.TokenResponse); + + this.EstateClient.Setup(e => e.GetEstate(It.IsAny(), It.IsAny(), It.IsAny())) + .ReturnsAsync(TestData.GetEstateResponseWithOperator1); + + (String responseMessage, TransactionResponseCode responseCode) response = await this.TransactionValidationService.ValidateSaleTransaction(TestData.EstateId, + TestData.MerchantId, + TestData.ContractId, + TestData.ProductId, + TestData.DeviceIdentifier, + TestData.OperatorIdentifier2, + TestData.TransactionAmount, + CancellationToken.None); + + response.responseCode.ShouldBe(TransactionResponseCode.OperatorNotValidForEstate); + } + + [Fact] + public async Task TransactionValidationService_ValidateSaleTransaction_EstateNotFound_ResponseIsInvalidEstateId() { + this.SecurityServiceClient.Setup(s => s.GetToken(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(TestData.TokenResponse); + + this.EstateClient.Setup(e => e.GetEstate(It.IsAny(), It.IsAny(), It.IsAny())) + .ThrowsAsync(new Exception("Exception", new KeyNotFoundException("Invalid Estate"))); + + (String responseMessage, TransactionResponseCode responseCode) response = await this.TransactionValidationService.ValidateSaleTransaction(TestData.EstateId, + TestData.MerchantId, + TestData.ContractId, + TestData.ProductId, + TestData.DeviceIdentifier, + TestData.OperatorIdentifier1, + TestData.TransactionAmount, + CancellationToken.None); + + response.responseCode.ShouldBe(TransactionResponseCode.InvalidEstateId); + } + + [Fact] + public async Task TransactionValidationService_ValidateSaleTransaction_InvalidContractId_ResponseIsInvalidContractIdValue() { + this.SecurityServiceClient.Setup(s => s.GetToken(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(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.StateRepository.Setup(p => p.Load(It.IsAny(), It.IsAny(), It.IsAny())) + .ReturnsAsync(TestData.MerchantBalanceProjectionState); + + (String responseMessage, TransactionResponseCode responseCode) response = await this.TransactionValidationService.ValidateSaleTransaction(TestData.EstateId, + TestData.MerchantId, + Guid.Empty, + TestData.ProductId, + TestData.DeviceIdentifier, + TestData.OperatorIdentifier1, + TestData.TransactionAmount, + CancellationToken.None); + + response.responseCode.ShouldBe(TransactionResponseCode.InvalidContractIdValue); + } + + [Fact] + public async Task TransactionValidationService_ValidateSaleTransaction_InvalidProductId_ResponseIsInvalidProductIdValue() { + this.SecurityServiceClient.Setup(s => s.GetToken(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(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.StateRepository.Setup(p => p.Load(It.IsAny(), It.IsAny(), It.IsAny())) + .ReturnsAsync(TestData.MerchantBalanceProjectionState); + + (String responseMessage, TransactionResponseCode responseCode) response = await this.TransactionValidationService.ValidateSaleTransaction(TestData.EstateId, + TestData.MerchantId, + TestData.ContractId, + Guid.Empty, + TestData.DeviceIdentifier, + TestData.OperatorIdentifier1, + TestData.TransactionAmount, + CancellationToken.None); + + response.responseCode.ShouldBe(TransactionResponseCode.InvalidProductIdValue); + } + + [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(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); + + (String responseMessage, TransactionResponseCode responseCode) response = await this.TransactionValidationService.ValidateSaleTransaction(TestData.EstateId, + TestData.MerchantId, + TestData.ContractId, + TestData.ProductId, + TestData.DeviceIdentifier, + TestData.OperatorIdentifier1, + transactionAmount, + CancellationToken.None); + + response.responseCode.ShouldBe(TransactionResponseCode.InvalidSaleTransactionAmount); + } + + [Fact] + public async Task TransactionValidationService_ValidateSaleTransaction_MerchantDeviceListEmpty_ResponseIsNoValidDevices() { + this.SecurityServiceClient.Setup(s => s.GetToken(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(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.GetMerchantResponseWithNoDevices); + + (String responseMessage, TransactionResponseCode responseCode) response = await this.TransactionValidationService.ValidateSaleTransaction(TestData.EstateId, + TestData.MerchantId, + TestData.ContractId, + TestData.ProductId, + TestData.DeviceIdentifier1, + TestData.OperatorIdentifier1, + TestData.TransactionAmount, + CancellationToken.None); + + response.responseCode.ShouldBe(TransactionResponseCode.NoValidDevices); + } + + [Fact] + public async Task TransactionValidationService_ValidateSaleTransaction_MerchantDeviceListNull_ResponseIsNoValidDevices() { + this.SecurityServiceClient.Setup(s => s.GetToken(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(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); + + (String responseMessage, TransactionResponseCode responseCode) response = await this.TransactionValidationService.ValidateSaleTransaction(TestData.EstateId, + TestData.MerchantId, + TestData.ContractId, + TestData.ProductId, + TestData.DeviceIdentifier1, + TestData.OperatorIdentifier1, + TestData.TransactionAmount, + CancellationToken.None); + + response.responseCode.ShouldBe(TransactionResponseCode.NoValidDevices); + } + + [Fact] + public async Task TransactionValidationService_ValidateSaleTransaction_MerchantDoesNotHaveSuppliedContract_ResponseIsContractNotValidForMerchant() { + this.SecurityServiceClient.Setup(s => s.GetToken(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(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.StateRepository.Setup(p => p.Load(It.IsAny(), It.IsAny(), It.IsAny())) + .ReturnsAsync(TestData.MerchantBalanceProjectionState); + + (String responseMessage, TransactionResponseCode responseCode) response = await this.TransactionValidationService.ValidateSaleTransaction(TestData.EstateId, + TestData.MerchantId, + TestData.ContractId1, + TestData.ProductId, + TestData.DeviceIdentifier, + TestData.OperatorIdentifier1, + TestData.TransactionAmount, + CancellationToken.None); + + response.responseCode.ShouldBe(TransactionResponseCode.ContractNotValidForMerchant); + } + + [Fact] + public async Task TransactionValidationService_ValidateSaleTransaction_MerchantHasNoContracts_ResponseIsMerchantDoesNotHaveEnoughCredit() { + this.SecurityServiceClient.Setup(s => s.GetToken(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(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(new List()); + + this.StateRepository.Setup(p => p.Load(It.IsAny(), It.IsAny(), It.IsAny())) + .ReturnsAsync(TestData.MerchantBalanceProjectionState); + + (String responseMessage, TransactionResponseCode responseCode) response = await this.TransactionValidationService.ValidateSaleTransaction(TestData.EstateId, + TestData.MerchantId, + TestData.ContractId, + TestData.ProductId, + TestData.DeviceIdentifier, + TestData.OperatorIdentifier1, + TestData.TransactionAmount, + CancellationToken.None); + + response.responseCode.ShouldBe(TransactionResponseCode.MerchantHasNoContractsConfigured); + } + + [Fact] + public async Task TransactionValidationService_ValidateSaleTransaction_MerchantHasNullContracts_ResponseIsMerchantDoesNotHaveEnoughCredit() { + this.SecurityServiceClient.Setup(s => s.GetToken(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(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); + List contracts = null; + this.EstateClient.Setup(e => e.GetMerchantContracts(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) + .ReturnsAsync(contracts); + + this.StateRepository.Setup(p => p.Load(It.IsAny(), It.IsAny(), It.IsAny())) + .ReturnsAsync(TestData.MerchantBalanceProjectionState); + + (String responseMessage, TransactionResponseCode responseCode) response = await this.TransactionValidationService.ValidateSaleTransaction(TestData.EstateId, + TestData.MerchantId, + TestData.ContractId, + TestData.ProductId, + TestData.DeviceIdentifier, + TestData.OperatorIdentifier1, + TestData.TransactionAmount, + CancellationToken.None); + + response.responseCode.ShouldBe(TransactionResponseCode.MerchantHasNoContractsConfigured); + } + + [Fact] + public async Task TransactionValidationService_ValidateSaleTransaction_MerchantNotEnoughCredit_ResponseIsMerchantDoesNotHaveEnoughCredit() { + this.SecurityServiceClient.Setup(s => s.GetToken(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(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.StateRepository.Setup(p => p.Load(It.IsAny(), It.IsAny(), It.IsAny())) + .ReturnsAsync(TestData.MerchantBalanceProjectionStateNoCredit); + + (String responseMessage, TransactionResponseCode responseCode) response = await this.TransactionValidationService.ValidateSaleTransaction(TestData.EstateId, + TestData.MerchantId, + TestData.ContractId, + TestData.ProductId, + TestData.DeviceIdentifier, + TestData.OperatorIdentifier1, + TestData.TransactionAmount, + CancellationToken.None); + + response.responseCode.ShouldBe(TransactionResponseCode.MerchantDoesNotHaveEnoughCredit); + } + + [Fact] + public async Task TransactionValidationService_ValidateSaleTransaction_MerchantNotFound_ResponseIsInvalidMerchantId() { + this.SecurityServiceClient.Setup(s => s.GetToken(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(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())) + .ThrowsAsync(new Exception("Exception", new KeyNotFoundException("Invalid Merchant"))); + + (String responseMessage, TransactionResponseCode responseCode) response = await this.TransactionValidationService.ValidateSaleTransaction(TestData.EstateId, + TestData.MerchantId, + TestData.ContractId, + TestData.ProductId, + TestData.DeviceIdentifier, + TestData.OperatorIdentifier1, + TestData.TransactionAmount, + CancellationToken.None); + + response.responseCode.ShouldBe(TransactionResponseCode.InvalidMerchantId); + } + + [Fact] + public async Task TransactionValidationService_ValidateSaleTransaction_MerchantNotFoundOnGetContract_ResponseIsInvalidMerchantId() { + this.SecurityServiceClient.Setup(s => s.GetToken(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(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())) + .ThrowsAsync(new Exception("Exception", new KeyNotFoundException("Invalid Merchant"))); + + this.StateRepository.Setup(p => p.Load(It.IsAny(), It.IsAny(), It.IsAny())) + .ReturnsAsync(TestData.MerchantBalanceProjectionState); + + (String responseMessage, TransactionResponseCode responseCode) response = await this.TransactionValidationService.ValidateSaleTransaction(TestData.EstateId, + TestData.MerchantId, + TestData.ContractId, + TestData.ProductId, + TestData.DeviceIdentifier, + TestData.OperatorIdentifier1, + TestData.TransactionAmount, + CancellationToken.None); + + response.responseCode.ShouldBe(TransactionResponseCode.InvalidMerchantId); + } + + [Fact] + public async Task TransactionValidationService_ValidateSaleTransaction_MerchantOperatorListEmpty_ResponseIsNoMerchantOperators() { + this.SecurityServiceClient.Setup(s => s.GetToken(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(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); + + (String responseMessage, TransactionResponseCode responseCode) response = await this.TransactionValidationService.ValidateSaleTransaction(TestData.EstateId, + TestData.MerchantId, + TestData.ContractId, + TestData.ProductId, + TestData.DeviceIdentifier, + TestData.OperatorIdentifier1, + TestData.TransactionAmount, + CancellationToken.None); + + response.responseCode.ShouldBe(TransactionResponseCode.NoMerchantOperators); + } + + [Fact] + public async Task TransactionValidationService_ValidateSaleTransaction_MerchantOperatorListNull_ResponseIsNoMerchantOperators() { + this.SecurityServiceClient.Setup(s => s.GetToken(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(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); + + (String responseMessage, TransactionResponseCode responseCode) response = await this.TransactionValidationService.ValidateSaleTransaction(TestData.EstateId, + TestData.MerchantId, + TestData.ContractId, + TestData.ProductId, + TestData.DeviceIdentifier, + TestData.OperatorIdentifier1, + TestData.TransactionAmount, + CancellationToken.None); + + response.responseCode.ShouldBe(TransactionResponseCode.NoMerchantOperators); + } + + [Fact] + public async Task TransactionValidationService_ValidateSaleTransaction_OperatorNotConfiguredFroMerchant_ResponseIsOperatorNotValidForMerchant() { + this.SecurityServiceClient.Setup(s => s.GetToken(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(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); + + (String responseMessage, TransactionResponseCode responseCode) response = await this.TransactionValidationService.ValidateSaleTransaction(TestData.EstateId, + TestData.MerchantId, + TestData.ContractId, + TestData.ProductId, + TestData.DeviceIdentifier, + TestData.OperatorIdentifier1, + TestData.TransactionAmount, + CancellationToken.None); + + response.responseCode.ShouldBe(TransactionResponseCode.OperatorNotValidForMerchant); + } + + [Fact] + public async Task TransactionValidationService_ValidateSaleTransaction_ProductIdNotConfigured_ResponseIsProductNotValidForMerchant() { + this.SecurityServiceClient.Setup(s => s.GetToken(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(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.StateRepository.Setup(p => p.Load(It.IsAny(), It.IsAny(), It.IsAny())) + .ReturnsAsync(TestData.MerchantBalanceProjectionState); + + (String responseMessage, TransactionResponseCode responseCode) response = await this.TransactionValidationService.ValidateSaleTransaction(TestData.EstateId, + TestData.MerchantId, + TestData.ContractId, + TestData.ProductId1, + TestData.DeviceIdentifier, + TestData.OperatorIdentifier1, + TestData.TransactionAmount, + CancellationToken.None); + + response.responseCode.ShouldBe(TransactionResponseCode.ProductNotValidForMerchant); + } + + [Fact] + public async Task TransactionValidationService_ValidateSaleTransaction_SuccessfulSale() { + this.SecurityServiceClient.Setup(s => s.GetToken(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(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.StateRepository.Setup(s => s.Load(It.IsAny(), It.IsAny(), It.IsAny())) + .ReturnsAsync(TestData.MerchantBalanceProjectionState); + + (String responseMessage, TransactionResponseCode responseCode) response = await this.TransactionValidationService.ValidateSaleTransaction(TestData.EstateId, + TestData.MerchantId, + TestData.ContractId, + TestData.ProductId, + TestData.DeviceIdentifier, + TestData.OperatorIdentifier1, + TestData.TransactionAmount, + CancellationToken.None); + + response.responseCode.ShouldBe(TransactionResponseCode.Success); + } +} \ No newline at end of file diff --git a/TransactionProcessor.BusinessLogic.Tests/TransactionProcessor.BusinessLogic.Tests.csproj b/TransactionProcessor.BusinessLogic.Tests/TransactionProcessor.BusinessLogic.Tests.csproj index 600870f6..965f95ac 100644 --- a/TransactionProcessor.BusinessLogic.Tests/TransactionProcessor.BusinessLogic.Tests.csproj +++ b/TransactionProcessor.BusinessLogic.Tests/TransactionProcessor.BusinessLogic.Tests.csproj @@ -2,7 +2,7 @@ net7.0 - None + Full false diff --git a/TransactionProcessor.BusinessLogic/Services/ITransactionValidationService.cs b/TransactionProcessor.BusinessLogic/Services/ITransactionValidationService.cs new file mode 100644 index 00000000..5df39b4a --- /dev/null +++ b/TransactionProcessor.BusinessLogic/Services/ITransactionValidationService.cs @@ -0,0 +1,30 @@ +namespace TransactionProcessor.BusinessLogic.Services; + +using System; +using System.Threading; +using System.Threading.Tasks; + +public interface ITransactionValidationService{ + #region Methods + + Task<(String responseMessage, TransactionResponseCode responseCode)> ValidateLogonTransaction(Guid estateId, + Guid merchantId, + String deviceIdentifier, + CancellationToken cancellationToken); + + Task<(String responseMessage, TransactionResponseCode responseCode)> 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, + String operatorIdentifier, + Decimal? transactionAmount, + CancellationToken cancellationToken); + + #endregion +} \ No newline at end of file diff --git a/TransactionProcessor.BusinessLogic/Services/TransactionDomainService.cs b/TransactionProcessor.BusinessLogic/Services/TransactionDomainService.cs index 2805217a..c0bf539b 100644 --- a/TransactionProcessor.BusinessLogic/Services/TransactionDomainService.cs +++ b/TransactionProcessor.BusinessLogic/Services/TransactionDomainService.cs @@ -1,9 +1,7 @@ -namespace TransactionProcessor.BusinessLogic.Services -{ +namespace TransactionProcessor.BusinessLogic.Services{ using System; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; - using System.Linq; using System.Threading; using System.Threading.Tasks; using Common; @@ -12,8 +10,6 @@ using EstateManagement.DataTransferObjects.Responses; using Models; using OperatorInterfaces; - using ProjectionEngine.Repository; - using ProjectionEngine.State; using ReconciliationAggregate; using SecurityService.Client; using SecurityService.DataTransferObjects.Responses; @@ -27,12 +23,9 @@ /// /// /// - public class TransactionDomainService : ITransactionDomainService - { + public class TransactionDomainService : ITransactionDomainService{ #region Fields - private readonly IAggregateRepository TransactionAggregateRepository; - /// /// The estate client /// @@ -48,71 +41,43 @@ public class TransactionDomainService : ITransactionDomainService /// private readonly IAggregateRepository ReconciliationAggregateRepository; - private readonly IProjectionStateRepository MerchantBalanceStateRepository; - - /// - /// The security service client - /// private readonly ISecurityServiceClient SecurityServiceClient; - /// - /// The token response - /// private TokenResponse TokenResponse; - /// - /// The transaction aggregate manager - /// - //private readonly ITransactionAggregateManager TransactionAggregateManager; + private readonly IAggregateRepository TransactionAggregateRepository; + + private readonly ITransactionValidationService TransactionValidationService; #endregion #region Constructors - /// - /// Initializes a new instance of the class. - /// - /// The transaction aggregate manager. - /// The estate client. - /// The security service client. - /// The operator proxy resolver. - /// The reconciliation aggregate repository. public TransactionDomainService(IAggregateRepository transactionAggregateRepository, IEstateClient estateClient, - ISecurityServiceClient securityServiceClient, Func operatorProxyResolver, IAggregateRepository reconciliationAggregateRepository, - IProjectionStateRepository merchantBalanceStateRepository) { + ITransactionValidationService transactionValidationService, + ISecurityServiceClient securityServiceClient){ this.TransactionAggregateRepository = transactionAggregateRepository; this.EstateClient = estateClient; - this.SecurityServiceClient = securityServiceClient; this.OperatorProxyResolver = operatorProxyResolver; this.ReconciliationAggregateRepository = reconciliationAggregateRepository; - this.MerchantBalanceStateRepository = merchantBalanceStateRepository; + this.TransactionValidationService = transactionValidationService; + this.SecurityServiceClient = securityServiceClient; } #endregion #region Methods - /// - /// Processes the logon transaction. - /// - /// The transaction identifier. - /// The estate identifier. - /// The merchant identifier. - /// The transaction date time. - /// The transaction number. - /// The device identifier. - /// The cancellation token. - /// public async Task ProcessLogonTransaction(Guid transactionId, Guid estateId, Guid merchantId, DateTime transactionDateTime, String transactionNumber, String deviceIdentifier, - CancellationToken cancellationToken) { + CancellationToken cancellationToken){ TransactionType transactionType = TransactionType.Logon; // Generate a transaction reference @@ -130,16 +95,23 @@ public async Task ProcessLogonTransaction(Guid null); // Logon transaction has no amount (String responseMessage, TransactionResponseCode responseCode) validationResult = - await this.ValidateLogonTransaction(estateId, merchantId, deviceIdentifier, cancellationToken); + await this.TransactionValidationService.ValidateLogonTransaction(estateId, merchantId, deviceIdentifier, cancellationToken); + + if (validationResult.responseCode == TransactionResponseCode.Success || + validationResult.responseCode == TransactionResponseCode.SuccessNeedToAddDevice) + { + if (validationResult.responseCode == TransactionResponseCode.SuccessNeedToAddDevice) + { + await this.AddDeviceToMerchant(estateId, merchantId, deviceIdentifier, cancellationToken); + } - if (validationResult.responseCode == TransactionResponseCode.Success) { // Record the successful validation // TODO: Generate local authcode transactionAggregate.AuthoriseTransactionLocally("ABCD1234", ((Int32)validationResult.responseCode).ToString().PadLeft(4, '0'), validationResult.responseMessage); } - else { + else{ // Record the failure transactionAggregate.DeclineTransactionLocally(((Int32)validationResult.responseCode).ToString().PadLeft(4, '0'), validationResult.responseMessage); @@ -149,27 +121,15 @@ public async Task ProcessLogonTransaction(Guid await this.TransactionAggregateRepository.SaveChanges(transactionAggregate, cancellationToken); - return new ProcessLogonTransactionResponse { - ResponseMessage = transactionAggregate.ResponseMessage, - ResponseCode = transactionAggregate.ResponseCode, - EstateId = estateId, - MerchantId = merchantId, - TransactionId = transactionId - }; + return new ProcessLogonTransactionResponse{ + ResponseMessage = transactionAggregate.ResponseMessage, + ResponseCode = transactionAggregate.ResponseCode, + EstateId = estateId, + MerchantId = merchantId, + TransactionId = transactionId + }; } - /// - /// Processes the reconciliation transaction. - /// - /// The transaction identifier. - /// The estate identifier. - /// The merchant identifier. - /// The device identifier. - /// The transaction date time. - /// The transaction count. - /// The transaction value. - /// The cancellation token. - /// public async Task ProcessReconciliationTransaction(Guid transactionId, Guid estateId, Guid merchantId, @@ -177,9 +137,9 @@ public async Task ProcessReconciliatio DateTime transactionDateTime, Int32 transactionCount, Decimal transactionValue, - CancellationToken cancellationToken) { + CancellationToken cancellationToken){ (String responseMessage, TransactionResponseCode responseCode) validationResult = - await this.ValidateReconciliationTransaction(estateId, merchantId, deviceIdentifier, cancellationToken); + await this.TransactionValidationService.ValidateReconciliationTransaction(estateId, merchantId, deviceIdentifier, cancellationToken); ReconciliationAggregate reconciliationAggregate = await this.ReconciliationAggregateRepository.GetLatestVersion(transactionId, cancellationToken); @@ -187,11 +147,11 @@ public async Task ProcessReconciliatio reconciliationAggregate.RecordOverallTotals(transactionCount, transactionValue); - if (validationResult.responseCode == TransactionResponseCode.Success) { + if (validationResult.responseCode == TransactionResponseCode.Success){ // Record the successful validation reconciliationAggregate.Authorise(((Int32)validationResult.responseCode).ToString().PadLeft(4, '0'), validationResult.responseMessage); } - else { + else{ // Record the failure reconciliationAggregate.Decline(((Int32)validationResult.responseCode).ToString().PadLeft(4, '0'), validationResult.responseMessage); } @@ -200,31 +160,15 @@ public async Task ProcessReconciliatio await this.ReconciliationAggregateRepository.SaveChanges(reconciliationAggregate, cancellationToken); - return new ProcessReconciliationTransactionResponse { - EstateId = reconciliationAggregate.EstateId, - MerchantId = reconciliationAggregate.MerchantId, - ResponseCode = reconciliationAggregate.ResponseCode, - ResponseMessage = reconciliationAggregate.ResponseMessage, - TransactionId = transactionId - }; + return new ProcessReconciliationTransactionResponse{ + EstateId = reconciliationAggregate.EstateId, + MerchantId = reconciliationAggregate.MerchantId, + ResponseCode = reconciliationAggregate.ResponseCode, + ResponseMessage = reconciliationAggregate.ResponseMessage, + TransactionId = transactionId + }; } - /// - /// Processes the sale transaction. - /// - /// The transaction identifier. - /// The estate identifier. - /// The merchant identifier. - /// The transaction date time. - /// The transaction number. - /// The device identifier. - /// The operator identifier. - /// The customer email address. - /// The additional transaction metadata. - /// The contract identifier. - /// The product identifier. - /// The cancellation token. - /// public async Task ProcessSaleTransaction(Guid transactionId, Guid estateId, Guid merchantId, @@ -237,7 +181,7 @@ public async Task ProcessSaleTransaction(Guid tr Guid contractId, Guid productId, Int32 transactionSource, - CancellationToken cancellationToken) { + CancellationToken cancellationToken){ TransactionType transactionType = TransactionType.Sale; TransactionSource transactionSourceValue = (TransactionSource)transactionSource; @@ -248,14 +192,14 @@ public async Task ProcessSaleTransaction(Guid tr Decimal? transactionAmount = additionalTransactionMetadata.ExtractFieldFromMetadata("Amount"); (String responseMessage, TransactionResponseCode responseCode) validationResult = - await this.ValidateSaleTransaction(estateId, - merchantId, - contractId, - productId, - deviceIdentifier, - operatorIdentifier, - transactionAmount, - cancellationToken); + await this.TransactionValidationService.ValidateSaleTransaction(estateId, + merchantId, + contractId, + productId, + deviceIdentifier, + operatorIdentifier, + transactionAmount, + cancellationToken); Logger.LogInformation($"Validation response is [{validationResult.responseCode}]"); @@ -275,14 +219,14 @@ await this.ValidateSaleTransaction(estateId, validationResult.responseCode != TransactionResponseCode.InvalidContractIdValue && validationResult.responseCode != TransactionResponseCode.InvalidProductIdValue && validationResult.responseCode != TransactionResponseCode.ContractNotValidForMerchant && - validationResult.responseCode != TransactionResponseCode.ProductNotValidForMerchant) { + validationResult.responseCode != TransactionResponseCode.ProductNotValidForMerchant){ transactionAggregate.AddProductDetails(contractId, productId); } // Add the transaction source transactionAggregate.AddTransactionSource(transactionSourceValue); - if (validationResult.responseCode == TransactionResponseCode.Success) { + if (validationResult.responseCode == TransactionResponseCode.Success){ // Record any additional request metadata transactionAggregate.RecordAdditionalRequestData(operatorIdentifier, additionalTransactionMetadata); @@ -297,15 +241,15 @@ await this.ValidateSaleTransaction(estateId, cancellationToken); // Act on the operator response - if (operatorResponse == null) { + if (operatorResponse == null){ // Failed to perform sed/receive with the operator TransactionResponseCode transactionResponseCode = TransactionResponseCode.OperatorCommsError; String responseMessage = "OPERATOR COMMS ERROR"; transactionAggregate.DeclineTransactionLocally(((Int32)transactionResponseCode).ToString().PadLeft(4, '0'), responseMessage); } - else { - if (operatorResponse.IsSuccessful) { + else{ + if (operatorResponse.IsSuccessful){ TransactionResponseCode transactionResponseCode = TransactionResponseCode.Success; String responseMessage = "SUCCESS"; @@ -317,7 +261,7 @@ await this.ValidateSaleTransaction(estateId, ((Int32)transactionResponseCode).ToString().PadLeft(4, '0'), responseMessage); } - else { + else{ TransactionResponseCode transactionResponseCode = TransactionResponseCode.TransactionDeclinedByOperator; String responseMessage = "DECLINED BY OPERATOR"; @@ -332,7 +276,7 @@ await this.ValidateSaleTransaction(estateId, transactionAggregate.RecordAdditionalResponseData(operatorIdentifier, operatorResponse.AdditionalTransactionResponseMetadata); } } - else { + else{ // Record the failure transactionAggregate.DeclineTransactionLocally(((Int32)validationResult.responseCode).ToString().PadLeft(4, '0'), validationResult.responseMessage); } @@ -340,7 +284,7 @@ await this.ValidateSaleTransaction(estateId, transactionAggregate.CompleteTransaction(); // Determine if the email receipt is required - if (String.IsNullOrEmpty(customerEmailAddress) == false) { + if (String.IsNullOrEmpty(customerEmailAddress) == false){ transactionAggregate.RequestEmailReceipt(customerEmailAddress); } @@ -349,24 +293,24 @@ await this.ValidateSaleTransaction(estateId, // Get the model from the aggregate Transaction transaction = transactionAggregate.GetTransaction(); - return new ProcessSaleTransactionResponse { - ResponseMessage = transaction.ResponseMessage, - ResponseCode = transaction.ResponseCode, - EstateId = estateId, - MerchantId = merchantId, - AdditionalTransactionMetadata = transaction.AdditionalResponseMetadata, - TransactionId = transactionId - }; + return new ProcessSaleTransactionResponse{ + ResponseMessage = transaction.ResponseMessage, + ResponseCode = transaction.ResponseCode, + EstateId = estateId, + MerchantId = merchantId, + AdditionalTransactionMetadata = transaction.AdditionalResponseMetadata, + TransactionId = transactionId + }; } public async Task ResendTransactionReceipt(Guid transactionId, Guid estateId, - CancellationToken cancellationToken) { + CancellationToken cancellationToken){ TransactionAggregate transactionAggregate = await this.TransactionAggregateRepository.GetLatestVersion(transactionId, cancellationToken); transactionAggregate.RequestEmailReceiptResend(); - await this.TransactionAggregateRepository.SaveChanges(transactionAggregate,cancellationToken); + await this.TransactionAggregateRepository.SaveChanges(transactionAggregate, cancellationToken); } /// @@ -379,16 +323,16 @@ public async Task ResendTransactionReceipt(Guid transactionId, private async Task AddDeviceToMerchant(Guid estateId, Guid merchantId, String deviceIdentifier, - CancellationToken cancellationToken) { + CancellationToken cancellationToken){ this.TokenResponse = await this.GetToken(cancellationToken); // Add the device to the merchant await this.EstateClient.AddDeviceToMerchant(this.TokenResponse.AccessToken, estateId, merchantId, - new AddMerchantDeviceRequest { - DeviceIdentifier = deviceIdentifier - }, + new AddMerchantDeviceRequest{ + DeviceIdentifier = deviceIdentifier + }, cancellationToken); } @@ -397,40 +341,18 @@ await this.EstateClient.AddDeviceToMerchant(this.TokenResponse.AccessToken, /// /// [ExcludeFromCodeCoverage] - private String GenerateTransactionReference() { + private String GenerateTransactionReference(){ Int64 i = 1; - foreach (Byte b in Guid.NewGuid().ToByteArray()) { + foreach (Byte b in Guid.NewGuid().ToByteArray()){ i *= (b + 1); } return $"{i - DateTime.Now.Ticks:x}"; } - /// - /// Gets the estate. - /// - /// The estate identifier. - /// The cancellation token. - /// - private async Task GetEstate(Guid estateId, - CancellationToken cancellationToken) { - this.TokenResponse = await this.GetToken(cancellationToken); - - EstateResponse estate = await this.EstateClient.GetEstate(this.TokenResponse.AccessToken, estateId, cancellationToken); - - return estate; - } - - /// - /// Gets the merchant. - /// - /// The estate identifier. - /// The merchant identifier. - /// The cancellation token. - /// private async Task GetMerchant(Guid estateId, Guid merchantId, - CancellationToken cancellationToken) { + CancellationToken cancellationToken){ this.TokenResponse = await this.GetToken(cancellationToken); MerchantResponse merchant = await this.EstateClient.GetMerchant(this.TokenResponse.AccessToken, estateId, merchantId, cancellationToken); @@ -438,32 +360,21 @@ private async Task GetMerchant(Guid estateId, return merchant; } - private async Task> GetMerchantContracts(Guid estateId, - Guid merchantId, - CancellationToken cancellationToken) - { - this.TokenResponse = await this.GetToken(cancellationToken); - - List merchantContracts = await this.EstateClient.GetMerchantContracts(this.TokenResponse.AccessToken, estateId, merchantId, cancellationToken); - - return merchantContracts; - } - [ExcludeFromCodeCoverage] - private async Task GetToken(CancellationToken cancellationToken) { + private async Task GetToken(CancellationToken cancellationToken){ // Get a token to talk to the estate service String clientId = ConfigurationReader.GetValue("AppSettings", "ClientId"); String clientSecret = ConfigurationReader.GetValue("AppSettings", "ClientSecret"); Logger.LogInformation($"Client Id is {clientId}"); Logger.LogInformation($"Client Secret is {clientSecret}"); - if (this.TokenResponse == null) { + if (this.TokenResponse == null){ TokenResponse token = await this.SecurityServiceClient.GetToken(clientId, clientSecret, cancellationToken); Logger.LogInformation($"Token is {token.AccessToken}"); return token; } - if (this.TokenResponse.Expires.UtcDateTime.Subtract(DateTime.UtcNow) < TimeSpan.FromMinutes(2)) { + if (this.TokenResponse.Expires.UtcDateTime.Subtract(DateTime.UtcNow) < TimeSpan.FromMinutes(2)){ Logger.LogInformation($"Token is about to expire at {this.TokenResponse.Expires.DateTime:O}"); TokenResponse token = await this.SecurityServiceClient.GetToken(clientId, clientSecret, cancellationToken); Logger.LogInformation($"Token is {token.AccessToken}"); @@ -479,10 +390,10 @@ private async Task ProcessMessageWithOperator(MerchantResponse String operatorIdentifier, Dictionary additionalTransactionMetadata, String transactionReference, - CancellationToken cancellationToken) { + CancellationToken cancellationToken){ IOperatorProxy operatorProxy = this.OperatorProxyResolver(operatorIdentifier.Replace(" ", "")); OperatorResponse operatorResponse = null; - try { + try{ operatorResponse = await operatorProxy.ProcessSaleMessage(this.TokenResponse.AccessToken, transactionId, operatorIdentifier, @@ -492,239 +403,13 @@ private async Task ProcessMessageWithOperator(MerchantResponse additionalTransactionMetadata, cancellationToken); } - catch(Exception e) { + catch(Exception e){ // Log out the error Logger.LogError(e); } return operatorResponse; } - - internal async Task<(String responseMessage, TransactionResponseCode responseCode)> ValidateLogonTransaction(Guid estateId, - Guid merchantId, - String deviceIdentifier, - CancellationToken cancellationToken) { - try { - (EstateResponse estate, MerchantResponse merchant) validateTransactionResponse = await this.ValidateMerchant(estateId, merchantId, cancellationToken); - MerchantResponse merchant = validateTransactionResponse.merchant; - - // Device Validation - if (merchant.Devices == null || merchant.Devices.Any() == false) { - await this.AddDeviceToMerchant(estateId, merchantId, deviceIdentifier, cancellationToken); - } - else { - // 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 async Task<(String responseMessage, TransactionResponseCode responseCode)> ValidateReconciliationTransaction(Guid estateId, - Guid merchantId, - String deviceIdentifier, - CancellationToken cancellationToken) { - try { - (EstateResponse estate, MerchantResponse merchant) validateTransactionResponse = await this.ValidateMerchant(estateId, merchantId, cancellationToken); - 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); - } - } - - internal async Task<(String responseMessage, TransactionResponseCode responseCode)> ValidateSaleTransaction(Guid estateId, - Guid merchantId, - Guid contractId, - Guid productId, - String deviceIdentifier, - String operatorIdentifier, - Decimal? transactionAmount, - CancellationToken cancellationToken) { - try { - (EstateResponse estate, MerchantResponse merchant) validateTransactionResponse = await this.ValidateMerchant(estateId, merchantId, cancellationToken); - EstateResponse estate = validateTransactionResponse.estate; - 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.Name == operatorIdentifier); - if (estateOperatorRecord == null) - { - throw new TransactionValidationException($"Operator {operatorIdentifier} not configured for Estate [{estate.EstateName}]", - TransactionResponseCode.OperatorNotValidForEstate); - } - - // 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 - MerchantOperatorResponse merchantOperatorRecord = merchant.Operators.SingleOrDefault(o => o.Name == operatorIdentifier); - if (merchantOperatorRecord == null) { - throw new TransactionValidationException($"Operator {operatorIdentifier} not configured for Merchant [{merchant.MerchantName}]", - TransactionResponseCode.OperatorNotValidForMerchant); - } - } - - // Check the amount - if (transactionAmount.HasValue) { - if (transactionAmount <= 0) { - throw new TransactionValidationException("Transaction Amount must be greater than 0", TransactionResponseCode.InvalidSaleTransactionAmount); - } - - MerchantBalanceState merchantBalanceState = await this.MerchantBalanceStateRepository.Load(estateId, merchantId, cancellationToken); - - // Check the merchant has enough balance to perform the sale - if (merchantBalanceState.AvailableBalance < transactionAmount) { - throw new - TransactionValidationException($"Merchant [{merchant.MerchantName}] does not have enough credit available [{merchantBalanceState.AvailableBalance}] to perform transaction amount [{transactionAmount}]", - TransactionResponseCode.MerchantDoesNotHaveEnoughCredit); - } - } - - // 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 - ContractResponse 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); - } - - ContractProduct contractProduct = contract.Products.SingleOrDefault(p => p.ProductId == productId); - - if (contractProduct == null) - { - throw new TransactionValidationException($"Product Id [{productId}] not valid for Merchant [{merchant.MerchantName}]", - TransactionResponseCode.ProductNotValidForMerchant); - } - - // If we get here everything is good - return ("SUCCESS", TransactionResponseCode.Success); - } - catch(TransactionValidationException tvex) { - return (tvex.Message, tvex.ResponseCode); - } - } - - private async Task<(EstateResponse estate, MerchantResponse merchant)> ValidateMerchant(Guid estateId, - Guid merchantId, - CancellationToken cancellationToken) { - EstateResponse estate = null; - MerchantResponse merchant = null; - - // Validate the Estate Record is a valid estate - try { - estate = await this.GetEstate(estateId, cancellationToken); - } - catch(Exception ex) when(ex.InnerException != null && ex.InnerException.GetType() == typeof(KeyNotFoundException)) { - throw new TransactionValidationException($"Estate Id [{estateId}] is not a valid estate", TransactionResponseCode.InvalidEstateId); - } - catch(Exception e) - { - throw new TransactionValidationException($"Exception occurred while getting Estate Id [{estateId}] Exception [{e.Message}]", TransactionResponseCode.UnknownFailure); - } - - // get the merchant record and validate the device - try { - merchant = await this.GetMerchant(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}] Exception [{e.Message}]", TransactionResponseCode.UnknownFailure); - } - - return (estate, merchant); - } #endregion } diff --git a/TransactionProcessor.BusinessLogic/Services/TransactionResponseCode.cs b/TransactionProcessor.BusinessLogic/Services/TransactionResponseCode.cs index f7ccea24..0c9881e6 100644 --- a/TransactionProcessor.BusinessLogic/Services/TransactionResponseCode.cs +++ b/TransactionProcessor.BusinessLogic/Services/TransactionResponseCode.cs @@ -3,7 +3,8 @@ public enum TransactionResponseCode { Success = 0, - + SuccessNeedToAddDevice = 1, + InvalidDeviceIdentifier = 1000, InvalidEstateId = 1001, InvalidMerchantId = 1002, diff --git a/TransactionProcessor.BusinessLogic/Services/TransactionValidationService.cs b/TransactionProcessor.BusinessLogic/Services/TransactionValidationService.cs new file mode 100644 index 00000000..8168e455 --- /dev/null +++ b/TransactionProcessor.BusinessLogic/Services/TransactionValidationService.cs @@ -0,0 +1,314 @@ +namespace TransactionProcessor.BusinessLogic.Services; + +using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using EstateManagement.Client; +using EstateManagement.DataTransferObjects.Responses; +using ProjectionEngine.Repository; +using ProjectionEngine.State; +using SecurityService.Client; +using SecurityService.DataTransferObjects.Responses; +using Shared.General; +using Shared.Logger; + +public class TransactionValidationService : ITransactionValidationService{ + #region Fields + + /// + /// The estate client + /// + private readonly IEstateClient EstateClient; + + private readonly IProjectionStateRepository MerchantBalanceStateRepository; + + /// + /// The security service client + /// + private readonly ISecurityServiceClient SecurityServiceClient; + + private TokenResponse TokenResponse; + + #endregion + + public TransactionValidationService(IEstateClient estateClient, + ISecurityServiceClient securityServiceClient, + IProjectionStateRepository merchantBalanceStateRepository){ + this.EstateClient = estateClient; + this.SecurityServiceClient = securityServiceClient; + this.MerchantBalanceStateRepository = merchantBalanceStateRepository; + } + + #region Methods + + public async Task<(String responseMessage, TransactionResponseCode responseCode)> ValidateLogonTransaction(Guid estateId, + Guid merchantId, + String deviceIdentifier, + CancellationToken cancellationToken){ + try{ + (EstateResponse estate, MerchantResponse merchant) validateTransactionResponse = await this.ValidateMerchant(estateId, merchantId, cancellationToken); + 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); + } + } + + public async Task<(String responseMessage, TransactionResponseCode responseCode)> ValidateReconciliationTransaction(Guid estateId, + Guid merchantId, + String deviceIdentifier, + CancellationToken cancellationToken){ + try{ + (EstateResponse estate, MerchantResponse merchant) validateTransactionResponse = await this.ValidateMerchant(estateId, merchantId, cancellationToken); + 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, + String operatorIdentifier, + Decimal? transactionAmount, + CancellationToken cancellationToken){ + try{ + (EstateResponse estate, MerchantResponse merchant) validateTransactionResponse = await this.ValidateMerchant(estateId, merchantId, cancellationToken); + EstateResponse estate = validateTransactionResponse.estate; + 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.Name == operatorIdentifier); + if (estateOperatorRecord == null){ + throw new TransactionValidationException($"Operator {operatorIdentifier} not configured for Estate [{estate.EstateName}]", + TransactionResponseCode.OperatorNotValidForEstate); + } + + // 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 + MerchantOperatorResponse merchantOperatorRecord = merchant.Operators.SingleOrDefault(o => o.Name == operatorIdentifier); + if (merchantOperatorRecord == null){ + throw new TransactionValidationException($"Operator {operatorIdentifier} not configured for Merchant [{merchant.MerchantName}]", + TransactionResponseCode.OperatorNotValidForMerchant); + } + } + + // Check the amount + if (transactionAmount.HasValue){ + if (transactionAmount <= 0){ + throw new TransactionValidationException("Transaction Amount must be greater than 0", TransactionResponseCode.InvalidSaleTransactionAmount); + } + + MerchantBalanceState merchantBalanceState = await this.MerchantBalanceStateRepository.Load(estateId, merchantId, cancellationToken); + + // Check the merchant has enough balance to perform the sale + if (merchantBalanceState.AvailableBalance < transactionAmount){ + throw new + TransactionValidationException($"Merchant [{merchant.MerchantName}] does not have enough credit available [{merchantBalanceState.AvailableBalance}] to perform transaction amount [{transactionAmount}]", + TransactionResponseCode.MerchantDoesNotHaveEnoughCredit); + } + } + + // 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 + ContractResponse 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); + } + + ContractProduct contractProduct = contract.Products.SingleOrDefault(p => p.ProductId == productId); + + if (contractProduct == null){ + throw new TransactionValidationException($"Product Id [{productId}] not valid for Merchant [{merchant.MerchantName}]", + TransactionResponseCode.ProductNotValidForMerchant); + } + + // If we get here everything is good + return ("SUCCESS", TransactionResponseCode.Success); + } + catch(TransactionValidationException tvex){ + return (tvex.Message, tvex.ResponseCode); + } + } + + private async Task GetEstate(Guid estateId, + CancellationToken cancellationToken){ + this.TokenResponse = await this.GetToken(cancellationToken); + + EstateResponse estate = await this.EstateClient.GetEstate(this.TokenResponse.AccessToken, estateId, cancellationToken); + + return estate; + } + + private async Task GetMerchant(Guid estateId, + Guid merchantId, + CancellationToken cancellationToken){ + this.TokenResponse = await this.GetToken(cancellationToken); + + MerchantResponse merchant = await this.EstateClient.GetMerchant(this.TokenResponse.AccessToken, estateId, merchantId, cancellationToken); + + return merchant; + } + + private async Task> GetMerchantContracts(Guid estateId, + Guid merchantId, + CancellationToken cancellationToken){ + this.TokenResponse = await this.GetToken(cancellationToken); + + List merchantContracts = await this.EstateClient.GetMerchantContracts(this.TokenResponse.AccessToken, estateId, merchantId, cancellationToken); + + return merchantContracts; + } + + [ExcludeFromCodeCoverage] + private async Task GetToken(CancellationToken cancellationToken){ + // Get a token to talk to the estate service + String clientId = ConfigurationReader.GetValue("AppSettings", "ClientId"); + String clientSecret = ConfigurationReader.GetValue("AppSettings", "ClientSecret"); + Logger.LogInformation($"Client Id is {clientId}"); + Logger.LogInformation($"Client Secret is {clientSecret}"); + + if (this.TokenResponse == null){ + TokenResponse token = await this.SecurityServiceClient.GetToken(clientId, clientSecret, cancellationToken); + Logger.LogInformation($"Token is {token.AccessToken}"); + return token; + } + + if (this.TokenResponse.Expires.UtcDateTime.Subtract(DateTime.UtcNow) < TimeSpan.FromMinutes(2)){ + Logger.LogInformation($"Token is about to expire at {this.TokenResponse.Expires.DateTime:O}"); + TokenResponse token = await this.SecurityServiceClient.GetToken(clientId, clientSecret, cancellationToken); + Logger.LogInformation($"Token is {token.AccessToken}"); + return token; + } + + return this.TokenResponse; + } + + private async Task<(EstateResponse estate, MerchantResponse merchant)> ValidateMerchant(Guid estateId, + Guid merchantId, + CancellationToken cancellationToken){ + EstateResponse estate = null; + MerchantResponse merchant = null; + + // Validate the Estate Record is a valid estate + try{ + estate = await this.GetEstate(estateId, cancellationToken); + } + catch(Exception ex) when(ex.InnerException != null && ex.InnerException.GetType() == typeof(KeyNotFoundException)){ + throw new TransactionValidationException($"Estate Id [{estateId}] is not a valid estate", TransactionResponseCode.InvalidEstateId); + } + catch(Exception e){ + throw new TransactionValidationException($"Exception occurred while getting Estate Id [{estateId}] Exception [{e.Message}]", TransactionResponseCode.UnknownFailure); + } + + // get the merchant record and validate the device + try{ + merchant = await this.GetMerchant(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}] Exception [{e.Message}]", TransactionResponseCode.UnknownFailure); + } + + return (estate, merchant); + } + + #endregion +} \ No newline at end of file diff --git a/TransactionProcessor.TransactionAggregate.Tests/TransactionAggregateTests.cs b/TransactionProcessor.TransactionAggregate.Tests/TransactionAggregateTests.cs index 867a0394..34f57f54 100644 --- a/TransactionProcessor.TransactionAggregate.Tests/TransactionAggregateTests.cs +++ b/TransactionProcessor.TransactionAggregate.Tests/TransactionAggregateTests.cs @@ -135,7 +135,6 @@ public void TransactionAggregate_StartTransaction_TransactionAlreadyCompleted_Er [InlineData(true, "0001", TransactionType.Logon, "ABCDEFG", true, false, "A1234567890")] [InlineData(true, "0001", TransactionType.Logon, "ABCDEFG", true, true, "")] [InlineData(true, "0001", TransactionType.Logon, "ABCDEFG", true, true, null)] - [InlineData(true, "0001", TransactionType.Logon, "ABCDEFG", true, true, "A!234567890")] [InlineData(true, "0001", (TransactionType)99, "ABCDEFG", true, true, "A1234567890")] [InlineData(true, "0001", TransactionType.Logon, "", true, true, "A1234567890")] [InlineData(true, "0001", TransactionType.Logon, null, true, true, "A1234567890")] @@ -147,7 +146,6 @@ public void TransactionAggregate_StartTransaction_TransactionAlreadyCompleted_Er [InlineData(true, "0001", TransactionType.Sale, "ABCDEFG", true, false, "A1234567890")] [InlineData(true, "0001", TransactionType.Sale, "ABCDEFG", true, true, "")] [InlineData(true, "0001", TransactionType.Sale, "ABCDEFG", true, true, null)] - [InlineData(true, "0001", TransactionType.Sale, "ABCDEFG", true, true, "A!234567890")] [InlineData(true, "0001", TransactionType.Sale, "", true, true, "A1234567890")] [InlineData(true, "0001", TransactionType.Sale, null, true, true, "A1234567890")] public void TransactionAggregate_StartTransaction_InvalidData_ErrorThrown(Boolean validTransactionDateTime, String transactionNumber, TransactionType transactionType, String transactionReference, Boolean validEstateId, Boolean validMerchantId, String deviceIdentifier) diff --git a/TransactionProcessor.TransactionAgrgegate/TransactionAggregate.cs b/TransactionProcessor.TransactionAgrgegate/TransactionAggregate.cs index fded3c9f..83f99bb1 100644 --- a/TransactionProcessor.TransactionAgrgegate/TransactionAggregate.cs +++ b/TransactionProcessor.TransactionAgrgegate/TransactionAggregate.cs @@ -382,12 +382,7 @@ public void StartTransaction(DateTime transactionDateTime, Guard.ThrowIfInvalidGuid(estateId, typeof(ArgumentException), $"Estate Id must not be [{Guid.Empty}]"); Guard.ThrowIfInvalidGuid(merchantId, typeof(ArgumentException), $"Merchant Id must not be [{Guid.Empty}]"); Guard.ThrowIfNullOrEmpty(deviceIdentifier, typeof(ArgumentException), "Device Identifier must not be null or empty"); - - Regex r = new Regex("^[a-zA-Z0-9]*$"); - if (r.IsMatch(deviceIdentifier) == false) { - throw new ArgumentException("Device Identifier must be alphanumeric"); - } - + this.CheckTransactionNotAlreadyStarted(); this.CheckTransactionNotAlreadyCompleted(); TransactionHasStartedEvent transactionHasStartedEvent = new TransactionHasStartedEvent(this.AggregateId, diff --git a/TransactionProcessor/Bootstrapper/DomainServiceRegistry.cs b/TransactionProcessor/Bootstrapper/DomainServiceRegistry.cs index b3ebf6fb..5134d4dd 100644 --- a/TransactionProcessor/Bootstrapper/DomainServiceRegistry.cs +++ b/TransactionProcessor/Bootstrapper/DomainServiceRegistry.cs @@ -22,6 +22,7 @@ public DomainServiceRegistry() this.AddSingleton(); this.AddSingleton(); this.AddSingleton(); + this.AddSingleton(); } #endregion From 71db0bb4836eb08c828189535057b23b5d53c062 Mon Sep 17 00:00:00 2001 From: Stuart Ferguson Date: Sat, 18 Feb 2023 16:58:39 +0000 Subject: [PATCH 2/2] Fix logon tests --- .../Features/LogonTransaction.feature | 6 +- .../Features/LogonTransaction.feature.cs | 640 +----------------- 2 files changed, 4 insertions(+), 642 deletions(-) diff --git a/TransactionProcessor.IntegrationTests/Features/LogonTransaction.feature b/TransactionProcessor.IntegrationTests/Features/LogonTransaction.feature index 6c4acbee..15ad1141 100644 --- a/TransactionProcessor.IntegrationTests/Features/LogonTransaction.feature +++ b/TransactionProcessor.IntegrationTests/Features/LogonTransaction.feature @@ -57,9 +57,9 @@ Scenario: Logon Transactions Then transaction response should contain the following information | EstateName | MerchantName | TransactionNumber | ResponseCode | ResponseMessage | - | Test Estate 1 | Test Merchant 1 | 1 | 0000 | SUCCESS | - | Test Estate 1 | Test Merchant 2 | 2 | 0000 | SUCCESS | - | Test Estate 2 | Test Merchant 3 | 3 | 0000 | SUCCESS | + | Test Estate 1 | Test Merchant 1 | 1 | 0001 | SUCCESS | + | Test Estate 1 | Test Merchant 2 | 2 | 0001 | SUCCESS | + | Test Estate 2 | Test Merchant 3 | 3 | 0001 | SUCCESS | Scenario: Logon Transaction with Existing Device diff --git a/TransactionProcessor.IntegrationTests/Features/LogonTransaction.feature.cs b/TransactionProcessor.IntegrationTests/Features/LogonTransaction.feature.cs index f7bd100a..b34d8696 100644 --- a/TransactionProcessor.IntegrationTests/Features/LogonTransaction.feature.cs +++ b/TransactionProcessor.IntegrationTests/Features/LogonTransaction.feature.cs @@ -1,639 +1 @@ -// ------------------------------------------------------------------------------ -// -// This code was generated by SpecFlow (https://www.specflow.org/). -// SpecFlow Version:3.9.0.0 -// SpecFlow Generator Version:3.9.0.0 -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -// ------------------------------------------------------------------------------ -#region Designer generated code -#pragma warning disable -namespace TransactionProcessor.IntegrationTests.Features -{ - using TechTalk.SpecFlow; - using System; - using System.Linq; - - - [System.CodeDom.Compiler.GeneratedCodeAttribute("TechTalk.SpecFlow", "3.9.0.0")] - [System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - [Xunit.TraitAttribute("Category", "base")] - [Xunit.TraitAttribute("Category", "shared")] - public partial class LogonTransactionFeature : object, Xunit.IClassFixture, System.IDisposable - { - - private static TechTalk.SpecFlow.ITestRunner testRunner; - - private static string[] featureTags = new string[] { - "base", - "shared"}; - - private Xunit.Abstractions.ITestOutputHelper _testOutputHelper; - -#line 1 "LogonTransaction.feature" -#line hidden - - public LogonTransactionFeature(LogonTransactionFeature.FixtureData fixtureData, TransactionProcessor_IntegrationTests_XUnitAssemblyFixture assemblyFixture, Xunit.Abstractions.ITestOutputHelper testOutputHelper) - { - this._testOutputHelper = testOutputHelper; - this.TestInitialize(); - } - - public static void FeatureSetup() - { - testRunner = TechTalk.SpecFlow.TestRunnerManager.GetTestRunner(); - TechTalk.SpecFlow.FeatureInfo featureInfo = new TechTalk.SpecFlow.FeatureInfo(new System.Globalization.CultureInfo("en-US"), "Features", "LogonTransaction", null, ProgrammingLanguage.CSharp, featureTags); - testRunner.OnFeatureStart(featureInfo); - } - - public static void FeatureTearDown() - { - testRunner.OnFeatureEnd(); - testRunner = null; - } - - public void TestInitialize() - { - } - - public void TestTearDown() - { - testRunner.OnScenarioEnd(); - } - - public void ScenarioInitialize(TechTalk.SpecFlow.ScenarioInfo scenarioInfo) - { - testRunner.OnScenarioInitialize(scenarioInfo); - testRunner.ScenarioContext.ScenarioContainer.RegisterInstanceAs(_testOutputHelper); - } - - public void ScenarioStart() - { - testRunner.OnScenarioStart(); - } - - public void ScenarioCleanup() - { - testRunner.CollectScenarioErrors(); - } - - public virtual void FeatureBackground() - { -#line 4 -#line hidden - TechTalk.SpecFlow.Table table1 = new TechTalk.SpecFlow.Table(new string[] { - "Name", - "DisplayName", - "Description"}); - table1.AddRow(new string[] { - "estateManagement", - "Estate Managememt REST Scope", - "A scope for Estate Managememt REST"}); - table1.AddRow(new string[] { - "transactionProcessor", - "Transaction Processor REST Scope", - "A scope for Transaction Processor REST"}); -#line 6 - testRunner.Given("I create the following api scopes", ((string)(null)), table1, "Given "); -#line hidden - TechTalk.SpecFlow.Table table2 = new TechTalk.SpecFlow.Table(new string[] { - "ResourceName", - "DisplayName", - "Secret", - "Scopes", - "UserClaims"}); - table2.AddRow(new string[] { - "estateManagement", - "Estate Managememt REST", - "Secret1", - "estateManagement", - "MerchantId, EstateId, role"}); - table2.AddRow(new string[] { - "transactionProcessor", - "Transaction Processor REST", - "Secret1", - "transactionProcessor", - ""}); -#line 11 - testRunner.Given("the following api resources exist", ((string)(null)), table2, "Given "); -#line hidden - TechTalk.SpecFlow.Table table3 = new TechTalk.SpecFlow.Table(new string[] { - "ClientId", - "ClientName", - "Secret", - "AllowedScopes", - "AllowedGrantTypes"}); - table3.AddRow(new string[] { - "serviceClient", - "Service Client", - "Secret1", - "estateManagement,transactionProcessor", - "client_credentials"}); -#line 16 - testRunner.Given("the following clients exist", ((string)(null)), table3, "Given "); -#line hidden - TechTalk.SpecFlow.Table table4 = new TechTalk.SpecFlow.Table(new string[] { - "ClientId"}); - table4.AddRow(new string[] { - "serviceClient"}); -#line 20 - testRunner.Given("I have a token to access the estate management and transaction processor resource" + - "s", ((string)(null)), table4, "Given "); -#line hidden - TechTalk.SpecFlow.Table table5 = new TechTalk.SpecFlow.Table(new string[] { - "EstateName"}); - table5.AddRow(new string[] { - "Test Estate 1"}); - table5.AddRow(new string[] { - "Test Estate 2"}); -#line 24 - testRunner.Given("I have created the following estates", ((string)(null)), table5, "Given "); -#line hidden - TechTalk.SpecFlow.Table table6 = new TechTalk.SpecFlow.Table(new string[] { - "EstateName", - "OperatorName", - "RequireCustomMerchantNumber", - "RequireCustomTerminalNumber"}); - table6.AddRow(new string[] { - "Test Estate 1", - "Test Operator 1", - "True", - "True"}); -#line 29 - testRunner.Given("I have created the following operators", ((string)(null)), table6, "Given "); -#line hidden - TechTalk.SpecFlow.Table table7 = new TechTalk.SpecFlow.Table(new string[] { - "MerchantName", - "AddressLine1", - "Town", - "Region", - "Country", - "ContactName", - "EmailAddress", - "EstateName"}); - table7.AddRow(new string[] { - "Test Merchant 1", - "Address Line 1", - "TestTown", - "Test Region", - "United Kingdom", - "Test Contact 1", - "testcontact1@merchant1.co.uk", - "Test Estate 1"}); - table7.AddRow(new string[] { - "Test Merchant 2", - "Address Line 1", - "TestTown", - "Test Region", - "United Kingdom", - "Test Contact 2", - "testcontact2@merchant2.co.uk", - "Test Estate 1"}); - table7.AddRow(new string[] { - "Test Merchant 3", - "Address Line 1", - "TestTown", - "Test Region", - "United Kingdom", - "Test Contact 3", - "testcontact3@merchant2.co.uk", - "Test Estate 2"}); -#line 33 - testRunner.Given("I create the following merchants", ((string)(null)), table7, "Given "); -#line hidden - TechTalk.SpecFlow.Table table8 = new TechTalk.SpecFlow.Table(new string[] { - "OperatorName", - "MerchantName", - "MerchantNumber", - "TerminalNumber", - "EstateName"}); - table8.AddRow(new string[] { - "Test Operator 1", - "Test Merchant 1", - "00000001", - "10000001", - "Test Estate 1"}); -#line 39 - testRunner.Given("I have assigned the following operator to the merchants", ((string)(null)), table8, "Given "); -#line hidden - TechTalk.SpecFlow.Table table9 = new TechTalk.SpecFlow.Table(new string[] { - "Reference", - "Amount", - "DateTime", - "MerchantName", - "EstateName"}); - table9.AddRow(new string[] { - "Deposit1", - "2000.00", - "Today", - "Test Merchant 1", - "Test Estate 1"}); - table9.AddRow(new string[] { - "Deposit1", - "1000.00", - "Today", - "Test Merchant 2", - "Test Estate 1"}); - table9.AddRow(new string[] { - "Deposit1", - "1000.00", - "Today", - "Test Merchant 3", - "Test Estate 2"}); -#line 43 - testRunner.Given("I make the following manual merchant deposits", ((string)(null)), table9, "Given "); -#line hidden - } - - void System.IDisposable.Dispose() - { - this.TestTearDown(); - } - - [Xunit.SkippableFactAttribute(DisplayName="Logon Transactions")] - [Xunit.TraitAttribute("FeatureTitle", "LogonTransaction")] - [Xunit.TraitAttribute("Description", "Logon Transactions")] - [Xunit.TraitAttribute("Category", "PRTest")] - public void LogonTransactions() - { - string[] tagsOfScenario = new string[] { - "PRTest"}; - System.Collections.Specialized.OrderedDictionary argumentsOfScenario = new System.Collections.Specialized.OrderedDictionary(); - TechTalk.SpecFlow.ScenarioInfo scenarioInfo = new TechTalk.SpecFlow.ScenarioInfo("Logon Transactions", null, tagsOfScenario, argumentsOfScenario, featureTags); -#line 50 -this.ScenarioInitialize(scenarioInfo); -#line hidden - if ((TagHelper.ContainsIgnoreTag(tagsOfScenario) || TagHelper.ContainsIgnoreTag(featureTags))) - { - testRunner.SkipScenario(); - } - else - { - this.ScenarioStart(); -#line 4 -this.FeatureBackground(); -#line hidden - TechTalk.SpecFlow.Table table10 = new TechTalk.SpecFlow.Table(new string[] { - "DateTime", - "TransactionNumber", - "TransactionType", - "MerchantName", - "DeviceIdentifier", - "EstateName"}); - table10.AddRow(new string[] { - "Today", - "1", - "Logon", - "Test Merchant 1", - "123456780", - "Test Estate 1"}); - table10.AddRow(new string[] { - "Today", - "2", - "Logon", - "Test Merchant 2", - "123456781", - "Test Estate 1"}); - table10.AddRow(new string[] { - "Today", - "3", - "Logon", - "Test Merchant 3", - "123456782", - "Test Estate 2"}); -#line 52 - testRunner.When("I perform the following transactions", ((string)(null)), table10, "When "); -#line hidden - TechTalk.SpecFlow.Table table11 = new TechTalk.SpecFlow.Table(new string[] { - "EstateName", - "MerchantName", - "TransactionNumber", - "ResponseCode", - "ResponseMessage"}); - table11.AddRow(new string[] { - "Test Estate 1", - "Test Merchant 1", - "1", - "0000", - "SUCCESS"}); - table11.AddRow(new string[] { - "Test Estate 1", - "Test Merchant 2", - "2", - "0000", - "SUCCESS"}); - table11.AddRow(new string[] { - "Test Estate 2", - "Test Merchant 3", - "3", - "0000", - "SUCCESS"}); -#line 58 - testRunner.Then("transaction response should contain the following information", ((string)(null)), table11, "Then "); -#line hidden - } - this.ScenarioCleanup(); - } - - [Xunit.SkippableFactAttribute(DisplayName="Logon Transaction with Existing Device")] - [Xunit.TraitAttribute("FeatureTitle", "LogonTransaction")] - [Xunit.TraitAttribute("Description", "Logon Transaction with Existing Device")] - public void LogonTransactionWithExistingDevice() - { - string[] tagsOfScenario = ((string[])(null)); - System.Collections.Specialized.OrderedDictionary argumentsOfScenario = new System.Collections.Specialized.OrderedDictionary(); - TechTalk.SpecFlow.ScenarioInfo scenarioInfo = new TechTalk.SpecFlow.ScenarioInfo("Logon Transaction with Existing Device", null, tagsOfScenario, argumentsOfScenario, featureTags); -#line 64 -this.ScenarioInitialize(scenarioInfo); -#line hidden - if ((TagHelper.ContainsIgnoreTag(tagsOfScenario) || TagHelper.ContainsIgnoreTag(featureTags))) - { - testRunner.SkipScenario(); - } - else - { - this.ScenarioStart(); -#line 4 -this.FeatureBackground(); -#line hidden - TechTalk.SpecFlow.Table table12 = new TechTalk.SpecFlow.Table(new string[] { - "DeviceIdentifier", - "MerchantName", - "MerchantNumber", - "EstateName"}); - table12.AddRow(new string[] { - "123456780", - "Test Merchant 1", - "00000001", - "Test Estate 1"}); -#line 66 - testRunner.Given("I have assigned the following devices to the merchants", ((string)(null)), table12, "Given "); -#line hidden - TechTalk.SpecFlow.Table table13 = new TechTalk.SpecFlow.Table(new string[] { - "DateTime", - "TransactionNumber", - "TransactionType", - "MerchantName", - "DeviceIdentifier", - "EstateName"}); - table13.AddRow(new string[] { - "Today", - "1", - "Logon", - "Test Merchant 1", - "123456780", - "Test Estate 1"}); -#line 70 - testRunner.When("I perform the following transactions", ((string)(null)), table13, "When "); -#line hidden - TechTalk.SpecFlow.Table table14 = new TechTalk.SpecFlow.Table(new string[] { - "EstateName", - "MerchantName", - "TransactionNumber", - "ResponseCode", - "ResponseMessage"}); - table14.AddRow(new string[] { - "Test Estate 1", - "Test Merchant 1", - "1", - "0000", - "SUCCESS"}); -#line 74 - testRunner.Then("transaction response should contain the following information", ((string)(null)), table14, "Then "); -#line hidden - } - this.ScenarioCleanup(); - } - - [Xunit.SkippableFactAttribute(DisplayName="Logon Transaction with Invalid Device")] - [Xunit.TraitAttribute("FeatureTitle", "LogonTransaction")] - [Xunit.TraitAttribute("Description", "Logon Transaction with Invalid Device")] - public void LogonTransactionWithInvalidDevice() - { - string[] tagsOfScenario = ((string[])(null)); - System.Collections.Specialized.OrderedDictionary argumentsOfScenario = new System.Collections.Specialized.OrderedDictionary(); - TechTalk.SpecFlow.ScenarioInfo scenarioInfo = new TechTalk.SpecFlow.ScenarioInfo("Logon Transaction with Invalid Device", null, tagsOfScenario, argumentsOfScenario, featureTags); -#line 78 -this.ScenarioInitialize(scenarioInfo); -#line hidden - if ((TagHelper.ContainsIgnoreTag(tagsOfScenario) || TagHelper.ContainsIgnoreTag(featureTags))) - { - testRunner.SkipScenario(); - } - else - { - this.ScenarioStart(); -#line 4 -this.FeatureBackground(); -#line hidden - TechTalk.SpecFlow.Table table15 = new TechTalk.SpecFlow.Table(new string[] { - "DeviceIdentifier", - "MerchantName", - "MerchantNumber", - "EstateName"}); - table15.AddRow(new string[] { - "123456780", - "Test Merchant 1", - "00000001", - "Test Estate 1"}); -#line 80 - testRunner.Given("I have assigned the following devices to the merchants", ((string)(null)), table15, "Given "); -#line hidden - TechTalk.SpecFlow.Table table16 = new TechTalk.SpecFlow.Table(new string[] { - "DateTime", - "TransactionNumber", - "TransactionType", - "MerchantName", - "DeviceIdentifier", - "EstateName"}); - table16.AddRow(new string[] { - "Today", - "1", - "Logon", - "Test Merchant 1", - "123456781", - "Test Estate 1"}); -#line 84 - testRunner.When("I perform the following transactions", ((string)(null)), table16, "When "); -#line hidden - TechTalk.SpecFlow.Table table17 = new TechTalk.SpecFlow.Table(new string[] { - "EstateName", - "MerchantName", - "TransactionNumber", - "ResponseCode", - "ResponseMessage"}); - table17.AddRow(new string[] { - "Test Estate 1", - "Test Merchant 1", - "1", - "1000", - "Device Identifier 123456781 not valid for Merchant Test Merchant 1"}); -#line 88 - testRunner.Then("transaction response should contain the following information", ((string)(null)), table17, "Then "); -#line hidden - } - this.ScenarioCleanup(); - } - - [Xunit.SkippableFactAttribute(DisplayName="Logon Transaction with Invalid Estate")] - [Xunit.TraitAttribute("FeatureTitle", "LogonTransaction")] - [Xunit.TraitAttribute("Description", "Logon Transaction with Invalid Estate")] - public void LogonTransactionWithInvalidEstate() - { - string[] tagsOfScenario = ((string[])(null)); - System.Collections.Specialized.OrderedDictionary argumentsOfScenario = new System.Collections.Specialized.OrderedDictionary(); - TechTalk.SpecFlow.ScenarioInfo scenarioInfo = new TechTalk.SpecFlow.ScenarioInfo("Logon Transaction with Invalid Estate", null, tagsOfScenario, argumentsOfScenario, featureTags); -#line 92 -this.ScenarioInitialize(scenarioInfo); -#line hidden - if ((TagHelper.ContainsIgnoreTag(tagsOfScenario) || TagHelper.ContainsIgnoreTag(featureTags))) - { - testRunner.SkipScenario(); - } - else - { - this.ScenarioStart(); -#line 4 -this.FeatureBackground(); -#line hidden - TechTalk.SpecFlow.Table table18 = new TechTalk.SpecFlow.Table(new string[] { - "DeviceIdentifier", - "MerchantName", - "MerchantNumber", - "EstateName"}); - table18.AddRow(new string[] { - "123456780", - "Test Merchant 1", - "00000001", - "Test Estate 1"}); -#line 94 - testRunner.Given("I have assigned the following devices to the merchants", ((string)(null)), table18, "Given "); -#line hidden - TechTalk.SpecFlow.Table table19 = new TechTalk.SpecFlow.Table(new string[] { - "DateTime", - "TransactionNumber", - "TransactionType", - "MerchantName", - "DeviceIdentifier", - "EstateName"}); - table19.AddRow(new string[] { - "Today", - "1", - "Logon", - "Test Merchant 1", - "123456781", - "InvalidEstate"}); -#line 98 - testRunner.When("I perform the following transactions", ((string)(null)), table19, "When "); -#line hidden - TechTalk.SpecFlow.Table table20 = new TechTalk.SpecFlow.Table(new string[] { - "EstateName", - "MerchantName", - "TransactionNumber", - "ResponseCode", - "ResponseMessage"}); - table20.AddRow(new string[] { - "InvalidEstate", - "Test Merchant 1", - "1", - "1001", - "Estate Id [79902550-64df-4491-b0c1-4e78943928a3] is not a valid estate"}); -#line 102 - testRunner.Then("transaction response should contain the following information", ((string)(null)), table20, "Then "); -#line hidden - } - this.ScenarioCleanup(); - } - - [Xunit.SkippableFactAttribute(DisplayName="Logon Transaction with Invalid Merchant")] - [Xunit.TraitAttribute("FeatureTitle", "LogonTransaction")] - [Xunit.TraitAttribute("Description", "Logon Transaction with Invalid Merchant")] - public void LogonTransactionWithInvalidMerchant() - { - string[] tagsOfScenario = ((string[])(null)); - System.Collections.Specialized.OrderedDictionary argumentsOfScenario = new System.Collections.Specialized.OrderedDictionary(); - TechTalk.SpecFlow.ScenarioInfo scenarioInfo = new TechTalk.SpecFlow.ScenarioInfo("Logon Transaction with Invalid Merchant", null, tagsOfScenario, argumentsOfScenario, featureTags); -#line 106 -this.ScenarioInitialize(scenarioInfo); -#line hidden - if ((TagHelper.ContainsIgnoreTag(tagsOfScenario) || TagHelper.ContainsIgnoreTag(featureTags))) - { - testRunner.SkipScenario(); - } - else - { - this.ScenarioStart(); -#line 4 -this.FeatureBackground(); -#line hidden - TechTalk.SpecFlow.Table table21 = new TechTalk.SpecFlow.Table(new string[] { - "DeviceIdentifier", - "MerchantName", - "MerchantNumber", - "EstateName"}); - table21.AddRow(new string[] { - "123456780", - "Test Merchant 1", - "00000001", - "Test Estate 1"}); -#line 108 - testRunner.Given("I have assigned the following devices to the merchants", ((string)(null)), table21, "Given "); -#line hidden - TechTalk.SpecFlow.Table table22 = new TechTalk.SpecFlow.Table(new string[] { - "DateTime", - "TransactionNumber", - "TransactionType", - "MerchantName", - "DeviceIdentifier", - "EstateName"}); - table22.AddRow(new string[] { - "Today", - "1", - "Logon", - "InvalidMerchant", - "123456781", - "Test Estate 1"}); -#line 112 - testRunner.When("I perform the following transactions", ((string)(null)), table22, "When "); -#line hidden - TechTalk.SpecFlow.Table table23 = new TechTalk.SpecFlow.Table(new string[] { - "EstateName", - "MerchantName", - "TransactionNumber", - "ResponseCode", - "ResponseMessage"}); - table23.AddRow(new string[] { - "Test Estate 1", - "InvalidMerchant", - "1", - "1002", - "Merchant Id [d59320fa-4c3e-4900-a999-483f6a10c69a] is not a valid merchant for es" + - "tate [Test Estate 1]"}); -#line 116 - testRunner.Then("transaction response should contain the following information", ((string)(null)), table23, "Then "); -#line hidden - } - this.ScenarioCleanup(); - } - - [System.CodeDom.Compiler.GeneratedCodeAttribute("TechTalk.SpecFlow", "3.9.0.0")] - [System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - public class FixtureData : System.IDisposable - { - - public FixtureData() - { - LogonTransactionFeature.FeatureSetup(); - } - - void System.IDisposable.Dispose() - { - LogonTransactionFeature.FeatureTearDown(); - } - } - } -} -#pragma warning restore -#endregion +#error Unable to use SpecFlow tools folder 'C:\Users\stuar\.nuget\packages\specflow\3.9.74\tools': Folder does not exist