From 9a0e5673471b6179a63dcc0380ddee8dae2ec76e Mon Sep 17 00:00:00 2001 From: Stuart Ferguson Date: Tue, 14 May 2024 15:13:15 +0100 Subject: [PATCH] reject sales when operator is disabled at either estate or merchant --- .../Services/TransactionDomainServiceTests.cs | 1 - .../TransactionValidationServiceTests.cs | 181 +++++++++++------- ...actionProcessor.BusinessLogic.Tests.csproj | 2 +- .../OperatorInterfaces/IOperatorProxy.cs | 4 +- .../PataPawaPostPay/PataPawaPostPayProxy.cs | 1 - .../PataPawaPrePay/PataPawaPrePayProxy.cs | 4 +- .../SafaricomPinless/SafaricomPinlessProxy.cs | 4 +- .../VoucherManagementProxy.cs | 6 +- .../Services/TransactionResponseCode.cs | 2 + .../Services/TransactionValidationService.cs | 15 +- .../TransactionProcessor.BusinessLogic.csproj | 8 +- ...rocessor.IntegrationTesting.Helpers.csproj | 4 +- .../Common/TestingContext.cs | 1 + ...ansactionProcessor.IntegrationTests.csproj | 10 +- ...ansactionProcessor.ProjectionEngine.csproj | 8 +- TransactionProcessor.Testing/TestData.cs | 142 ++++++++++++-- 16 files changed, 285 insertions(+), 108 deletions(-) diff --git a/TransactionProcessor.BusinessLogic.Tests/Services/TransactionDomainServiceTests.cs b/TransactionProcessor.BusinessLogic.Tests/Services/TransactionDomainServiceTests.cs index 8a1bbbf9..930b9ded 100644 --- a/TransactionProcessor.BusinessLogic.Tests/Services/TransactionDomainServiceTests.cs +++ b/TransactionProcessor.BusinessLogic.Tests/Services/TransactionDomainServiceTests.cs @@ -23,7 +23,6 @@ using Testing; using TransactionAggregate; using Xunit; - using MerchantResponse = EstateManagement.DataTransferObjects.Responses.MerchantResponse; public class TransactionDomainServiceTests{ #region Fields diff --git a/TransactionProcessor.BusinessLogic.Tests/Services/TransactionValidationServiceTests.cs b/TransactionProcessor.BusinessLogic.Tests/Services/TransactionValidationServiceTests.cs index 4c589e27..25f3d22c 100644 --- a/TransactionProcessor.BusinessLogic.Tests/Services/TransactionValidationServiceTests.cs +++ b/TransactionProcessor.BusinessLogic.Tests/Services/TransactionValidationServiceTests.cs @@ -7,24 +7,28 @@ using BusinessLogic.Services; using EstateManagement.Client; using EstateManagement.DataTransferObjects.Responses; +using EstateManagement.DataTransferObjects.Responses.Contract; using Microsoft.Extensions.Configuration; using Moq; +using Newtonsoft.Json; using ProjectionEngine.Repository; using ProjectionEngine.State; using SecurityService.Client; +using Shared.EventStore.EventStore; 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; + private readonly Mock EventStoreContext; public TransactionValidationServiceTests(){ IConfigurationRoot configurationRoot = new ConfigurationBuilder().AddInMemoryCollection(TestData.DefaultAppSettings).Build(); @@ -35,10 +39,12 @@ public TransactionValidationServiceTests(){ this.EstateClient = new Mock(); this.SecurityServiceClient = new Mock(); this.StateRepository = new Mock>(); + this.EventStoreContext = new Mock(); this.TransactionValidationService = new TransactionValidationService(this.EstateClient.Object, this.SecurityServiceClient.Object, - this.StateRepository.Object); + this.StateRepository.Object, + this.EventStoreContext.Object); } [Fact] @@ -55,7 +61,7 @@ public async Task TransactionValidationService_ValidateLogonTransaction_DeviceNo 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); @@ -310,7 +316,7 @@ public async Task TransactionValidationService_ValidateSaleTransaction_DeviceNot TestData.ContractId, TestData.ProductId, TestData.DeviceIdentifier1, - TestData.OperatorIdentifier1, + TestData.OperatorId, TestData.TransactionAmount, CancellationToken.None); @@ -328,7 +334,7 @@ public async Task TransactionValidationService_ValidateSaleTransaction_EstateCli TestData.ContractId, TestData.ProductId, TestData.DeviceIdentifier, - TestData.OperatorIdentifier1, + TestData.OperatorId, TestData.TransactionAmount, CancellationToken.None); @@ -349,33 +355,33 @@ public async Task TransactionValidationService_ValidateSaleTransaction_EstateCli TestData.ContractId, TestData.ProductId, TestData.DeviceIdentifier, - TestData.OperatorIdentifier1, + TestData.OperatorId, 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())) + this.EstateClient.SetupSequence(e => e.GetMerchant(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) + .ReturnsAsync(TestData.GetMerchantResponseWithOperator1) .ThrowsAsync(new Exception("Exception")); - this.StateRepository.Setup(p => p.Load(It.IsAny(), It.IsAny(), It.IsAny())) - .ReturnsAsync(TestData.MerchantBalanceProjectionState); + + this.EventStoreContext.Setup(e => e.GetPartitionStateFromProjection(It.IsAny(), It.IsAny(), It.IsAny())) + .ReturnsAsync(JsonConvert.SerializeObject(TestData.MerchantBalanceProjectionState)); (String responseMessage, TransactionResponseCode responseCode) response = await this.TransactionValidationService.ValidateSaleTransaction(TestData.EstateId, TestData.MerchantId, TestData.ContractId, TestData.ProductId, TestData.DeviceIdentifier, - TestData.OperatorIdentifier1, + TestData.OperatorId, TestData.TransactionAmount, CancellationToken.None); @@ -394,13 +400,33 @@ public async Task TransactionValidationService_ValidateSaleTransaction_EstateFou TestData.ContractId, TestData.ProductId, TestData.DeviceIdentifier, - TestData.OperatorIdentifier1, + TestData.OperatorId, TestData.TransactionAmount, CancellationToken.None); response.responseCode.ShouldBe(TransactionResponseCode.NoEstateOperators); } + [Fact] + public async Task TransactionValidationService_ValidateSaleTransaction_EstateFoundButOperatorIsDeleted_ResponseIsOperatorNotEnabledForEstate() + { + 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.GetEstateResponseWithOperator1Deleted); + + (String responseMessage, TransactionResponseCode responseCode) response = await this.TransactionValidationService.ValidateSaleTransaction(TestData.EstateId, + TestData.MerchantId, + TestData.ContractId, + TestData.ProductId, + TestData.DeviceIdentifier, + TestData.OperatorId, + TestData.TransactionAmount, + CancellationToken.None); + + response.responseCode.ShouldBe(TransactionResponseCode.OperatorNotEnabledForEstate); + } + [Fact] public async Task TransactionValidationService_ValidateSaleTransaction_EstateFoundButHasNullOperators_ResponseIsInvalidEstateId() { this.SecurityServiceClient.Setup(s => s.GetToken(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(TestData.TokenResponse); @@ -413,7 +439,7 @@ public async Task TransactionValidationService_ValidateSaleTransaction_EstateFou TestData.ContractId, TestData.ProductId, TestData.DeviceIdentifier, - TestData.OperatorIdentifier1, + TestData.OperatorId, TestData.TransactionAmount, CancellationToken.None); @@ -432,7 +458,7 @@ public async Task TransactionValidationService_ValidateSaleTransaction_EstateFou TestData.ContractId, TestData.ProductId, TestData.DeviceIdentifier, - TestData.OperatorIdentifier2, + TestData.OperatorId2, TestData.TransactionAmount, CancellationToken.None); @@ -451,7 +477,7 @@ public async Task TransactionValidationService_ValidateSaleTransaction_EstateNot TestData.ContractId, TestData.ProductId, TestData.DeviceIdentifier, - TestData.OperatorIdentifier1, + TestData.OperatorId, TestData.TransactionAmount, CancellationToken.None); @@ -467,15 +493,15 @@ public async Task TransactionValidationService_ValidateSaleTransaction_InvalidCo 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); + this.EventStoreContext.Setup(e => e.GetPartitionStateFromProjection(It.IsAny(), It.IsAny(), It.IsAny())) + .ReturnsAsync(JsonConvert.SerializeObject(TestData.MerchantBalanceProjectionState)); (String responseMessage, TransactionResponseCode responseCode) response = await this.TransactionValidationService.ValidateSaleTransaction(TestData.EstateId, TestData.MerchantId, Guid.Empty, TestData.ProductId, TestData.DeviceIdentifier, - TestData.OperatorIdentifier1, + TestData.OperatorId, TestData.TransactionAmount, CancellationToken.None); @@ -493,15 +519,15 @@ public async Task TransactionValidationService_ValidateSaleTransaction_InvalidPr 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); + this.EventStoreContext.Setup(e => e.GetPartitionStateFromProjection(It.IsAny(), It.IsAny(), It.IsAny())) + .ReturnsAsync(JsonConvert.SerializeObject(TestData.MerchantBalanceProjectionState)); (String responseMessage, TransactionResponseCode responseCode) response = await this.TransactionValidationService.ValidateSaleTransaction(TestData.EstateId, TestData.MerchantId, TestData.ContractId, Guid.Empty, TestData.DeviceIdentifier, - TestData.OperatorIdentifier1, + TestData.OperatorId, TestData.TransactionAmount, CancellationToken.None); @@ -526,7 +552,7 @@ public async Task TransactionValidationService_ValidateSaleTransaction_InvalidTr TestData.ContractId, TestData.ProductId, TestData.DeviceIdentifier, - TestData.OperatorIdentifier1, + TestData.OperatorId, transactionAmount, CancellationToken.None); @@ -547,7 +573,7 @@ public async Task TransactionValidationService_ValidateSaleTransaction_MerchantD TestData.ContractId, TestData.ProductId, TestData.DeviceIdentifier1, - TestData.OperatorIdentifier1, + TestData.OperatorId, TestData.TransactionAmount, CancellationToken.None); @@ -568,7 +594,7 @@ public async Task TransactionValidationService_ValidateSaleTransaction_MerchantD TestData.ContractId, TestData.ProductId, TestData.DeviceIdentifier1, - TestData.OperatorIdentifier1, + TestData.OperatorId, TestData.TransactionAmount, CancellationToken.None); @@ -586,15 +612,15 @@ public async Task TransactionValidationService_ValidateSaleTransaction_MerchantD 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); + this.EventStoreContext.Setup(e => e.GetPartitionStateFromProjection(It.IsAny(), It.IsAny(), It.IsAny())) + .ReturnsAsync(JsonConvert.SerializeObject(TestData.MerchantBalanceProjectionState)); (String responseMessage, TransactionResponseCode responseCode) response = await this.TransactionValidationService.ValidateSaleTransaction(TestData.EstateId, TestData.MerchantId, TestData.ContractId1, TestData.ProductId, TestData.DeviceIdentifier, - TestData.OperatorIdentifier1, + TestData.OperatorId, TestData.TransactionAmount, CancellationToken.None); @@ -607,53 +633,52 @@ public async Task TransactionValidationService_ValidateSaleTransaction_MerchantH 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.EstateClient.SetupSequence(e => e.GetMerchant(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) + .ReturnsAsync(TestData.GetMerchantResponseWithOperator1) + .ReturnsAsync(TestData.GetMerchantResponseWithOperator1AndEmptyContracts); + - this.StateRepository.Setup(p => p.Load(It.IsAny(), It.IsAny(), It.IsAny())) - .ReturnsAsync(TestData.MerchantBalanceProjectionState); + this.EventStoreContext.Setup(e => e.GetPartitionStateFromProjection(It.IsAny(), It.IsAny(), It.IsAny())) + .ReturnsAsync(JsonConvert.SerializeObject(TestData.MerchantBalanceProjectionState)); (String responseMessage, TransactionResponseCode responseCode) response = await this.TransactionValidationService.ValidateSaleTransaction(TestData.EstateId, TestData.MerchantId, TestData.ContractId, TestData.ProductId, TestData.DeviceIdentifier, - TestData.OperatorIdentifier1, + TestData.OperatorId, 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); + this.EstateClient.SetupSequence(e => e.GetMerchant(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) + .ReturnsAsync(TestData.GetMerchantResponseWithOperator1) + .ReturnsAsync(TestData.GetMerchantResponseWithOperator1AndNullContracts); + + this.EventStoreContext.Setup(e => e.GetPartitionStateFromProjection(It.IsAny(), It.IsAny(), It.IsAny())) + .ReturnsAsync(JsonConvert.SerializeObject(TestData.MerchantBalanceProjectionState)); (String responseMessage, TransactionResponseCode responseCode) response = await this.TransactionValidationService.ValidateSaleTransaction(TestData.EstateId, TestData.MerchantId, TestData.ContractId, TestData.ProductId, TestData.DeviceIdentifier, - TestData.OperatorIdentifier1, + TestData.OperatorId, 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); @@ -664,15 +689,15 @@ public async Task TransactionValidationService_ValidateSaleTransaction_MerchantN .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.MerchantBalanceProjectionStateNoCredit); + this.EventStoreContext.Setup(e => e.GetPartitionStateFromProjection(It.IsAny(), It.IsAny(), It.IsAny())) + .ReturnsAsync(JsonConvert.SerializeObject(TestData.MerchantBalanceProjectionStateNoCredit)); (String responseMessage, TransactionResponseCode responseCode) response = await this.TransactionValidationService.ValidateSaleTransaction(TestData.EstateId, TestData.MerchantId, TestData.ContractId, TestData.ProductId, TestData.DeviceIdentifier, - TestData.OperatorIdentifier1, + TestData.OperatorId, TestData.TransactionAmount, CancellationToken.None); @@ -693,7 +718,7 @@ public async Task TransactionValidationService_ValidateSaleTransaction_MerchantN TestData.ContractId, TestData.ProductId, TestData.DeviceIdentifier, - TestData.OperatorIdentifier1, + TestData.OperatorId, TestData.TransactionAmount, CancellationToken.None); @@ -706,20 +731,21 @@ public async Task TransactionValidationService_ValidateSaleTransaction_MerchantN 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())) + this.EstateClient.SetupSequence(e => e.GetMerchant(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) + .ReturnsAsync(TestData.GetMerchantResponseWithOperator1) .ThrowsAsync(new Exception("Exception", new KeyNotFoundException("Invalid Merchant"))); + //this.EstateClient.Setup(e => e.GetMerchantContracts(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) + // .ThrowsAsync(new Exception("Exception", new KeyNotFoundException("Invalid Merchant"))); - this.StateRepository.Setup(p => p.Load(It.IsAny(), It.IsAny(), It.IsAny())) - .ReturnsAsync(TestData.MerchantBalanceProjectionState); + this.EventStoreContext.Setup(e => e.GetPartitionStateFromProjection(It.IsAny(), It.IsAny(), It.IsAny())) + .ReturnsAsync(JsonConvert.SerializeObject(TestData.MerchantBalanceProjectionState)); (String responseMessage, TransactionResponseCode responseCode) response = await this.TransactionValidationService.ValidateSaleTransaction(TestData.EstateId, TestData.MerchantId, TestData.ContractId, TestData.ProductId, TestData.DeviceIdentifier, - TestData.OperatorIdentifier1, + TestData.OperatorId, TestData.TransactionAmount, CancellationToken.None); @@ -740,7 +766,7 @@ public async Task TransactionValidationService_ValidateSaleTransaction_MerchantO TestData.ContractId, TestData.ProductId, TestData.DeviceIdentifier, - TestData.OperatorIdentifier1, + TestData.OperatorId, TestData.TransactionAmount, CancellationToken.None); @@ -761,13 +787,35 @@ public async Task TransactionValidationService_ValidateSaleTransaction_MerchantO TestData.ContractId, TestData.ProductId, TestData.DeviceIdentifier, - TestData.OperatorIdentifier1, + TestData.OperatorId, TestData.TransactionAmount, CancellationToken.None); response.responseCode.ShouldBe(TransactionResponseCode.NoMerchantOperators); } + [Fact] + public async Task TransactionValidationService_ValidateSaleTransaction_MerchantOperatorIsDeleted_ResponseIsOperatorNotEnabledForMerchant() + { + 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.GetMerchantResponseWithOperator1Deleted); + + (String responseMessage, TransactionResponseCode responseCode) response = await this.TransactionValidationService.ValidateSaleTransaction(TestData.EstateId, + TestData.MerchantId, + TestData.ContractId, + TestData.ProductId, + TestData.DeviceIdentifier, + TestData.OperatorId, + TestData.TransactionAmount, + CancellationToken.None); + + response.responseCode.ShouldBe(TransactionResponseCode.OperatorNotEnabledForMerchant); + } + [Fact] public async Task TransactionValidationService_ValidateSaleTransaction_OperatorNotConfiguredFroMerchant_ResponseIsOperatorNotValidForMerchant() { this.SecurityServiceClient.Setup(s => s.GetToken(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(TestData.TokenResponse); @@ -782,13 +830,14 @@ public async Task TransactionValidationService_ValidateSaleTransaction_OperatorN TestData.ContractId, TestData.ProductId, TestData.DeviceIdentifier, - TestData.OperatorIdentifier1, + TestData.OperatorId, 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); @@ -800,15 +849,15 @@ public async Task TransactionValidationService_ValidateSaleTransaction_ProductId 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); + this.EventStoreContext.Setup(e => e.GetPartitionStateFromProjection(It.IsAny(), It.IsAny(), It.IsAny())) + .ReturnsAsync(JsonConvert.SerializeObject(TestData.MerchantBalanceProjectionState)); (String responseMessage, TransactionResponseCode responseCode) response = await this.TransactionValidationService.ValidateSaleTransaction(TestData.EstateId, TestData.MerchantId, TestData.ContractId, TestData.ProductId1, TestData.DeviceIdentifier, - TestData.OperatorIdentifier1, + TestData.OperatorId, TestData.TransactionAmount, CancellationToken.None); @@ -826,18 +875,18 @@ public async Task TransactionValidationService_ValidateSaleTransaction_Successfu 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); + this.EventStoreContext.Setup(e => e.GetPartitionStateFromProjection(It.IsAny(), It.IsAny(), It.IsAny())) + .ReturnsAsync(JsonConvert.SerializeObject(TestData.MerchantBalanceProjectionState)); (String responseMessage, TransactionResponseCode responseCode) response = await this.TransactionValidationService.ValidateSaleTransaction(TestData.EstateId, TestData.MerchantId, TestData.ContractId, TestData.ProductId, TestData.DeviceIdentifier, - TestData.OperatorIdentifier1, + TestData.OperatorId, TestData.TransactionAmount, CancellationToken.None); response.responseCode.ShouldBe(TransactionResponseCode.Success); } -}*/ \ No newline at end of file +} \ 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 48f81fcd..6e144a25 100644 --- a/TransactionProcessor.BusinessLogic.Tests/TransactionProcessor.BusinessLogic.Tests.csproj +++ b/TransactionProcessor.BusinessLogic.Tests/TransactionProcessor.BusinessLogic.Tests.csproj @@ -2,7 +2,7 @@ net8.0 - Full + None false diff --git a/TransactionProcessor.BusinessLogic/OperatorInterfaces/IOperatorProxy.cs b/TransactionProcessor.BusinessLogic/OperatorInterfaces/IOperatorProxy.cs index 2d9065da..6b5f2c86 100644 --- a/TransactionProcessor.BusinessLogic/OperatorInterfaces/IOperatorProxy.cs +++ b/TransactionProcessor.BusinessLogic/OperatorInterfaces/IOperatorProxy.cs @@ -4,7 +4,7 @@ using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; - using EstateManagement.DataTransferObjects.Responses; + using EstateManagement.DataTransferObjects.Responses.Merchant; /// /// @@ -18,7 +18,7 @@ Task ProcessLogonMessage(String accessToken, Task ProcessSaleMessage(String accessToken, Guid transactionId, Guid operatorId, - EstateManagement.DataTransferObjects.Responses.Merchant.MerchantResponse merchant, + MerchantResponse merchant, DateTime transactionDateTime, String transactionReference, Dictionary additionalTransactionMetadata, diff --git a/TransactionProcessor.BusinessLogic/OperatorInterfaces/PataPawaPostPay/PataPawaPostPayProxy.cs b/TransactionProcessor.BusinessLogic/OperatorInterfaces/PataPawaPostPay/PataPawaPostPayProxy.cs index 1bcf2b79..a4b4c7d0 100644 --- a/TransactionProcessor.BusinessLogic/OperatorInterfaces/PataPawaPostPay/PataPawaPostPayProxy.cs +++ b/TransactionProcessor.BusinessLogic/OperatorInterfaces/PataPawaPostPay/PataPawaPostPayProxy.cs @@ -5,7 +5,6 @@ using System.Threading; using System.Threading.Tasks; using Common; - using EstateManagement.DataTransferObjects.Responses; using global::PataPawaPostPay; using Microsoft.Extensions.Caching.Memory; using Shared.Logger; diff --git a/TransactionProcessor.BusinessLogic/OperatorInterfaces/PataPawaPrePay/PataPawaPrePayProxy.cs b/TransactionProcessor.BusinessLogic/OperatorInterfaces/PataPawaPrePay/PataPawaPrePayProxy.cs index 8699a814..3fd3bec2 100644 --- a/TransactionProcessor.BusinessLogic/OperatorInterfaces/PataPawaPrePay/PataPawaPrePayProxy.cs +++ b/TransactionProcessor.BusinessLogic/OperatorInterfaces/PataPawaPrePay/PataPawaPrePayProxy.cs @@ -6,7 +6,7 @@ using System.Threading; using System.Threading.Tasks; using Common; -using EstateManagement.DataTransferObjects.Responses; +using EstateManagement.DataTransferObjects.Responses.Merchant; using Microsoft.Extensions.Caching.Memory; using Newtonsoft.Json; using Shared.Logger; @@ -56,7 +56,7 @@ public async Task ProcessLogonMessage(String accessToken, Canc } public async Task ProcessSaleMessage(String accessToken, Guid transactionId, Guid operatorId, - EstateManagement.DataTransferObjects.Responses.Merchant.MerchantResponse merchant, DateTime transactionDateTime, String transactionReference, Dictionary additionalTransactionMetadata, CancellationToken cancellationToken){ + MerchantResponse merchant, DateTime transactionDateTime, String transactionReference, Dictionary additionalTransactionMetadata, CancellationToken cancellationToken){ // Get the logon response for the operator OperatorResponse logonResponse = this.MemoryCache.Get("PataPawaPrePayLogon"); if (logonResponse == null) diff --git a/TransactionProcessor.BusinessLogic/OperatorInterfaces/SafaricomPinless/SafaricomPinlessProxy.cs b/TransactionProcessor.BusinessLogic/OperatorInterfaces/SafaricomPinless/SafaricomPinlessProxy.cs index c961657f..b3369067 100644 --- a/TransactionProcessor.BusinessLogic/OperatorInterfaces/SafaricomPinless/SafaricomPinlessProxy.cs +++ b/TransactionProcessor.BusinessLogic/OperatorInterfaces/SafaricomPinless/SafaricomPinlessProxy.cs @@ -11,7 +11,7 @@ using System.Xml; using System.Xml.Serialization; using Common; - using EstateManagement.DataTransferObjects.Responses; + using EstateManagement.DataTransferObjects.Responses.Merchant; using Shared.Logger; /// @@ -74,7 +74,7 @@ public async Task ProcessLogonMessage(String accessToken, public async Task ProcessSaleMessage(String accessToken, Guid transactionId, Guid operatorId, - EstateManagement.DataTransferObjects.Responses.Merchant.MerchantResponse merchant, + MerchantResponse merchant, DateTime transactionDateTime, String transactionReference, Dictionary additionalTransactionMetadata, diff --git a/TransactionProcessor.BusinessLogic/OperatorInterfaces/VoucherManagement/VoucherManagementProxy.cs b/TransactionProcessor.BusinessLogic/OperatorInterfaces/VoucherManagement/VoucherManagementProxy.cs index a909e237..d68c0795 100644 --- a/TransactionProcessor.BusinessLogic/OperatorInterfaces/VoucherManagement/VoucherManagementProxy.cs +++ b/TransactionProcessor.BusinessLogic/OperatorInterfaces/VoucherManagement/VoucherManagementProxy.cs @@ -8,11 +8,9 @@ namespace TransactionProcessor.BusinessLogic.OperatorInterfaces.VoucherManagemen using System.Threading; using System.Threading.Tasks; using Common; - using EstateManagement.DataTransferObjects.Responses; + using EstateManagement.DataTransferObjects.Responses.Merchant; using IdentityModel.Client; using MediatR; - //using global::VoucherManagement.Client; - //using global::VoucherManagement.DataTransferObjects; using Microsoft.EntityFrameworkCore.Storage.ValueConversion.Internal; using Microsoft.Identity.Client; using Models; @@ -56,7 +54,7 @@ public async Task ProcessLogonMessage(String accessToken, public async Task ProcessSaleMessage(String accessToken, Guid transactionId, Guid operatorId, - EstateManagement.DataTransferObjects.Responses.Merchant.MerchantResponse merchant, + MerchantResponse merchant, DateTime transactionDateTime, String transactionReference, Dictionary additionalTransactionMetadata, diff --git a/TransactionProcessor.BusinessLogic/Services/TransactionResponseCode.cs b/TransactionProcessor.BusinessLogic/Services/TransactionResponseCode.cs index 0c9881e6..9feb7bca 100644 --- a/TransactionProcessor.BusinessLogic/Services/TransactionResponseCode.cs +++ b/TransactionProcessor.BusinessLogic/Services/TransactionResponseCode.cs @@ -22,6 +22,8 @@ public enum TransactionResponseCode MerchantHasNoContractsConfigured = 1014, ContractNotValidForMerchant = 1015, ProductNotValidForMerchant = 1016, + OperatorNotEnabledForEstate = 1017, + OperatorNotEnabledForMerchant = 1018, // A Catch All generic Error where reason has not been identified UnknownFailure = 9999 diff --git a/TransactionProcessor.BusinessLogic/Services/TransactionValidationService.cs b/TransactionProcessor.BusinessLogic/Services/TransactionValidationService.cs index cf802cb9..4deba2a6 100644 --- a/TransactionProcessor.BusinessLogic/Services/TransactionValidationService.cs +++ b/TransactionProcessor.BusinessLogic/Services/TransactionValidationService.cs @@ -141,6 +141,12 @@ public TransactionValidationService(IEstateClient estateClient, TransactionResponseCode.OperatorNotValidForEstate); } + // Check the operator is enabled and not deleted + if (estateOperatorRecord.IsDeleted){ + throw new TransactionValidationException($"Operator {operatorId} not enabled for Estate [{estate.EstateName}]", + TransactionResponseCode.OperatorNotEnabledForEstate); + } + // Device Validation if (merchant.Devices == null || merchant.Devices.Any() == false){ throw new TransactionValidationException($"Merchant {merchant.MerchantName} has no valid Devices for this transaction.", @@ -168,8 +174,15 @@ public TransactionValidationService(IEstateClient estateClient, throw new TransactionValidationException($"Operator {operatorId} not configured for Merchant [{merchant.MerchantName}]", TransactionResponseCode.OperatorNotValidForMerchant); } - } + // Check the operator is enabled and not deleted + if (merchantOperatorRecord.IsDeleted) + { + throw new TransactionValidationException($"Operator {operatorId} not enabled for Merchant [{merchant.MerchantName}]", + TransactionResponseCode.OperatorNotEnabledForMerchant); + } + } + // Contract and Product Validation if (contractId == Guid.Empty){ throw new TransactionValidationException($"Contract Id [{contractId}] must be set for a sale transaction", diff --git a/TransactionProcessor.BusinessLogic/TransactionProcessor.BusinessLogic.csproj b/TransactionProcessor.BusinessLogic/TransactionProcessor.BusinessLogic.csproj index 02ea90ad..38b2210a 100644 --- a/TransactionProcessor.BusinessLogic/TransactionProcessor.BusinessLogic.csproj +++ b/TransactionProcessor.BusinessLogic/TransactionProcessor.BusinessLogic.csproj @@ -5,11 +5,11 @@ - - + + - - + + diff --git a/TransactionProcessor.IntegrationTesting.Helpers/TransactionProcessor.IntegrationTesting.Helpers.csproj b/TransactionProcessor.IntegrationTesting.Helpers/TransactionProcessor.IntegrationTesting.Helpers.csproj index c82d4a8b..bcfe050e 100644 --- a/TransactionProcessor.IntegrationTesting.Helpers/TransactionProcessor.IntegrationTesting.Helpers.csproj +++ b/TransactionProcessor.IntegrationTesting.Helpers/TransactionProcessor.IntegrationTesting.Helpers.csproj @@ -7,8 +7,8 @@ - - + + diff --git a/TransactionProcessor.IntegrationTests/Common/TestingContext.cs b/TransactionProcessor.IntegrationTests/Common/TestingContext.cs index 06c0929c..562a8c49 100644 --- a/TransactionProcessor.IntegrationTests/Common/TestingContext.cs +++ b/TransactionProcessor.IntegrationTests/Common/TestingContext.cs @@ -7,6 +7,7 @@ using System.Threading.Tasks; using DataTransferObjects; using EstateManagement.DataTransferObjects.Responses; + using EstateManagement.DataTransferObjects.Responses.Merchant; using EstateManagement.IntegrationTesting.Helpers; using global::Shared.IntegrationTesting; using global::Shared.Logger; diff --git a/TransactionProcessor.IntegrationTests/TransactionProcessor.IntegrationTests.csproj b/TransactionProcessor.IntegrationTests/TransactionProcessor.IntegrationTests.csproj index 8792185e..d45be436 100644 --- a/TransactionProcessor.IntegrationTests/TransactionProcessor.IntegrationTests.csproj +++ b/TransactionProcessor.IntegrationTests/TransactionProcessor.IntegrationTests.csproj @@ -9,14 +9,14 @@ - - + + - - + + @@ -28,7 +28,7 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive - + diff --git a/TransactionProcessor.ProjectionEngine/TransactionProcessor.ProjectionEngine.csproj b/TransactionProcessor.ProjectionEngine/TransactionProcessor.ProjectionEngine.csproj index c8e6abec..9aa41a07 100644 --- a/TransactionProcessor.ProjectionEngine/TransactionProcessor.ProjectionEngine.csproj +++ b/TransactionProcessor.ProjectionEngine/TransactionProcessor.ProjectionEngine.csproj @@ -7,10 +7,10 @@ - - - - + + + + diff --git a/TransactionProcessor.Testing/TestData.cs b/TransactionProcessor.Testing/TestData.cs index 8041d2f3..56b1553d 100644 --- a/TransactionProcessor.Testing/TestData.cs +++ b/TransactionProcessor.Testing/TestData.cs @@ -8,8 +8,7 @@ using BusinessLogic.OperatorInterfaces.SafaricomPinless; using BusinessLogic.Requests; using BusinessLogic.Services; - using EstateManagement.DataTransferObjects; - using EstateManagement.DataTransferObjects.Responses; + using EstateManagement.DataTransferObjects.Responses.Merchant; using EstateManagement.DataTransferObjects.Responses.Contract; using EstateManagement.DataTransferObjects.Responses.Estate; using FloatAggregate; @@ -364,6 +363,24 @@ public static Dictionary AdditionalTransactionMetaDataForPataPaw } }; + public static EstateResponse GetEstateResponseWithOperator1Deleted => + new EstateResponse + { + EstateName = TestData.EstateName, + EstateId = TestData.EstateId, + Operators = new List + { + new EstateOperatorResponse + { + Name = "Safaricom", + OperatorId = TestData.OperatorId, + RequireCustomMerchantNumber = TestData.RequireCustomMerchantNumber, + RequireCustomTerminalNumber = TestData.RequireCustomTerminalNumber, + IsDeleted = true + } + } + }; + public static EstateResponse GetEstateResponseWithOperator2 => new EstateResponse { @@ -414,7 +431,59 @@ public static Dictionary AdditionalTransactionMetaDataForPataPaw MerchantNumber = TestData.MerchantNumber, TerminalNumber = TestData.TerminalNumber } - } + }, + Contracts = new List{ + new MerchantContractResponse{ + ContractId = TestData.ContractId, + ContractProducts = new List(){ + TestData.ProductId + } + } + } + }; + + public static EstateManagement.DataTransferObjects.Responses.Merchant.MerchantResponse GetMerchantResponseWithOperator1AndNullContracts => + new EstateManagement.DataTransferObjects.Responses.Merchant.MerchantResponse + { + EstateId = TestData.EstateId, + MerchantId = TestData.MerchantId, + MerchantName = TestData.MerchantName, + Devices = new Dictionary + { + {TestData.DeviceId, TestData.DeviceIdentifier} + }, + Operators = new List + { + new EstateManagement.DataTransferObjects.Responses.Merchant.MerchantOperatorResponse + { + OperatorId = TestData.OperatorId, + MerchantNumber = TestData.MerchantNumber, + TerminalNumber = TestData.TerminalNumber + } + }, + Contracts = null + }; + + public static EstateManagement.DataTransferObjects.Responses.Merchant.MerchantResponse GetMerchantResponseWithOperator1AndEmptyContracts => + new EstateManagement.DataTransferObjects.Responses.Merchant.MerchantResponse + { + EstateId = TestData.EstateId, + MerchantId = TestData.MerchantId, + MerchantName = TestData.MerchantName, + Devices = new Dictionary + { + {TestData.DeviceId, TestData.DeviceIdentifier} + }, + Operators = new List + { + new EstateManagement.DataTransferObjects.Responses.Merchant.MerchantOperatorResponse + { + OperatorId = TestData.OperatorId, + MerchantNumber = TestData.MerchantNumber, + TerminalNumber = TestData.TerminalNumber + } + }, + Contracts = new List() }; @@ -439,6 +508,37 @@ public static Dictionary AdditionalTransactionMetaDataForPataPaw } }; + public static MerchantResponse GetMerchantResponseWithOperator1Deleted => + new MerchantResponse + { + EstateId = TestData.EstateId, + MerchantId = TestData.MerchantId, + MerchantName = TestData.MerchantName, + Devices = new Dictionary + { + {TestData.DeviceId, TestData.DeviceIdentifier} + }, + Operators = new List + { + new EstateManagement.DataTransferObjects.Responses.Merchant.MerchantOperatorResponse + { + OperatorId = TestData.OperatorId, + MerchantNumber = TestData.MerchantNumber, + TerminalNumber = TestData.TerminalNumber, + IsDeleted = true + + } + }, + Contracts = new List{ + new MerchantContractResponse{ + ContractId = TestData.ContractId, + ContractProducts = new List(){ + TestData.ProductId + } + } + } + }; + public static MerchantResponse GetMerchantResponseWithNoDevices => new MerchantResponse { @@ -1042,16 +1142,32 @@ public static TokenResponse TokenResponse() new Dictionary() }; - public static MerchantBalanceState MerchantBalanceProjectionState => - new MerchantBalanceState { - AvailableBalance = TestData.AvailableBalance, - }; - public static MerchantBalanceState MerchantBalanceProjectionStateNoCredit => - new MerchantBalanceState - { - AvailableBalance = 0, - }; - + public static String MerchantStateId = "Merchant1"; + + public static Merchant MerchantState = new Merchant(TestData.MerchantStateId, + TestData.MerchantName, + 1, + TestData.AvailableBalance, + new Deposits(1, 100.00m, DateTime.Now.AddDays(-1)), + new Withdrawals(0, 0, null), + new AuthorisedSales(1, 55.0m, DateTime.Now), + new DeclinedSales(0, 0, null), + new Fees(0, 0)); + + public static Merchant MerchantStateNoCredit = new Merchant(TestData.MerchantStateId, + TestData.MerchantName, + 1, + 0, + new Deposits(1, 100.00m, DateTime.Now.AddDays(-1)), + new Withdrawals(0, 0, null), + new AuthorisedSales(1, 55.0m, DateTime.Now), + new DeclinedSales(0, 0, null), + new Fees(0, 0)); + + public static MerchantBalanceProjectionState1 MerchantBalanceProjectionState => new MerchantBalanceProjectionState1(TestData.MerchantState); + + public static MerchantBalanceProjectionState1 MerchantBalanceProjectionStateNoCredit => new MerchantBalanceProjectionState1(TestData.MerchantStateNoCredit); + public static ResendTransactionReceiptRequest ResendTransactionReceiptRequest => ResendTransactionReceiptRequest.Create(TestData.TransactionId, TestData.EstateId);