diff --git a/TransactionProcessor.BusinessLogic.Tests/Requests/RequestTests.cs b/TransactionProcessor.BusinessLogic.Tests/Requests/RequestTests.cs index d003dc0c..25899284 100644 --- a/TransactionProcessor.BusinessLogic.Tests/Requests/RequestTests.cs +++ b/TransactionProcessor.BusinessLogic.Tests/Requests/RequestTests.cs @@ -34,7 +34,9 @@ public void ProcessSaleTransactionRequest_CanBeCreated_IsCreated() TestData.TransactionNumber, TestData.OperatorIdentifier1, TestData.CustomerEmailAddress, - TestData.AdditionalTransactionMetaData); + TestData.AdditionalTransactionMetaData, + TestData.ContractId, + TestData.ProductId); processSaleTransactionRequest.ShouldNotBeNull(); processSaleTransactionRequest.EstateId.ShouldBe(TestData.EstateId); @@ -48,6 +50,8 @@ public void ProcessSaleTransactionRequest_CanBeCreated_IsCreated() processSaleTransactionRequest.CustomerEmailAddress.ShouldBe(TestData.CustomerEmailAddress); processSaleTransactionRequest.AdditionalTransactionMetadata.ShouldNotBeNull(); processSaleTransactionRequest.AdditionalTransactionMetadata.Count.ShouldBe(TestData.AdditionalTransactionMetaData.Count); + processSaleTransactionRequest.ContractId.ShouldBe(TestData.ContractId); + processSaleTransactionRequest.ProductId.ShouldBe(TestData.ProductId); } } } diff --git a/TransactionProcessor.BusinessLogic.Tests/Services/TransactionAggregateManagerTests.cs b/TransactionProcessor.BusinessLogic.Tests/Services/TransactionAggregateManagerTests.cs index 2042a1c2..36287b96 100644 --- a/TransactionProcessor.BusinessLogic.Tests/Services/TransactionAggregateManagerTests.cs +++ b/TransactionProcessor.BusinessLogic.Tests/Services/TransactionAggregateManagerTests.cs @@ -219,5 +219,19 @@ await transactionAggregateManager.RequestEmailReceipt(TestData.EstateId, TestData.CustomerEmailAddress, CancellationToken.None); } + + [Fact] + public async Task TransactionAggregateManager_AddProductDetails_ProductDetailsAddedToTransaction() + { + Mock> aggregateRepository = new Mock>(); + aggregateRepository.Setup(a => a.GetLatestVersion(It.IsAny(), It.IsAny())).ReturnsAsync(TestData.GetStartedTransactionAggregate()); + TransactionAggregateManager transactionAggregateManager = new TransactionAggregateManager(aggregateRepository.Object); + + await transactionAggregateManager.AddProductDetails(TestData.EstateId, + TestData.TransactionId, + TestData.ContractId, + TestData.ProductId, + CancellationToken.None); + } } } diff --git a/TransactionProcessor.BusinessLogic.Tests/Services/TransactionDomainServiceTests.cs b/TransactionProcessor.BusinessLogic.Tests/Services/TransactionDomainServiceTests.cs index 40328702..fbaf245a 100644 --- a/TransactionProcessor.BusinessLogic.Tests/Services/TransactionDomainServiceTests.cs +++ b/TransactionProcessor.BusinessLogic.Tests/Services/TransactionDomainServiceTests.cs @@ -292,6 +292,8 @@ public async Task TransactionDomainService_ProcessSaleTransaction_SuccesfulOpera TestData.OperatorIdentifier1, TestData.CustomerEmailAddress, TestData.AdditionalTransactionMetaData, + TestData.ContractId, + TestData.ProductId, CancellationToken.None); this.ValidateResponse(response, TransactionResponseCode.Success); @@ -343,6 +345,8 @@ public async Task TransactionDomainService_ProcessSaleTransaction_FailedOperator TestData.OperatorIdentifier1, TestData.CustomerEmailAddress, TestData.AdditionalTransactionMetaData, + TestData.ContractId, + TestData.ProductId, CancellationToken.None); this.ValidateResponse(response, TransactionResponseCode.TransactionDeclinedByOperator); @@ -382,6 +386,8 @@ public async Task TransactionDomainService_ProcessSaleTransaction_MerchantWithNu TestData.OperatorIdentifier1, TestData.CustomerEmailAddress, TestData.AdditionalTransactionMetaData, + TestData.ContractId, + TestData.ProductId, CancellationToken.None); this.ValidateResponse(response, TransactionResponseCode.NoValidDevices); @@ -422,6 +428,8 @@ public async Task TransactionDomainService_ProcessSaleTransaction_MerchantWithNo TestData.OperatorIdentifier1, TestData.CustomerEmailAddress, TestData.AdditionalTransactionMetaData, + TestData.ContractId, + TestData.ProductId, CancellationToken.None); this.ValidateResponse(response, TransactionResponseCode.NoValidDevices); @@ -461,6 +469,8 @@ public async Task TransactionDomainService_ProcessSaleTransaction_IncorrectDevic TestData.OperatorIdentifier1, TestData.CustomerEmailAddress, TestData.AdditionalTransactionMetaData, + TestData.ContractId, + TestData.ProductId, CancellationToken.None); this.ValidateResponse(response, TransactionResponseCode.InvalidDeviceIdentifier); @@ -500,6 +510,8 @@ public async Task TransactionDomainService_ProcessSaleTransaction_InvalidEstate_ TestData.OperatorIdentifier1, TestData.CustomerEmailAddress, TestData.AdditionalTransactionMetaData, + TestData.ContractId, + TestData.ProductId, CancellationToken.None); this.ValidateResponse(response, TransactionResponseCode.InvalidEstateId); @@ -539,6 +551,8 @@ public async Task TransactionDomainService_ProcessSaleTransaction_NotEnoughCredi TestData.OperatorIdentifier1, TestData.CustomerEmailAddress, TestData.AdditionalTransactionMetaData, + TestData.ContractId, + TestData.ProductId, CancellationToken.None); this.ValidateResponse(response, TransactionResponseCode.MerchantDoesNotHaveEnoughCredit); @@ -560,8 +574,7 @@ public async Task TransactionDomainService_ProcessSaleTransaction_InvalidMerchan securityServiceClient.Setup(s => s.GetToken(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(TestData.TokenResponse); estateClient.Setup(e => e.GetEstate(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(TestData.GetEstateResponseWithOperator1); - estateClient.Setup(e => e.GetMerchant(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) - .ReturnsAsync(TestData.GetEmptyMerchantResponse); + estateClient.Setup(e => e.GetMerchant(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())).ThrowsAsync(new Exception("Exception", new KeyNotFoundException("Invalid Merchant"))); transactionAggregateManager.Setup(t => t.GetAggregate(It.IsAny(), It.IsAny(), It.IsAny())) .ReturnsAsync(TestData.GetLocallyDeclinedTransactionAggregate(TransactionResponseCode.InvalidMerchantId)); @@ -578,6 +591,8 @@ public async Task TransactionDomainService_ProcessSaleTransaction_InvalidMerchan TestData.OperatorIdentifier1, TestData.CustomerEmailAddress, TestData.AdditionalTransactionMetaData, + TestData.ContractId, + TestData.ProductId, CancellationToken.None); this.ValidateResponse(response, TransactionResponseCode.InvalidMerchantId); @@ -617,6 +632,8 @@ public async Task TransactionDomainService_ProcessSaleTransaction_EstateWithEmpt TestData.OperatorIdentifier1, TestData.CustomerEmailAddress, TestData.AdditionalTransactionMetaData, + TestData.ContractId, + TestData.ProductId, CancellationToken.None); this.ValidateResponse(response, TransactionResponseCode.NoEstateOperators); @@ -656,6 +673,8 @@ public async Task TransactionDomainService_ProcessSaleTransaction_EstateWithNull TestData.OperatorIdentifier1, TestData.CustomerEmailAddress, TestData.AdditionalTransactionMetaData, + TestData.ContractId, + TestData.ProductId, CancellationToken.None); this.ValidateResponse(response, TransactionResponseCode.NoEstateOperators); @@ -695,6 +714,8 @@ public async Task TransactionDomainService_ProcessSaleTransaction_OperatorNotSup TestData.OperatorIdentifier2, TestData.CustomerEmailAddress, TestData.AdditionalTransactionMetaData, + TestData.ContractId, + TestData.ProductId, CancellationToken.None); this.ValidateResponse(response, TransactionResponseCode.OperatorNotValidForEstate); @@ -734,6 +755,8 @@ public async Task TransactionDomainService_ProcessSaleTransaction_MerchantWithEm TestData.OperatorIdentifier1, TestData.CustomerEmailAddress, TestData.AdditionalTransactionMetaData, + TestData.ContractId, + TestData.ProductId, CancellationToken.None); this.ValidateResponse(response, TransactionResponseCode.NoMerchantOperators); @@ -773,6 +796,8 @@ public async Task TransactionDomainService_ProcessSaleTransaction_MerchantWithNu TestData.OperatorIdentifier1, TestData.CustomerEmailAddress, TestData.AdditionalTransactionMetaData, + TestData.ContractId, + TestData.ProductId, CancellationToken.None); this.ValidateResponse(response, TransactionResponseCode.NoMerchantOperators); @@ -812,6 +837,8 @@ public async Task TransactionDomainService_ProcessSaleTransaction_OperatorNotSup TestData.OperatorIdentifier1, TestData.CustomerEmailAddress, TestData.AdditionalTransactionMetaData, + TestData.ContractId, + TestData.ProductId, CancellationToken.None); this.ValidateResponse(response, TransactionResponseCode.OperatorNotValidForMerchant); diff --git a/TransactionProcessor.BusinessLogic/RequestHandlers/TransactionRequestHandler.cs b/TransactionProcessor.BusinessLogic/RequestHandlers/TransactionRequestHandler.cs index 33d66bd1..ed244832 100644 --- a/TransactionProcessor.BusinessLogic/RequestHandlers/TransactionRequestHandler.cs +++ b/TransactionProcessor.BusinessLogic/RequestHandlers/TransactionRequestHandler.cs @@ -76,6 +76,8 @@ public async Task Handle(ProcessSaleTransactionR request.OperatorIdentifier, request.CustomerEmailAddress, request.AdditionalTransactionMetadata, + request.ContractId, + request.ProductId, cancellationToken); return saleResponse; diff --git a/TransactionProcessor.BusinessLogic/Requests/ProcessSaleTransactionRequest.cs b/TransactionProcessor.BusinessLogic/Requests/ProcessSaleTransactionRequest.cs index 0ed59628..ecfb45b0 100644 --- a/TransactionProcessor.BusinessLogic/Requests/ProcessSaleTransactionRequest.cs +++ b/TransactionProcessor.BusinessLogic/Requests/ProcessSaleTransactionRequest.cs @@ -1,11 +1,8 @@ -using System; -using System.Collections.Generic; -using System.Text; - -namespace TransactionProcessor.BusinessLogic.Requests +namespace TransactionProcessor.BusinessLogic.Requests { + using System; + using System.Collections.Generic; using MediatR; - using Microsoft.EntityFrameworkCore.Storage.ValueConversion; using Models; public class ProcessSaleTransactionRequest : IRequest @@ -25,6 +22,8 @@ public class ProcessSaleTransactionRequest : IRequestThe operator identifier. /// The customer email address. /// The additional transaction metadata. + /// The contract identifier. + /// The product identifier. private ProcessSaleTransactionRequest(Guid transactionId, Guid estateId, Guid merchantId, @@ -34,7 +33,9 @@ private ProcessSaleTransactionRequest(Guid transactionId, String transactionNumber, String operatorIdentifier, String customerEmailAddress, - Dictionary additionalTransactionMetadata) + Dictionary additionalTransactionMetadata, + Guid contractId, + Guid productId) { this.TransactionId = transactionId; this.EstateId = estateId; @@ -45,6 +46,8 @@ private ProcessSaleTransactionRequest(Guid transactionId, this.OperatorIdentifier = operatorIdentifier; this.CustomerEmailAddress = customerEmailAddress; this.AdditionalTransactionMetadata = additionalTransactionMetadata; + this.ContractId = contractId; + this.ProductId = productId; this.TransactionType = transactionType; } @@ -52,6 +55,22 @@ private ProcessSaleTransactionRequest(Guid transactionId, #region Properties + /// + /// Gets or sets the additional transaction metadata. + /// + /// + /// The additional transaction metadata. + /// + public Dictionary AdditionalTransactionMetadata { get; } + + /// + /// Gets the customer email address. + /// + /// + /// The customer email address. + /// + public String CustomerEmailAddress { get; } + /// /// Gets the device identifier. /// @@ -76,6 +95,14 @@ private ProcessSaleTransactionRequest(Guid transactionId, /// public Guid MerchantId { get; } + /// + /// Gets or sets the operator identifier. + /// + /// + /// The operator identifier. + /// + public String OperatorIdentifier { get; } + /// /// Gets the transaction date time. /// @@ -109,28 +136,20 @@ private ProcessSaleTransactionRequest(Guid transactionId, public String TransactionType { get; } /// - /// Gets or sets the operator identifier. - /// - /// - /// The operator identifier. - /// - public String OperatorIdentifier { get; } - - /// - /// Gets the customer email address. + /// Gets the contract identifier. /// /// - /// The customer email address. + /// The contract identifier. /// - public String CustomerEmailAddress { get; private set; } + public Guid ContractId { get; } /// - /// Gets or sets the additional transaction metadata. + /// Gets the product identifier. /// /// - /// The additional transaction metadata. + /// The product identifier. /// - public Dictionary AdditionalTransactionMetadata { get; } + public Guid ProductId { get; } #endregion @@ -149,6 +168,8 @@ private ProcessSaleTransactionRequest(Guid transactionId, /// The operator identifier. /// The customer email address. /// The additional transaction metadata. + /// The contract identifier. + /// The product identifier. /// public static ProcessSaleTransactionRequest Create(Guid transactionId, Guid estateId, @@ -159,7 +180,9 @@ public static ProcessSaleTransactionRequest Create(Guid transactionId, String transactionNumber, String operatorIdentifier, String customerEmailAddress, - Dictionary additionalTransactionMetadata) + Dictionary additionalTransactionMetadata, + Guid contractId, + Guid productId) { return new ProcessSaleTransactionRequest(transactionId, estateId, @@ -170,9 +193,11 @@ public static ProcessSaleTransactionRequest Create(Guid transactionId, transactionNumber, operatorIdentifier, customerEmailAddress, - additionalTransactionMetadata); + additionalTransactionMetadata, + contractId, + productId); } #endregion } -} +} \ No newline at end of file diff --git a/TransactionProcessor.BusinessLogic/Services/ITransactionAggregateManager.cs b/TransactionProcessor.BusinessLogic/Services/ITransactionAggregateManager.cs index 75b2ca30..ecbbce9f 100644 --- a/TransactionProcessor.BusinessLogic/Services/ITransactionAggregateManager.cs +++ b/TransactionProcessor.BusinessLogic/Services/ITransactionAggregateManager.cs @@ -15,6 +15,21 @@ public interface ITransactionAggregateManager { #region Methods + /// + /// Adds the product details. + /// + /// The estate identifier. + /// The transaction identifier. + /// The contract identifier. + /// The product identifier. + /// The cancellation token. + /// + Task AddProductDetails(Guid estateId, + Guid transactionId, + Guid contractId, + Guid productId, + CancellationToken cancellationToken); + /// /// Authorises the transaction. /// @@ -60,19 +75,6 @@ Task CompleteTransaction(Guid estateId, Guid transactionId, CancellationToken cancellationToken); - /// - /// Requests the email receipt. - /// - /// The estate identifier. - /// The transaction identifier. - /// The customer email address. - /// The cancellation token. - /// - Task RequestEmailReceipt(Guid estateId, - Guid transactionId, - String customerEmailAddress, - CancellationToken cancellationToken); - /// /// Declines the transaction. /// @@ -146,6 +148,19 @@ Task RecordAdditionalResponseData(Guid estateId, Dictionary additionalTransactionResponseMetadata, CancellationToken cancellationToken); + /// + /// Requests the email receipt. + /// + /// The estate identifier. + /// The transaction identifier. + /// The customer email address. + /// The cancellation token. + /// + Task RequestEmailReceipt(Guid estateId, + Guid transactionId, + String customerEmailAddress, + CancellationToken cancellationToken); + /// /// Starts the transaction. /// diff --git a/TransactionProcessor.BusinessLogic/Services/ITransactionDomainService.cs b/TransactionProcessor.BusinessLogic/Services/ITransactionDomainService.cs index 0f56c253..17e5b5fc 100644 --- a/TransactionProcessor.BusinessLogic/Services/ITransactionDomainService.cs +++ b/TransactionProcessor.BusinessLogic/Services/ITransactionDomainService.cs @@ -44,6 +44,8 @@ Task ProcessLogonTransaction(Guid transactionId /// The operator identifier. /// The customer email address. /// The additional transaction metadata. + /// The contract identifier. + /// The product identifier. /// The cancellation token. /// Task ProcessSaleTransaction(Guid transactionId, @@ -55,6 +57,8 @@ Task ProcessSaleTransaction(Guid transactionId, String operatorId, String customerEmailAddress, Dictionary additionalTransactionMetadata, + Guid contractId, + Guid productId, CancellationToken cancellationToken); #endregion diff --git a/TransactionProcessor.BusinessLogic/Services/TransactionAggregateManager.cs b/TransactionProcessor.BusinessLogic/Services/TransactionAggregateManager.cs index eaf4c6ff..f32fa01b 100644 --- a/TransactionProcessor.BusinessLogic/Services/TransactionAggregateManager.cs +++ b/TransactionProcessor.BusinessLogic/Services/TransactionAggregateManager.cs @@ -40,6 +40,27 @@ public TransactionAggregateManager(IAggregateRepository tr #region Methods + /// + /// Adds the product details. + /// + /// The estate identifier. + /// The transaction identifier. + /// The contract identifier. + /// The product identifier. + /// The cancellation token. + public async Task AddProductDetails(Guid estateId, + Guid transactionId, + Guid contractId, + Guid productId, + CancellationToken cancellationToken) + { + TransactionAggregate transactionAggregate = await this.TransactionAggregateRepository.GetLatestVersion(transactionId, cancellationToken); + + transactionAggregate.AddProductDetails(contractId, productId); + + await this.TransactionAggregateRepository.SaveChanges(transactionAggregate, cancellationToken); + } + /// /// Authorises the transaction. /// @@ -227,7 +248,10 @@ public async Task RecordAdditionalResponseData(Guid estateId, /// The estate identifier. /// The transaction identifier. /// The cancellation token. - public async Task RequestEmailReceipt(Guid estateId, Guid transactionId, String customerEmailAddress, CancellationToken cancellationToken) + public async Task RequestEmailReceipt(Guid estateId, + Guid transactionId, + String customerEmailAddress, + CancellationToken cancellationToken) { TransactionAggregate transactionAggregate = await this.TransactionAggregateRepository.GetLatestVersion(transactionId, cancellationToken); @@ -262,7 +286,14 @@ public async Task StartTransaction(Guid transactionId, { TransactionAggregate transactionAggregate = await this.TransactionAggregateRepository.GetLatestVersion(transactionId, cancellationToken); - transactionAggregate.StartTransaction(transactionDateTime, transactionNumber, transactionType, transactionReference, estateId, merchantId, deviceIdentifier, transactionAmount); + transactionAggregate.StartTransaction(transactionDateTime, + transactionNumber, + transactionType, + transactionReference, + estateId, + merchantId, + deviceIdentifier, + transactionAmount); await this.TransactionAggregateRepository.SaveChanges(transactionAggregate, cancellationToken); } diff --git a/TransactionProcessor.BusinessLogic/Services/TransactionDomainService.cs b/TransactionProcessor.BusinessLogic/Services/TransactionDomainService.cs index cf971820..89343b10 100644 --- a/TransactionProcessor.BusinessLogic/Services/TransactionDomainService.cs +++ b/TransactionProcessor.BusinessLogic/Services/TransactionDomainService.cs @@ -146,6 +146,8 @@ await this.TransactionAggregateManager.StartTransaction(transactionId, /// 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, @@ -157,6 +159,8 @@ public async Task ProcessSaleTransaction(Guid tr String operatorIdentifier, String customerEmailAddress, Dictionary additionalTransactionMetadata, + Guid contractId, + Guid productId, CancellationToken cancellationToken) { TransactionType transactionType = TransactionType.Sale; @@ -183,6 +187,9 @@ await this.TransactionAggregateManager.StartTransaction(transactionId, if (validationResult.responseCode == TransactionResponseCode.Success) { + // Add the product details + await this.TransactionAggregateManager.AddProductDetails(estateId, transactionId, contractId, productId, cancellationToken); + // Record any additional request metadata await this.TransactionAggregateManager.RecordAdditionalRequestData(estateId, transactionId, diff --git a/TransactionProcessor.BusinessLogic/TransactionProcessor.BusinessLogic.csproj b/TransactionProcessor.BusinessLogic/TransactionProcessor.BusinessLogic.csproj index 46fe7c06..dd39f933 100644 --- a/TransactionProcessor.BusinessLogic/TransactionProcessor.BusinessLogic.csproj +++ b/TransactionProcessor.BusinessLogic/TransactionProcessor.BusinessLogic.csproj @@ -5,7 +5,7 @@ - + diff --git a/TransactionProcessor.DataTransferObjects/SaleTransactionRequest.cs b/TransactionProcessor.DataTransferObjects/SaleTransactionRequest.cs index e2062053..4cd21085 100644 --- a/TransactionProcessor.DataTransferObjects/SaleTransactionRequest.cs +++ b/TransactionProcessor.DataTransferObjects/SaleTransactionRequest.cs @@ -1,45 +1,45 @@ -using System; -using System.Collections.Generic; -using System.Text; - -namespace TransactionProcessor.DataTransferObjects +namespace TransactionProcessor.DataTransferObjects { + using System; + using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; [ExcludeFromCodeCoverage] public class SaleTransactionRequest : DataTransferObject { + #region Properties + /// - /// Gets or sets the device identifier. + /// Gets or sets the additional transaction metadata. /// /// - /// The device identifier. + /// The additional transaction metadata. /// - public String DeviceIdentifier { get; set; } + public Dictionary AdditionalTransactionMetadata { get; set; } /// - /// Gets or sets the transaction date time. + /// Gets or sets the contract identifier. /// /// - /// The transaction date time. + /// The contract identifier. /// - public DateTime TransactionDateTime { get; set; } + public Guid ContractId { get; set; } /// - /// Gets or sets the transaction number. + /// Gets or sets the customer email address. /// /// - /// The transaction number. + /// The customer email address. /// - public String TransactionNumber { get; set; } + public String CustomerEmailAddress { get; set; } /// - /// Gets or sets the type of the transaction. + /// Gets or sets the device identifier. /// /// - /// The type of the transaction. + /// The device identifier. /// - public String TransactionType { get; set; } + public String DeviceIdentifier { get; set; } /// /// Gets or sets the operator identifier. @@ -50,19 +50,37 @@ public class SaleTransactionRequest : DataTransferObject public String OperatorIdentifier { get; set; } /// - /// Gets or sets the customer email address. + /// Gets or sets the product identifier. /// /// - /// The customer email address. + /// The product identifier. /// - public String CustomerEmailAddress { get; set; } + public Guid ProductId { get; set; } /// - /// Gets or sets the additional transaction metadata. + /// Gets or sets the transaction date time. /// /// - /// The additional transaction metadata. + /// The transaction date time. /// - public Dictionary AdditionalTransactionMetadata { get; set; } + public DateTime TransactionDateTime { get; set; } + + /// + /// Gets or sets the transaction number. + /// + /// + /// The transaction number. + /// + public String TransactionNumber { get; set; } + + /// + /// Gets or sets the type of the transaction. + /// + /// + /// The type of the transaction. + /// + public String TransactionType { get; set; } + + #endregion } -} +} \ No newline at end of file diff --git a/TransactionProcessor.IntegrationTests/Common/ClientDetails.cs b/TransactionProcessor.IntegrationTests/Common/ClientDetails.cs new file mode 100644 index 00000000..7b59d3b7 --- /dev/null +++ b/TransactionProcessor.IntegrationTests/Common/ClientDetails.cs @@ -0,0 +1,75 @@ +namespace TransactionProcessor.IntegrationTests.Common +{ + using System; + + /// + /// + /// + public class ClientDetails + { + #region Constructors + + /// + /// Initializes a new instance of the class. + /// + /// The client identifier. + /// The client secret. + /// Type of the grant. + private ClientDetails(String clientId, + String clientSecret, + String grantType) + { + this.ClientId = clientId; + this.ClientSecret = clientSecret; + this.GrantType = grantType; + } + + #endregion + + #region Properties + + /// + /// Gets the client identifier. + /// + /// + /// The client identifier. + /// + public String ClientId { get; } + + /// + /// Gets the client secret. + /// + /// + /// The client secret. + /// + public String ClientSecret { get; } + + /// + /// Gets the type of the grant. + /// + /// + /// The type of the grant. + /// + public String GrantType { get; } + + #endregion + + #region Methods + + /// + /// Creates the specified client identifier. + /// + /// The client identifier. + /// The client secret. + /// Type of the grant. + /// + public static ClientDetails Create(String clientId, + String clientSecret, + String grantType) + { + return new ClientDetails(clientId, clientSecret, grantType); + } + + #endregion + } +} \ No newline at end of file diff --git a/TransactionProcessor.IntegrationTests/Common/Contract.cs b/TransactionProcessor.IntegrationTests/Common/Contract.cs new file mode 100644 index 00000000..c5ebc667 --- /dev/null +++ b/TransactionProcessor.IntegrationTests/Common/Contract.cs @@ -0,0 +1,100 @@ +namespace TransactionProcessor.IntegrationTests.Common +{ + using System; + using System.Collections.Generic; + using System.Linq; + + /// + /// + /// + public class Contract + { + #region Properties + + /// + /// Gets or sets the contract identifier. + /// + /// + /// The contract identifier. + /// + public Guid ContractId { get; set; } + + /// + /// Gets or sets the description. + /// + /// + /// The description. + /// + public String Description { get; set; } + + /// + /// Gets or sets the operator identifier. + /// + /// + /// The operator identifier. + /// + public Guid OperatorId { get; set; } + + /// + /// Gets or sets the products. + /// + /// + /// The products. + /// + public List Products { get; set; } + + #endregion + + #region Methods + + /// + /// Adds the product. + /// + /// The product identifier. + /// The name. + /// The display text. + /// The value. + public void AddProduct(Guid productId, + String name, + String displayText, + Decimal? value = null) + { + Product product = new Product + { + ProductId = productId, + DisplayText = displayText, + Name = name, + Value = value + }; + + if (this.Products == null) + { + this.Products = new List(); + } + + this.Products.Add(product); + } + + /// + /// Gets the product. + /// + /// The product identifier. + /// + public Product GetProduct(Guid productId) + { + return this.Products.SingleOrDefault(p => p.ProductId == productId); + } + + /// + /// Gets the product. + /// + /// The name. + /// + public Product GetProduct(String name) + { + return this.Products.SingleOrDefault(p => p.Name == name); + } + + #endregion + } +} \ No newline at end of file diff --git a/TransactionProcessor.IntegrationTests/Common/EstateDetails.cs b/TransactionProcessor.IntegrationTests/Common/EstateDetails.cs new file mode 100644 index 00000000..c93f113d --- /dev/null +++ b/TransactionProcessor.IntegrationTests/Common/EstateDetails.cs @@ -0,0 +1,317 @@ +namespace TransactionProcessor.IntegrationTests.Common +{ + using System; + using System.Collections.Generic; + using System.Linq; + using DataTransferObjects; + + /// + /// + /// + public class EstateDetails + { + #region Fields + + /// + /// The contracts + /// + private List Contracts; + + /// + /// The merchants + /// + private readonly Dictionary Merchants; + + /// + /// The merchant users + /// + private readonly Dictionary> MerchantUsers; + + /// + /// The merchant users tokens + /// + private Dictionary> MerchantUsersTokens; + + /// + /// The operators + /// + private readonly Dictionary Operators; + + #endregion + + #region Constructors + + /// + /// Initializes a new instance of the class. + /// + /// The estate identifier. + /// Name of the estate. + private EstateDetails(Guid estateId, + String estateName) + { + this.EstateId = estateId; + this.EstateName = estateName; + this.Merchants = new Dictionary(); + this.Operators = new Dictionary(); + this.MerchantUsers = new Dictionary>(); + this.TransactionResponses = new Dictionary<(Guid merchantId, String transactionNumber), SerialisedMessage>(); + this.Contracts = new List(); + } + + #endregion + + #region Properties + + /// + /// Gets the access token. + /// + /// + /// The access token. + /// + public String AccessToken { get; private set; } + + /// + /// Gets the estate identifier. + /// + /// + /// The estate identifier. + /// + public Guid EstateId { get; } + + /// + /// Gets the name of the estate. + /// + /// + /// The name of the estate. + /// + public String EstateName { get; } + + /// + /// Gets the estate password. + /// + /// + /// The estate password. + /// + public String EstatePassword { get; private set; } + + /// + /// Gets the estate user. + /// + /// + /// The estate user. + /// + public String EstateUser { get; private set; } + + /// + /// Gets or sets the transaction responses. + /// + /// + /// The transaction responses. + /// + private Dictionary<(Guid merchantId, String transactionNumber), SerialisedMessage> TransactionResponses { get; } + + #endregion + + #region Methods + + /// + /// Adds the contract. + /// + /// The contract identifier. + /// Name of the contract. + /// The operator identifier. + public void AddContract(Guid contractId, + String contractName, + Guid operatorId) + { + this.Contracts.Add(new Contract + { + ContractId = contractId, + Description = contractName, + OperatorId = operatorId, + }); + } + + /// + /// Adds the merchant. + /// + /// The merchant identifier. + /// Name of the merchant. + public void AddMerchant(Guid merchantId, + String merchantName) + { + this.Merchants.Add(merchantName, merchantId); + } + + /// + /// Adds the merchant user. + /// + /// Name of the merchant. + /// Name of the user. + /// The password. + public void AddMerchantUser(String merchantName, + String userName, + String password) + { + if (this.MerchantUsers.ContainsKey(merchantName)) + { + Dictionary merchantUsersList = this.MerchantUsers[merchantName]; + if (merchantUsersList.ContainsKey(userName) == false) + { + merchantUsersList.Add(userName, password); + } + } + else + { + Dictionary merchantUsersList = new Dictionary(); + merchantUsersList.Add(userName, password); + this.MerchantUsers.Add(merchantName, merchantUsersList); + } + } + + /// + /// Adds the merchant user token. + /// + /// Name of the merchant. + /// Name of the user. + /// The token. + public void AddMerchantUserToken(String merchantName, + String userName, + String token) + { + if (this.MerchantUsersTokens.ContainsKey(merchantName)) + { + Dictionary merchantUsersList = this.MerchantUsersTokens[merchantName]; + if (merchantUsersList.ContainsKey(userName) == false) + { + merchantUsersList.Add(userName, token); + } + } + else + { + Dictionary merchantUsersList = new Dictionary(); + merchantUsersList.Add(userName, token); + this.MerchantUsersTokens.Add(merchantName, merchantUsersList); + } + } + + /// + /// Adds the operator. + /// + /// The operator identifier. + /// Name of the operator. + public void AddOperator(Guid operatorId, + String operatorName) + { + this.Operators.Add(operatorName, operatorId); + } + + /// + /// Adds the transaction response. + /// + /// The merchant identifier. + /// The transaction number. + /// The transaction response. + public void AddTransactionResponse(Guid merchantId, + String transactionNumber, + SerialisedMessage transactionResponse) + { + this.TransactionResponses.Add((merchantId, transactionNumber), transactionResponse); + } + + /// + /// Creates the specified estate identifier. + /// + /// The estate identifier. + /// Name of the estate. + /// + public static EstateDetails Create(Guid estateId, + String estateName) + { + return new EstateDetails(estateId, estateName); + } + + /// + /// Gets the contract. + /// + /// Name of the contract. + /// + public Contract GetContract(String contractName) + { + return this.Contracts.Single(c => c.Description == contractName); + } + + /// + /// Gets the contract. + /// + /// The contract identifier. + /// + public Contract GetContract(Guid contractId) + { + return this.Contracts.Single(c => c.ContractId == contractId); + } + + /// + /// Gets the merchant identifier. + /// + /// Name of the merchant. + /// + public Guid GetMerchantId(String merchantName) + { + if (merchantName == "InvalidMerchant") + { + return Guid.Parse("D59320FA-4C3E-4900-A999-483F6A10C69A"); + } + + return this.Merchants.Single(m => m.Key == merchantName).Value; + } + + /// + /// Gets the operator identifier. + /// + /// Name of the operator. + /// + public Guid GetOperatorId(String operatorName) + { + return this.Operators.Single(o => o.Key == operatorName).Value; + } + + /// + /// Gets the transaction response. + /// + /// The merchant identifier. + /// The transaction number. + /// + public SerialisedMessage GetTransactionResponse(Guid merchantId, + String transactionNumber) + { + KeyValuePair<(Guid merchantId, String transactionNumber), SerialisedMessage> transactionResponse = + this.TransactionResponses.Where(t => t.Key.merchantId == merchantId && t.Key.transactionNumber == transactionNumber).SingleOrDefault(); + + return transactionResponse.Value; + } + + /// + /// Sets the estate user. + /// + /// Name of the user. + /// The password. + public void SetEstateUser(String userName, + String password) + { + this.EstateUser = userName; + this.EstatePassword = password; + } + + /// + /// Sets the estate user token. + /// + /// The access token. + public void SetEstateUserToken(String accessToken) + { + this.AccessToken = accessToken; + } + + #endregion + } +} \ No newline at end of file diff --git a/TransactionProcessor.IntegrationTests/Common/Product.cs b/TransactionProcessor.IntegrationTests/Common/Product.cs new file mode 100644 index 00000000..f4e97c86 --- /dev/null +++ b/TransactionProcessor.IntegrationTests/Common/Product.cs @@ -0,0 +1,109 @@ +namespace TransactionProcessor.IntegrationTests.Common +{ + using System; + using System.Collections.Generic; + using System.Linq; + using EstateManagement.DataTransferObjects; + + /// + /// + /// + public class Product + { + #region Properties + + /// + /// Gets or sets the display text. + /// + /// + /// The display text. + /// + public String DisplayText { get; set; } + + /// + /// Gets or sets the name. + /// + /// + /// The name. + /// + public String Name { get; set; } + + /// + /// Gets or sets the product identifier. + /// + /// + /// The product identifier. + /// + public Guid ProductId { get; set; } + + /// + /// Gets or sets the transaction fees. + /// + /// + /// The transaction fees. + /// + public List TransactionFees { get; set; } + + /// + /// Gets or sets the value. + /// + /// + /// The value. + /// + public Decimal? Value { get; set; } + + #endregion + + #region Methods + + /// + /// Adds the transaction fee. + /// + /// The transaction fee identifier. + /// Type of the calculation. + /// The description. + /// The value. + public void AddTransactionFee(Guid transactionFeeId, + CalculationType calculationType, + String description, + Decimal value) + { + TransactionFee transactionFee = new TransactionFee + { + TransactionFeeId = transactionFeeId, + CalculationType = calculationType, + Description = description, + Value = value + }; + + if (this.TransactionFees == null) + { + this.TransactionFees = new List(); + } + + this.TransactionFees.Add(transactionFee); + } + + /// + /// Gets the transaction fee. + /// + /// The transaction fee identifier. + /// + public TransactionFee GetTransactionFee(Guid transactionFeeId) + { + return this.TransactionFees.SingleOrDefault(t => t.TransactionFeeId == transactionFeeId); + } + + /// + /// Gets the transaction fee. + /// + /// The description. + /// + public TransactionFee GetTransactionFee(String description) + { + return this.TransactionFees.SingleOrDefault(t => t.Description == description); + } + + #endregion + } +} \ No newline at end of file diff --git a/TransactionProcessor.IntegrationTests/Common/SpecflowTableHelper.cs b/TransactionProcessor.IntegrationTests/Common/SpecflowTableHelper.cs index 296e8207..c618d6f5 100644 --- a/TransactionProcessor.IntegrationTests/Common/SpecflowTableHelper.cs +++ b/TransactionProcessor.IntegrationTests/Common/SpecflowTableHelper.cs @@ -3,81 +3,127 @@ using System; using TechTalk.SpecFlow; + /// + /// + /// public static class SpecflowTableHelper { #region Methods - public static Decimal GetDecimalValue(TableRow row, + /// + /// Gets the boolean value. + /// + /// The row. + /// The key. + /// + public static Boolean GetBooleanValue(TableRow row, String key) { String field = SpecflowTableHelper.GetStringRowValue(row, key); - return Decimal.TryParse(field, out Decimal value) ? value : -1; + return bool.TryParse(field, out Boolean value) && value; } - public static Boolean GetBooleanValue(TableRow row, + /// + /// Gets the date for date string. + /// + /// The date string. + /// The today. + /// + public static DateTime GetDateForDateString(String dateString, + DateTime today) + { + switch(dateString.ToUpper()) + { + case "TODAY": + return today.Date; + case "YESTERDAY": + return today.AddDays(-1).Date; + case "LASTWEEK": + return today.AddDays(-7).Date; + case "LASTMONTH": + return today.AddMonths(-1).Date; + case "LASTYEAR": + return today.AddYears(-1).Date; + case "TOMORROW": + return today.AddDays(1).Date; + default: + return DateTime.Parse(dateString); + } + } + + /// + /// Gets the decimal value. + /// + /// The row. + /// The key. + /// + public static Decimal GetDecimalValue(TableRow row, String key) { String field = SpecflowTableHelper.GetStringRowValue(row, key); - return Boolean.TryParse(field, out Boolean value) && value; + return decimal.TryParse(field, out Decimal value) ? value : -1; + } + + /// + /// Gets the enum value. + /// + /// + /// The row. + /// The key. + /// + public static T GetEnumValue(TableRow row, + String key) where T : struct + { + String field = SpecflowTableHelper.GetStringRowValue(row, key); + + return Enum.Parse(field, true); } + /// + /// Gets the int value. + /// + /// The row. + /// The key. + /// public static Int32 GetIntValue(TableRow row, String key) { String field = SpecflowTableHelper.GetStringRowValue(row, key); - return Int32.TryParse(field, out Int32 value) ? value : -1; + return int.TryParse(field, out Int32 value) ? value : -1; } + /// + /// Gets the short value. + /// + /// The row. + /// The key. + /// public static Int16 GetShortValue(TableRow row, String key) { String field = SpecflowTableHelper.GetStringRowValue(row, key); - if (Int16.TryParse(field, out Int16 value)) + if (short.TryParse(field, out Int16 value)) { return value; } - else - { - return -1; - } - } - public static String GetStringRowValue(TableRow row, - String key) - { - return row.TryGetValue(key, out String value) ? value : ""; + return -1; } /// - /// Gets the date for date string. + /// Gets the string row value. /// - /// The date string. - /// The today. + /// The row. + /// The key. /// - public static DateTime GetDateForDateString(String dateString, - DateTime today) + public static String GetStringRowValue(TableRow row, + String key) { - switch (dateString.ToUpper()) - { - case "TODAY": - return today.Date; - case "YESTERDAY": - return today.AddDays(-1).Date; - case "LASTWEEK": - return today.AddDays(-7).Date; - case "LASTMONTH": - return today.AddMonths(-1).Date; - case "LASTYEAR": - return today.AddYears(-1).Date; - case "TOMORROW": - return today.AddDays(1).Date; - default: - return DateTime.Parse(dateString); - } + return row.TryGetValue(key, out String value) ? value : ""; } #endregion diff --git a/TransactionProcessor.IntegrationTests/Common/TestingContext.cs b/TransactionProcessor.IntegrationTests/Common/TestingContext.cs index 29fb06b7..473da9b8 100644 --- a/TransactionProcessor.IntegrationTests/Common/TestingContext.cs +++ b/TransactionProcessor.IntegrationTests/Common/TestingContext.cs @@ -1,111 +1,112 @@ -using System; -using System.Collections.Generic; -using System.Text; - -namespace TransactionProcessor.IntegrationTests.Common +namespace TransactionProcessor.IntegrationTests.Common { + using System; + using System.Collections.Generic; using System.Linq; - using DataTransferObjects; using global::Shared.Logger; using Shouldly; using TechTalk.SpecFlow; - //public class TestingContext - //{ - // public TestingContext() - // { - // this.Estates = new Dictionary(); - // this.Merchants = new Dictionary(); - // this.Operators = new Dictionary(); - // this.EstateMerchants = new Dictionary>(); - // this.TransactionResponses=new Dictionary(); - // } - - // public DockerHelper DockerHelper { get; set; } - - // public Dictionary Estates { get; set; } - // public Dictionary Merchants { get; set; } - - // public Dictionary Operators { get; set; } + /// + /// + /// + public class TestingContext + { + #region Fields - // public Dictionary> EstateMerchants { get; set; } + /// + /// The clients + /// + private readonly List Clients; - // public Dictionary TransactionResponses { get; set; } + /// + /// The estates + /// + private readonly List Estates; + #endregion - //} + #region Constructors - public class TestingContext - { + /// + /// Initializes a new instance of the class. + /// public TestingContext() { this.Estates = new List(); this.Clients = new List(); } - - public NlogLogger Logger { get; set; } - - public DockerHelper DockerHelper { get; set; } - private List Clients; + #endregion - private List Estates; + #region Properties + /// + /// Gets or sets the access token. + /// + /// + /// The access token. + /// public String AccessToken { get; set; } - public EstateDetails GetEstateDetails(TableRow tableRow) - { - String estateName = SpecflowTableHelper.GetStringRowValue(tableRow, "EstateName"); - EstateDetails estateDetails = null; - - estateDetails = this.Estates.SingleOrDefault(e => e.EstateName == estateName); - - if (estateDetails == null && estateName == "InvalidEstate") - { - estateDetails = EstateDetails.Create(Guid.Parse("79902550-64DF-4491-B0C1-4E78943928A3"), estateName); - estateDetails.AddMerchant(Guid.Parse("36AA0109-E2E3-4049-9575-F507A887BB1F"), "Test Merchant 1"); - this.Estates.Add(estateDetails); - } - - estateDetails.ShouldNotBeNull(); - - return estateDetails; - } + /// + /// Gets or sets the docker helper. + /// + /// + /// The docker helper. + /// + public DockerHelper DockerHelper { get; set; } - public List GetAllEstateIds() - { - return this.Estates.Select(e => e.EstateId).ToList(); - } - public EstateDetails GetEstateDetails(String estateName) - { - EstateDetails estateDetails = this.Estates.SingleOrDefault(e => e.EstateName == estateName); + /// + /// Gets or sets the logger. + /// + /// + /// The logger. + /// + public NlogLogger Logger { get; set; } - estateDetails.ShouldNotBeNull(); + #endregion - return estateDetails; - } + #region Methods - public EstateDetails GetEstateDetails(Guid estateId) + /// + /// Adds the client details. + /// + /// The client identifier. + /// The client secret. + /// Type of the grant. + public void AddClientDetails(String clientId, + String clientSecret, + String grantType) { - EstateDetails estateDetails = this.Estates.SingleOrDefault(e => e.EstateId== estateId); - - estateDetails.ShouldNotBeNull(); - - return estateDetails; + this.Clients.Add(ClientDetails.Create(clientId, clientSecret, grantType)); } - public void AddEstateDetails(Guid estateId, String estateName) + /// + /// Adds the estate details. + /// + /// The estate identifier. + /// Name of the estate. + public void AddEstateDetails(Guid estateId, + String estateName) { this.Estates.Add(EstateDetails.Create(estateId, estateName)); } - public void AddClientDetails(String clientId, - String clientSecret, - String grantType) + /// + /// Gets all estate ids. + /// + /// + public List GetAllEstateIds() { - this.Clients.Add(ClientDetails.Create(clientId, clientSecret, grantType)); + return this.Estates.Select(e => e.EstateId).ToList(); } + /// + /// Gets the client details. + /// + /// The client identifier. + /// public ClientDetails GetClientDetails(String clientId) { ClientDetails clientDetails = this.Clients.SingleOrDefault(c => c.ClientId == clientId); @@ -114,159 +115,59 @@ public ClientDetails GetClientDetails(String clientId) return clientDetails; } - } - - public class EstateDetails - { - private EstateDetails(Guid estateId, String estateName) - { - this.EstateId = estateId; - this.EstateName = estateName; - this.Merchants = new Dictionary(); - this.Operators = new Dictionary(); - this.MerchantUsers = new Dictionary>(); - this.TransactionResponses = new Dictionary<(Guid merchantId, String transactionNumber), SerialisedMessage>(); - } - - public void AddTransactionResponse(Guid merchantId, - String transactionNumber, - SerialisedMessage transactionResponse) - { - this.TransactionResponses.Add((merchantId, transactionNumber), transactionResponse); - } - - public SerialisedMessage GetTransactionResponse(Guid merchantId, - String transactionNumber) - { - KeyValuePair<(Guid merchantId, String transactionNumber), SerialisedMessage> transactionResponse = - this.TransactionResponses.Where(t => t.Key.merchantId == merchantId && t.Key.transactionNumber == transactionNumber).SingleOrDefault(); - - return transactionResponse.Value; - } - private Dictionary<(Guid merchantId, String transactionNumber), SerialisedMessage> TransactionResponses { get; set; } - - public String EstateUser { get; private set; } - public String EstatePassword { get; private set; } - - public String AccessToken { get; private set; } - - public static EstateDetails Create(Guid estateId, - String estateName) - { - return new EstateDetails(estateId, estateName); - } - - public void AddOperator(Guid operatorId, - String operatorName) + /// + /// Gets the estate details. + /// + /// The table row. + /// + public EstateDetails GetEstateDetails(TableRow tableRow) { - this.Operators.Add(operatorName, operatorId); - } + String estateName = SpecflowTableHelper.GetStringRowValue(tableRow, "EstateName"); + EstateDetails estateDetails = null; - public void AddMerchant(Guid merchantId, - String merchantName) - { - this.Merchants.Add(merchantName, merchantId); - } + estateDetails = this.Estates.SingleOrDefault(e => e.EstateName == estateName); - public Guid GetMerchantId(String merchantName) - { - if (merchantName == "InvalidMerchant") + if (estateDetails == null && estateName == "InvalidEstate") { - return Guid.Parse("D59320FA-4C3E-4900-A999-483F6A10C69A"); + estateDetails = EstateDetails.Create(Guid.Parse("79902550-64DF-4491-B0C1-4E78943928A3"), estateName); + estateDetails.AddMerchant(Guid.Parse("36AA0109-E2E3-4049-9575-F507A887BB1F"), "Test Merchant 1"); + this.Estates.Add(estateDetails); } - return this.Merchants.Single(m => m.Key == merchantName).Value; - } + estateDetails.ShouldNotBeNull(); - public Guid GetOperatorId(String operatorName) - { - return this.Operators.Single(o => o.Key == operatorName).Value; + return estateDetails; } - public void SetEstateUser(String userName, - String password) + /// + /// Gets the estate details. + /// + /// Name of the estate. + /// + public EstateDetails GetEstateDetails(String estateName) { - this.EstateUser = userName; - this.EstatePassword = password; - } + EstateDetails estateDetails = this.Estates.SingleOrDefault(e => e.EstateName == estateName); - public void AddMerchantUser(String merchantName, - String userName, - String password) - { - if (this.MerchantUsers.ContainsKey(merchantName)) - { - Dictionary merchantUsersList = this.MerchantUsers[merchantName]; - if (merchantUsersList.ContainsKey(userName) == false) - { - merchantUsersList.Add(userName, password); - } - } - else - { - Dictionary merchantUsersList = new Dictionary(); - merchantUsersList.Add(userName, password); - this.MerchantUsers.Add(merchantName, merchantUsersList); - } - } + estateDetails.ShouldNotBeNull(); - public void AddMerchantUserToken(String merchantName, - String userName, - String token) - { - if (this.MerchantUsersTokens.ContainsKey(merchantName)) - { - Dictionary merchantUsersList = this.MerchantUsersTokens[merchantName]; - if (merchantUsersList.ContainsKey(userName) == false) - { - merchantUsersList.Add(userName, token); - } - } - else - { - Dictionary merchantUsersList = new Dictionary(); - merchantUsersList.Add(userName, token); - this.MerchantUsersTokens.Add(merchantName, merchantUsersList); - } + return estateDetails; } - public void SetEstateUserToken(String accessToken) + /// + /// Gets the estate details. + /// + /// The estate identifier. + /// + public EstateDetails GetEstateDetails(Guid estateId) { - this.AccessToken = accessToken; - } - - public Guid EstateId { get; private set; } - public String EstateName { get; private set; } - - private Dictionary Operators; - - private Dictionary Merchants; - - private Dictionary> MerchantUsers; - private Dictionary> MerchantUsersTokens; - } + EstateDetails estateDetails = this.Estates.SingleOrDefault(e => e.EstateId == estateId); - public class ClientDetails - { - public String ClientId { get; private set; } - public String ClientSecret { get; private set; } - public String GrantType { get; private set; } + estateDetails.ShouldNotBeNull(); - private ClientDetails(String clientId, - String clientSecret, - String grantType) - { - this.ClientId = clientId; - this.ClientSecret = clientSecret; - this.GrantType = grantType; + return estateDetails; } - public static ClientDetails Create(String clientId, - String clientSecret, - String grantType) - { - return new ClientDetails(clientId, clientSecret, grantType); - } + #endregion } -} +} \ No newline at end of file diff --git a/TransactionProcessor.IntegrationTests/Common/TransactionFee.cs b/TransactionProcessor.IntegrationTests/Common/TransactionFee.cs new file mode 100644 index 00000000..e141c924 --- /dev/null +++ b/TransactionProcessor.IntegrationTests/Common/TransactionFee.cs @@ -0,0 +1,47 @@ +namespace TransactionProcessor.IntegrationTests.Common +{ + using System; + using EstateManagement.DataTransferObjects; + + /// + /// + /// + public class TransactionFee + { + #region Properties + + /// + /// Gets or sets the type of the calculation. + /// + /// + /// The type of the calculation. + /// + public CalculationType CalculationType { get; set; } + + /// + /// Gets or sets the description. + /// + /// + /// The description. + /// + public String Description { get; set; } + + /// + /// Gets or sets the transaction fee identifier. + /// + /// + /// The transaction fee identifier. + /// + public Guid TransactionFeeId { get; set; } + + /// + /// Gets or sets the value. + /// + /// + /// The value. + /// + public Decimal Value { get; set; } + + #endregion + } +} \ No newline at end of file diff --git a/TransactionProcessor.IntegrationTests/SaleTransaction/SaleTransactionFeature.feature b/TransactionProcessor.IntegrationTests/SaleTransaction/SaleTransactionFeature.feature index 50c9e058..c21493fe 100644 --- a/TransactionProcessor.IntegrationTests/SaleTransaction/SaleTransactionFeature.feature +++ b/TransactionProcessor.IntegrationTests/SaleTransaction/SaleTransactionFeature.feature @@ -26,6 +26,21 @@ Background: | Test Estate 1 | Safaricom | True | True | | Test Estate 2 | Safaricom | True | True | + Given I create a contract with the following values + | EstateName | OperatorName | ContractDescription | + | Test Estate 1 | Safaricom | Safaricom Contract | + | Test Estate 2 | Safaricom | Safaricom Contract | + + When I create the following Products + | EstateName | OperatorName | ContractDescription | ProductName | DisplayText | Value | + | Test Estate 1 | Safaricom | Safaricom Contract | Variable Topup | Custom | | + | Test Estate 2 | Safaricom | Safaricom Contract | Variable Topup | Custom | | + + When I add the following Transaction Fees + | EstateName | OperatorName | ContractDescription | ProductName | CalculationType | FeeDescription | Value | + | Test Estate 1 | Safaricom | Safaricom Contract | Variable Topup | Fixed | Merchant Commission | 2.50 | + | Test Estate 2 | Safaricom | Safaricom Contract | Variable Topup | Percentage | Merchant Commission | 0.85 | + Given I create the following merchants | MerchantName | AddressLine1 | Town | Region | Country | ContactName | EmailAddress | EstateName | | Test Merchant 1 | Address Line 1 | TestTown | Test Region | United Kingdom | Test Contact 1 | testcontact1@merchant1.co.uk | Test Estate 1 | @@ -54,11 +69,11 @@ Background: Scenario: Sale Transactions When I perform the following transactions - | DateTime | TransactionNumber | TransactionType | MerchantName | DeviceIdentifier | EstateName | OperatorName | TransactionAmount | CustomerAccountNumber | CustomerEmailAddress | - | Today | 1 | Sale | Test Merchant 1 | 123456780 | Test Estate 1 | Safaricom | 1000.00 | 123456789 | | - | Today | 2 | Sale | Test Merchant 2 | 123456781 | Test Estate 1 | Safaricom | 1000.00 | 123456789 | | - | Today | 3 | Sale | Test Merchant 3 | 123456782 | Test Estate 2 | Safaricom | 1000.00 | 123456789 | | - | Today | 4 | Sale | Test Merchant 1 | 123456780 | Test Estate 1 | Safaricom | 1000.00 | 123456789 | testcustomer@customer.co.uk | + | DateTime | TransactionNumber | TransactionType | MerchantName | DeviceIdentifier | EstateName | OperatorName | TransactionAmount | CustomerAccountNumber | CustomerEmailAddress | ContractDescription | ProductName | + | Today | 1 | Sale | Test Merchant 1 | 123456780 | Test Estate 1 | Safaricom | 1000.00 | 123456789 | | Safaricom Contract | Variable Topup | + | Today | 2 | Sale | Test Merchant 2 | 123456781 | Test Estate 1 | Safaricom | 1000.00 | 123456789 | | Safaricom Contract | Variable Topup | + | Today | 3 | Sale | Test Merchant 3 | 123456782 | Test Estate 2 | Safaricom | 1000.00 | 123456789 | | Safaricom Contract | Variable Topup | + | Today | 4 | Sale | Test Merchant 1 | 123456780 | Test Estate 1 | Safaricom | 1000.00 | 123456789 | testcustomer@customer.co.uk | Safaricom Contract | Variable Topup | Then transaction response should contain the following information | EstateName | MerchantName | TransactionNumber | ResponseCode | ResponseMessage | @@ -71,8 +86,8 @@ Scenario: Sale Transactions Scenario: Sale Transaction with Invalid Device When I perform the following transactions - | DateTime | TransactionNumber | TransactionType | MerchantName | DeviceIdentifier | EstateName | OperatorName | TransactionAmount | CustomerAccountNumber | CustomerEmailAddress | - | Today | 1 | Sale | Test Merchant 1 | 123456781 | Test Estate 1 | Safaricom | 1000.00 | 123456789 | testcustomer@customer.co.uk | + | DateTime | TransactionNumber | TransactionType | MerchantName | DeviceIdentifier | EstateName | OperatorName | TransactionAmount | CustomerAccountNumber | CustomerEmailAddress | ContractDescription | ProductName | + | Today | 1 | Sale | Test Merchant 1 | 123456781 | Test Estate 1 | Safaricom | 1000.00 | 123456789 | testcustomer@customer.co.uk | Safaricom Contract | Variable Topup | Then transaction response should contain the following information | EstateName | MerchantName | TransactionNumber | ResponseCode | ResponseMessage | @@ -81,8 +96,8 @@ Scenario: Sale Transaction with Invalid Device Scenario: Sale Transaction with Invalid Estate When I perform the following transactions - | DateTime | TransactionNumber | TransactionType | MerchantName | DeviceIdentifier | EstateName | OperatorName | TransactionAmount | CustomerAccountNumber | CustomerEmailAddress | - | Today | 1 | Sale | Test Merchant 1 | 123456780 | InvalidEstate | Safaricom | 1000.00 | 123456789 | testcustomer@customer.co.uk | + | DateTime | TransactionNumber | TransactionType | MerchantName | DeviceIdentifier | EstateName | OperatorName | TransactionAmount | CustomerAccountNumber | CustomerEmailAddress | ContractDescription | ProductName | + | Today | 1 | Sale | Test Merchant 1 | 123456780 | InvalidEstate | Safaricom | 1000.00 | 123456789 | testcustomer@customer.co.uk | Safaricom Contract | Variable Topup | Then transaction response should contain the following information | EstateName | MerchantName | TransactionNumber | ResponseCode | ResponseMessage | @@ -91,8 +106,8 @@ Scenario: Sale Transaction with Invalid Estate Scenario: Sale Transaction with Invalid Merchant When I perform the following transactions - | DateTime | TransactionNumber | TransactionType | MerchantName | DeviceIdentifier | EstateName | OperatorName | TransactionAmount | CustomerAccountNumber | CustomerEmailAddress | - | Today | 1 | Sale | InvalidMerchant | 123456780 | Test Estate 1 | Safaricom | 1000.00 | 123456789 | testcustomer@customer.co.uk | + | DateTime | TransactionNumber | TransactionType | MerchantName | DeviceIdentifier | EstateName | OperatorName | TransactionAmount | CustomerAccountNumber | CustomerEmailAddress | ContractDescription | ProductName | + | Today | 1 | Sale | InvalidMerchant | 123456780 | Test Estate 1 | Safaricom | 1000.00 | 123456789 | testcustomer@customer.co.uk | Safaricom Contract | Variable Topup | Then transaction response should contain the following information | EstateName | MerchantName | TransactionNumber | ResponseCode | ResponseMessage | @@ -102,8 +117,8 @@ Scenario: Sale Transaction with Invalid Merchant Scenario: Sale Transaction with Not Enough Credit Available When I perform the following transactions - | DateTime | TransactionNumber | TransactionType | MerchantName | DeviceIdentifier | EstateName | OperatorName | TransactionAmount | CustomerAccountNumber | CustomerEmailAddress | - | Today | 1 | Sale | Test Merchant 1 | 123456780 | Test Estate 1 | Safaricom | 3000.00 | 123456789 | testcustomer@customer.co.uk | + | DateTime | TransactionNumber | TransactionType | MerchantName | DeviceIdentifier | EstateName | OperatorName | TransactionAmount | CustomerAccountNumber | CustomerEmailAddress | ContractDescription | ProductName | + | Today | 1 | Sale | Test Merchant 1 | 123456780 | Test Estate 1 | Safaricom | 3000.00 | 123456789 | testcustomer@customer.co.uk | Safaricom Contract | Variable Topup | Then transaction response should contain the following information diff --git a/TransactionProcessor.IntegrationTests/SaleTransaction/SaleTransactionFeature.feature.cs b/TransactionProcessor.IntegrationTests/SaleTransaction/SaleTransactionFeature.feature.cs index 1ca10045..7bee7287 100644 --- a/TransactionProcessor.IntegrationTests/SaleTransaction/SaleTransactionFeature.feature.cs +++ b/TransactionProcessor.IntegrationTests/SaleTransaction/SaleTransactionFeature.feature.cs @@ -157,6 +157,72 @@ public virtual void FeatureBackground() testRunner.Given("I have created the following operators", ((string)(null)), table26, "Given "); #line hidden TechTalk.SpecFlow.Table table27 = new TechTalk.SpecFlow.Table(new string[] { + "EstateName", + "OperatorName", + "ContractDescription"}); + table27.AddRow(new string[] { + "Test Estate 1", + "Safaricom", + "Safaricom Contract"}); + table27.AddRow(new string[] { + "Test Estate 2", + "Safaricom", + "Safaricom Contract"}); +#line 29 + testRunner.Given("I create a contract with the following values", ((string)(null)), table27, "Given "); +#line hidden + TechTalk.SpecFlow.Table table28 = new TechTalk.SpecFlow.Table(new string[] { + "EstateName", + "OperatorName", + "ContractDescription", + "ProductName", + "DisplayText", + "Value"}); + table28.AddRow(new string[] { + "Test Estate 1", + "Safaricom", + "Safaricom Contract", + "Variable Topup", + "Custom", + ""}); + table28.AddRow(new string[] { + "Test Estate 2", + "Safaricom", + "Safaricom Contract", + "Variable Topup", + "Custom", + ""}); +#line 34 + testRunner.When("I create the following Products", ((string)(null)), table28, "When "); +#line hidden + TechTalk.SpecFlow.Table table29 = new TechTalk.SpecFlow.Table(new string[] { + "EstateName", + "OperatorName", + "ContractDescription", + "ProductName", + "CalculationType", + "FeeDescription", + "Value"}); + table29.AddRow(new string[] { + "Test Estate 1", + "Safaricom", + "Safaricom Contract", + "Variable Topup", + "Fixed", + "Merchant Commission", + "2.50"}); + table29.AddRow(new string[] { + "Test Estate 2", + "Safaricom", + "Safaricom Contract", + "Variable Topup", + "Percentage", + "Merchant Commission", + "0.85"}); +#line 39 + testRunner.When("I add the following Transaction Fees", ((string)(null)), table29, "When "); +#line hidden + TechTalk.SpecFlow.Table table30 = new TechTalk.SpecFlow.Table(new string[] { "MerchantName", "AddressLine1", "Town", @@ -165,7 +231,7 @@ public virtual void FeatureBackground() "ContactName", "EmailAddress", "EstateName"}); - table27.AddRow(new string[] { + table30.AddRow(new string[] { "Test Merchant 1", "Address Line 1", "TestTown", @@ -174,7 +240,7 @@ public virtual void FeatureBackground() "Test Contact 1", "testcontact1@merchant1.co.uk", "Test Estate 1"}); - table27.AddRow(new string[] { + table30.AddRow(new string[] { "Test Merchant 2", "Address Line 1", "TestTown", @@ -183,7 +249,7 @@ public virtual void FeatureBackground() "Test Contact 2", "testcontact2@merchant2.co.uk", "Test Estate 1"}); - table27.AddRow(new string[] { + table30.AddRow(new string[] { "Test Merchant 3", "Address Line 1", "TestTown", @@ -192,81 +258,81 @@ public virtual void FeatureBackground() "Test Contact 3", "testcontact3@merchant2.co.uk", "Test Estate 2"}); -#line 29 - testRunner.Given("I create the following merchants", ((string)(null)), table27, "Given "); +#line 44 + testRunner.Given("I create the following merchants", ((string)(null)), table30, "Given "); #line hidden - TechTalk.SpecFlow.Table table28 = new TechTalk.SpecFlow.Table(new string[] { + TechTalk.SpecFlow.Table table31 = new TechTalk.SpecFlow.Table(new string[] { "OperatorName", "MerchantName", "MerchantNumber", "TerminalNumber", "EstateName"}); - table28.AddRow(new string[] { + table31.AddRow(new string[] { "Safaricom", "Test Merchant 1", "00000001", "10000001", "Test Estate 1"}); - table28.AddRow(new string[] { + table31.AddRow(new string[] { "Safaricom", "Test Merchant 2", "00000002", "10000002", "Test Estate 1"}); - table28.AddRow(new string[] { + table31.AddRow(new string[] { "Safaricom", "Test Merchant 3", "00000003", "10000003", "Test Estate 2"}); -#line 35 - testRunner.Given("I have assigned the following operator to the merchants", ((string)(null)), table28, "Given "); +#line 50 + testRunner.Given("I have assigned the following operator to the merchants", ((string)(null)), table31, "Given "); #line hidden - TechTalk.SpecFlow.Table table29 = new TechTalk.SpecFlow.Table(new string[] { + TechTalk.SpecFlow.Table table32 = new TechTalk.SpecFlow.Table(new string[] { "DeviceIdentifier", "MerchantName", "EstateName"}); - table29.AddRow(new string[] { + table32.AddRow(new string[] { "123456780", "Test Merchant 1", "Test Estate 1"}); - table29.AddRow(new string[] { + table32.AddRow(new string[] { "123456781", "Test Merchant 2", "Test Estate 1"}); - table29.AddRow(new string[] { + table32.AddRow(new string[] { "123456782", "Test Merchant 3", "Test Estate 2"}); -#line 41 - testRunner.Given("I have assigned the following devices to the merchants", ((string)(null)), table29, "Given "); +#line 56 + testRunner.Given("I have assigned the following devices to the merchants", ((string)(null)), table32, "Given "); #line hidden - TechTalk.SpecFlow.Table table30 = new TechTalk.SpecFlow.Table(new string[] { + TechTalk.SpecFlow.Table table33 = new TechTalk.SpecFlow.Table(new string[] { "Reference", "Amount", "DateTime", "MerchantName", "EstateName"}); - table30.AddRow(new string[] { + table33.AddRow(new string[] { "Deposit1", "2000.00", "Today", "Test Merchant 1", "Test Estate 1"}); - table30.AddRow(new string[] { + table33.AddRow(new string[] { "Deposit1", "1000.00", "Today", "Test Merchant 2", "Test Estate 1"}); - table30.AddRow(new string[] { + table33.AddRow(new string[] { "Deposit1", "1000.00", "Today", "Test Merchant 3", "Test Estate 2"}); -#line 47 - testRunner.Given("I make the following manual merchant deposits", ((string)(null)), table30, "Given "); +#line 62 + testRunner.Given("I make the following manual merchant deposits", ((string)(null)), table33, "Given "); #line hidden } @@ -285,7 +351,7 @@ public virtual void SaleTransactions() "PRTest"}; System.Collections.Specialized.OrderedDictionary argumentsOfScenario = new System.Collections.Specialized.OrderedDictionary(); TechTalk.SpecFlow.ScenarioInfo scenarioInfo = new TechTalk.SpecFlow.ScenarioInfo("Sale Transactions", null, tagsOfScenario, argumentsOfScenario); -#line 54 +#line 69 this.ScenarioInitialize(scenarioInfo); #line hidden bool isScenarioIgnored = default(bool); @@ -308,7 +374,7 @@ public virtual void SaleTransactions() #line 4 this.FeatureBackground(); #line hidden - TechTalk.SpecFlow.Table table31 = new TechTalk.SpecFlow.Table(new string[] { + TechTalk.SpecFlow.Table table34 = new TechTalk.SpecFlow.Table(new string[] { "DateTime", "TransactionNumber", "TransactionType", @@ -318,8 +384,10 @@ public virtual void SaleTransactions() "OperatorName", "TransactionAmount", "CustomerAccountNumber", - "CustomerEmailAddress"}); - table31.AddRow(new string[] { + "CustomerEmailAddress", + "ContractDescription", + "ProductName"}); + table34.AddRow(new string[] { "Today", "1", "Sale", @@ -329,8 +397,10 @@ public virtual void SaleTransactions() "Safaricom", "1000.00", "123456789", - ""}); - table31.AddRow(new string[] { + "", + "Safaricom Contract", + "Variable Topup"}); + table34.AddRow(new string[] { "Today", "2", "Sale", @@ -340,8 +410,10 @@ public virtual void SaleTransactions() "Safaricom", "1000.00", "123456789", - ""}); - table31.AddRow(new string[] { + "", + "Safaricom Contract", + "Variable Topup"}); + table34.AddRow(new string[] { "Today", "3", "Sale", @@ -351,8 +423,10 @@ public virtual void SaleTransactions() "Safaricom", "1000.00", "123456789", - ""}); - table31.AddRow(new string[] { + "", + "Safaricom Contract", + "Variable Topup"}); + table34.AddRow(new string[] { "Today", "4", "Sale", @@ -362,42 +436,44 @@ public virtual void SaleTransactions() "Safaricom", "1000.00", "123456789", - "testcustomer@customer.co.uk"}); -#line 56 - testRunner.When("I perform the following transactions", ((string)(null)), table31, "When "); + "testcustomer@customer.co.uk", + "Safaricom Contract", + "Variable Topup"}); +#line 71 + testRunner.When("I perform the following transactions", ((string)(null)), table34, "When "); #line hidden - TechTalk.SpecFlow.Table table32 = new TechTalk.SpecFlow.Table(new string[] { + TechTalk.SpecFlow.Table table35 = new TechTalk.SpecFlow.Table(new string[] { "EstateName", "MerchantName", "TransactionNumber", "ResponseCode", "ResponseMessage"}); - table32.AddRow(new string[] { + table35.AddRow(new string[] { "Test Estate 1", "Test Merchant 1", "1", "0000", "SUCCESS"}); - table32.AddRow(new string[] { + table35.AddRow(new string[] { "Test Estate 1", "Test Merchant 2", "2", "0000", "SUCCESS"}); - table32.AddRow(new string[] { + table35.AddRow(new string[] { "Test Estate 2", "Test Merchant 3", "3", "0000", "SUCCESS"}); - table32.AddRow(new string[] { + table35.AddRow(new string[] { "Test Estate 1", "Test Merchant 1", "4", "0000", "SUCCESS"}); -#line 63 - testRunner.Then("transaction response should contain the following information", ((string)(null)), table32, "Then "); +#line 78 + testRunner.Then("transaction response should contain the following information", ((string)(null)), table35, "Then "); #line hidden } this.ScenarioCleanup(); @@ -413,7 +489,7 @@ public virtual void SaleTransactionWithInvalidDevice() "PRTest"}; System.Collections.Specialized.OrderedDictionary argumentsOfScenario = new System.Collections.Specialized.OrderedDictionary(); TechTalk.SpecFlow.ScenarioInfo scenarioInfo = new TechTalk.SpecFlow.ScenarioInfo("Sale Transaction with Invalid Device", null, tagsOfScenario, argumentsOfScenario); -#line 71 +#line 86 this.ScenarioInitialize(scenarioInfo); #line hidden bool isScenarioIgnored = default(bool); @@ -436,7 +512,7 @@ public virtual void SaleTransactionWithInvalidDevice() #line 4 this.FeatureBackground(); #line hidden - TechTalk.SpecFlow.Table table33 = new TechTalk.SpecFlow.Table(new string[] { + TechTalk.SpecFlow.Table table36 = new TechTalk.SpecFlow.Table(new string[] { "DateTime", "TransactionNumber", "TransactionType", @@ -446,8 +522,10 @@ public virtual void SaleTransactionWithInvalidDevice() "OperatorName", "TransactionAmount", "CustomerAccountNumber", - "CustomerEmailAddress"}); - table33.AddRow(new string[] { + "CustomerEmailAddress", + "ContractDescription", + "ProductName"}); + table36.AddRow(new string[] { "Today", "1", "Sale", @@ -457,24 +535,26 @@ public virtual void SaleTransactionWithInvalidDevice() "Safaricom", "1000.00", "123456789", - "testcustomer@customer.co.uk"}); -#line 73 - testRunner.When("I perform the following transactions", ((string)(null)), table33, "When "); + "testcustomer@customer.co.uk", + "Safaricom Contract", + "Variable Topup"}); +#line 88 + testRunner.When("I perform the following transactions", ((string)(null)), table36, "When "); #line hidden - TechTalk.SpecFlow.Table table34 = new TechTalk.SpecFlow.Table(new string[] { + TechTalk.SpecFlow.Table table37 = new TechTalk.SpecFlow.Table(new string[] { "EstateName", "MerchantName", "TransactionNumber", "ResponseCode", "ResponseMessage"}); - table34.AddRow(new string[] { + table37.AddRow(new string[] { "Test Estate 1", "Test Merchant 1", "1", "1000", "Device Identifier 123456781 not valid for Merchant Test Merchant 1"}); -#line 77 - testRunner.Then("transaction response should contain the following information", ((string)(null)), table34, "Then "); +#line 92 + testRunner.Then("transaction response should contain the following information", ((string)(null)), table37, "Then "); #line hidden } this.ScenarioCleanup(); @@ -488,7 +568,7 @@ public virtual void SaleTransactionWithInvalidEstate() string[] tagsOfScenario = ((string[])(null)); System.Collections.Specialized.OrderedDictionary argumentsOfScenario = new System.Collections.Specialized.OrderedDictionary(); TechTalk.SpecFlow.ScenarioInfo scenarioInfo = new TechTalk.SpecFlow.ScenarioInfo("Sale Transaction with Invalid Estate", null, tagsOfScenario, argumentsOfScenario); -#line 81 +#line 96 this.ScenarioInitialize(scenarioInfo); #line hidden bool isScenarioIgnored = default(bool); @@ -511,7 +591,7 @@ public virtual void SaleTransactionWithInvalidEstate() #line 4 this.FeatureBackground(); #line hidden - TechTalk.SpecFlow.Table table35 = new TechTalk.SpecFlow.Table(new string[] { + TechTalk.SpecFlow.Table table38 = new TechTalk.SpecFlow.Table(new string[] { "DateTime", "TransactionNumber", "TransactionType", @@ -521,8 +601,10 @@ public virtual void SaleTransactionWithInvalidEstate() "OperatorName", "TransactionAmount", "CustomerAccountNumber", - "CustomerEmailAddress"}); - table35.AddRow(new string[] { + "CustomerEmailAddress", + "ContractDescription", + "ProductName"}); + table38.AddRow(new string[] { "Today", "1", "Sale", @@ -532,24 +614,26 @@ public virtual void SaleTransactionWithInvalidEstate() "Safaricom", "1000.00", "123456789", - "testcustomer@customer.co.uk"}); -#line 83 - testRunner.When("I perform the following transactions", ((string)(null)), table35, "When "); + "testcustomer@customer.co.uk", + "Safaricom Contract", + "Variable Topup"}); +#line 98 + testRunner.When("I perform the following transactions", ((string)(null)), table38, "When "); #line hidden - TechTalk.SpecFlow.Table table36 = new TechTalk.SpecFlow.Table(new string[] { + TechTalk.SpecFlow.Table table39 = new TechTalk.SpecFlow.Table(new string[] { "EstateName", "MerchantName", "TransactionNumber", "ResponseCode", "ResponseMessage"}); - table36.AddRow(new string[] { + table39.AddRow(new string[] { "InvalidEstate", "Test Merchant 1", "1", "1001", "Estate Id [79902550-64df-4491-b0c1-4e78943928a3] is not a valid estate"}); -#line 87 - testRunner.Then("transaction response should contain the following information", ((string)(null)), table36, "Then "); +#line 102 + testRunner.Then("transaction response should contain the following information", ((string)(null)), table39, "Then "); #line hidden } this.ScenarioCleanup(); @@ -563,7 +647,7 @@ public virtual void SaleTransactionWithInvalidMerchant() string[] tagsOfScenario = ((string[])(null)); System.Collections.Specialized.OrderedDictionary argumentsOfScenario = new System.Collections.Specialized.OrderedDictionary(); TechTalk.SpecFlow.ScenarioInfo scenarioInfo = new TechTalk.SpecFlow.ScenarioInfo("Sale Transaction with Invalid Merchant", null, tagsOfScenario, argumentsOfScenario); -#line 91 +#line 106 this.ScenarioInitialize(scenarioInfo); #line hidden bool isScenarioIgnored = default(bool); @@ -586,7 +670,7 @@ public virtual void SaleTransactionWithInvalidMerchant() #line 4 this.FeatureBackground(); #line hidden - TechTalk.SpecFlow.Table table37 = new TechTalk.SpecFlow.Table(new string[] { + TechTalk.SpecFlow.Table table40 = new TechTalk.SpecFlow.Table(new string[] { "DateTime", "TransactionNumber", "TransactionType", @@ -596,8 +680,10 @@ public virtual void SaleTransactionWithInvalidMerchant() "OperatorName", "TransactionAmount", "CustomerAccountNumber", - "CustomerEmailAddress"}); - table37.AddRow(new string[] { + "CustomerEmailAddress", + "ContractDescription", + "ProductName"}); + table40.AddRow(new string[] { "Today", "1", "Sale", @@ -607,25 +693,27 @@ public virtual void SaleTransactionWithInvalidMerchant() "Safaricom", "1000.00", "123456789", - "testcustomer@customer.co.uk"}); -#line 93 - testRunner.When("I perform the following transactions", ((string)(null)), table37, "When "); + "testcustomer@customer.co.uk", + "Safaricom Contract", + "Variable Topup"}); +#line 108 + testRunner.When("I perform the following transactions", ((string)(null)), table40, "When "); #line hidden - TechTalk.SpecFlow.Table table38 = new TechTalk.SpecFlow.Table(new string[] { + TechTalk.SpecFlow.Table table41 = new TechTalk.SpecFlow.Table(new string[] { "EstateName", "MerchantName", "TransactionNumber", "ResponseCode", "ResponseMessage"}); - table38.AddRow(new string[] { + table41.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 97 - testRunner.Then("transaction response should contain the following information", ((string)(null)), table38, "Then "); +#line 112 + testRunner.Then("transaction response should contain the following information", ((string)(null)), table41, "Then "); #line hidden } this.ScenarioCleanup(); @@ -641,7 +729,7 @@ public virtual void SaleTransactionWithNotEnoughCreditAvailable() "PRTest"}; System.Collections.Specialized.OrderedDictionary argumentsOfScenario = new System.Collections.Specialized.OrderedDictionary(); TechTalk.SpecFlow.ScenarioInfo scenarioInfo = new TechTalk.SpecFlow.ScenarioInfo("Sale Transaction with Not Enough Credit Available", null, tagsOfScenario, argumentsOfScenario); -#line 102 +#line 117 this.ScenarioInitialize(scenarioInfo); #line hidden bool isScenarioIgnored = default(bool); @@ -664,7 +752,7 @@ public virtual void SaleTransactionWithNotEnoughCreditAvailable() #line 4 this.FeatureBackground(); #line hidden - TechTalk.SpecFlow.Table table39 = new TechTalk.SpecFlow.Table(new string[] { + TechTalk.SpecFlow.Table table42 = new TechTalk.SpecFlow.Table(new string[] { "DateTime", "TransactionNumber", "TransactionType", @@ -674,8 +762,10 @@ public virtual void SaleTransactionWithNotEnoughCreditAvailable() "OperatorName", "TransactionAmount", "CustomerAccountNumber", - "CustomerEmailAddress"}); - table39.AddRow(new string[] { + "CustomerEmailAddress", + "ContractDescription", + "ProductName"}); + table42.AddRow(new string[] { "Today", "1", "Sale", @@ -685,25 +775,27 @@ public virtual void SaleTransactionWithNotEnoughCreditAvailable() "Safaricom", "3000.00", "123456789", - "testcustomer@customer.co.uk"}); -#line 104 - testRunner.When("I perform the following transactions", ((string)(null)), table39, "When "); + "testcustomer@customer.co.uk", + "Safaricom Contract", + "Variable Topup"}); +#line 119 + testRunner.When("I perform the following transactions", ((string)(null)), table42, "When "); #line hidden - TechTalk.SpecFlow.Table table40 = new TechTalk.SpecFlow.Table(new string[] { + TechTalk.SpecFlow.Table table43 = new TechTalk.SpecFlow.Table(new string[] { "EstateName", "MerchantName", "TransactionNumber", "ResponseCode", "ResponseMessage"}); - table40.AddRow(new string[] { + table43.AddRow(new string[] { "Test Estate 1", "Test Merchant 1", "1", "1009", "Merchant [Test Merchant 1] does not have enough credit available [2000.0] to perf" + "orm transaction amount [3000.00]"}); -#line 109 - testRunner.Then("transaction response should contain the following information", ((string)(null)), table40, "Then "); +#line 124 + testRunner.Then("transaction response should contain the following information", ((string)(null)), table43, "Then "); #line hidden } this.ScenarioCleanup(); diff --git a/TransactionProcessor.IntegrationTests/Shared/SharedSteps.cs b/TransactionProcessor.IntegrationTests/Shared/SharedSteps.cs index 6f729b50..8878b52e 100644 --- a/TransactionProcessor.IntegrationTests/Shared/SharedSteps.cs +++ b/TransactionProcessor.IntegrationTests/Shared/SharedSteps.cs @@ -11,6 +11,7 @@ namespace TransactionProcessor.IntegrationTests.Shared using System.Threading.Tasks; using Common; using DataTransferObjects; + using EstateManagement.DataTransferObjects; using EstateManagement.DataTransferObjects.Requests; using EstateManagement.DataTransferObjects.Responses; using Microsoft.EntityFrameworkCore.ValueGeneration.Internal; @@ -236,7 +237,7 @@ public async Task WhenIPerformTheFollowingTransactions(Table table) String deviceIdentifier = SpecflowTableHelper.GetStringRowValue(tableRow, "DeviceIdentifier"); EstateDetails estateDetails = this.TestingContext.GetEstateDetails(tableRow); - + // Lookup the merchant id Guid merchantId = estateDetails.GetMerchantId(merchantName); SerialisedMessage transactionResponse = null; @@ -258,6 +259,11 @@ public async Task WhenIPerformTheFollowingTransactions(Table table) Decimal transactionAmount = SpecflowTableHelper.GetDecimalValue(tableRow, "TransactionAmount"); String customerAccountNumber = SpecflowTableHelper.GetStringRowValue(tableRow, "CustomerAccountNumber"); String customerEmailAddress = SpecflowTableHelper.GetStringRowValue(tableRow, "CustomerEmailAddress"); + String contractDescription = SpecflowTableHelper.GetStringRowValue(tableRow, "ContractDescription"); + String productName = SpecflowTableHelper.GetStringRowValue(tableRow, "ProductName"); + + var contract = estateDetails.GetContract(contractDescription); + var product = contract.GetProduct(productName); transactionResponse = await this.PerformSaleTransaction(estateDetails.EstateId, merchantId, @@ -269,6 +275,8 @@ public async Task WhenIPerformTheFollowingTransactions(Table table) transactionAmount, customerAccountNumber, customerEmailAddress, + contract.ContractId, + product.ProductId, CancellationToken.None); break; @@ -278,6 +286,122 @@ public async Task WhenIPerformTheFollowingTransactions(Table table) } } + [Given(@"I create a contract with the following values")] + public async Task GivenICreateAContractWithTheFollowingValues(Table table) + { + foreach (TableRow tableRow in table.Rows) + { + EstateDetails estateDetails = this.TestingContext.GetEstateDetails(tableRow); + + String token = this.TestingContext.AccessToken; + if (String.IsNullOrEmpty(estateDetails.AccessToken) == false) + { + token = estateDetails.AccessToken; + } + + String operatorName = SpecflowTableHelper.GetStringRowValue(tableRow, "OperatorName"); + Guid operatorId = estateDetails.GetOperatorId(operatorName); + + CreateContractRequest createContractRequest = new CreateContractRequest + { + OperatorId = operatorId, + Description = SpecflowTableHelper.GetStringRowValue(tableRow, "ContractDescription") + }; + + CreateContractResponse contractResponse = + await this.TestingContext.DockerHelper.EstateClient.CreateContract(token, estateDetails.EstateId, createContractRequest, CancellationToken.None); + + estateDetails.AddContract(contractResponse.ContractId, createContractRequest.Description, operatorId); + } + } + + [When(@"I create the following Products")] + public async Task WhenICreateTheFollowingProducts(Table table) + { + foreach (TableRow tableRow in table.Rows) + { + EstateDetails estateDetails = this.TestingContext.GetEstateDetails(tableRow); + + String token = this.TestingContext.AccessToken; + if (String.IsNullOrEmpty(estateDetails.AccessToken) == false) + { + token = estateDetails.AccessToken; + } + + String contractName = SpecflowTableHelper.GetStringRowValue(tableRow, "ContractDescription"); + Contract contract = estateDetails.GetContract(contractName); + String productValue = SpecflowTableHelper.GetStringRowValue(tableRow, "Value"); + + AddProductToContractRequest addProductToContractRequest = new AddProductToContractRequest + { + ProductName = SpecflowTableHelper.GetStringRowValue(tableRow, "ProductName"), + DisplayText = SpecflowTableHelper.GetStringRowValue(tableRow, "DisplayText"), + Value = null + }; + if (String.IsNullOrEmpty(productValue) == false) + { + addProductToContractRequest.Value = Decimal.Parse(productValue); + } + + AddProductToContractResponse addProductToContractResponse = await this.TestingContext.DockerHelper.EstateClient.AddProductToContract(token, + estateDetails.EstateId, + contract.ContractId, + addProductToContractRequest, + CancellationToken.None); + + contract.AddProduct(addProductToContractResponse.ProductId, addProductToContractRequest.ProductName, addProductToContractRequest.DisplayText, + addProductToContractRequest.Value); + } + } + + [When(@"I add the following Transaction Fees")] + public async Task WhenIAddTheFollowingTransactionFees(Table table) + { + foreach (TableRow tableRow in table.Rows) + { + EstateDetails estateDetails = this.TestingContext.GetEstateDetails(tableRow); + + String token = this.TestingContext.AccessToken; + if (String.IsNullOrEmpty(estateDetails.AccessToken) == false) + { + token = estateDetails.AccessToken; + } + + String contractName = SpecflowTableHelper.GetStringRowValue(tableRow, "ContractDescription"); + String productName = SpecflowTableHelper.GetStringRowValue(tableRow, "ProductName"); + Contract contract = estateDetails.GetContract(contractName); + + Product product = contract.GetProduct(productName); + + AddTransactionFeeForProductToContractRequest addTransactionFeeForProductToContractRequest = new AddTransactionFeeForProductToContractRequest + { + Value = + SpecflowTableHelper + .GetDecimalValue(tableRow, "Value"), + Description = + SpecflowTableHelper.GetStringRowValue(tableRow, + "FeeDescription"), + CalculationType = + SpecflowTableHelper + .GetEnumValue(tableRow, + "CalculationType") + }; + + AddTransactionFeeForProductToContractResponse addTransactionFeeForProductToContractResponse = + await this.TestingContext.DockerHelper.EstateClient.AddTransactionFeeForProductToContract(token, + estateDetails.EstateId, + contract.ContractId, + product.ProductId, + addTransactionFeeForProductToContractRequest, + CancellationToken.None); + + product.AddTransactionFee(addTransactionFeeForProductToContractResponse.TransactionFeeId, + addTransactionFeeForProductToContractRequest.CalculationType, + addTransactionFeeForProductToContractRequest.Description, + addTransactionFeeForProductToContractRequest.Value); + } + } + /// /// Performs the logon transaction. /// @@ -317,7 +441,10 @@ await this.TestingContext.DockerHelper.TransactionProcessorClient.PerformTransac return responseSerialisedMessage; } - private async Task PerformSaleTransaction(Guid estateId, Guid merchantId, DateTime transactionDateTime, String transactionType, String transactionNumber, String deviceIdentifier, String operatorIdentifier, Decimal transactionAmount, String customerAccountNumber, String customerEmailAddres, CancellationToken cancellationToken) + private async Task PerformSaleTransaction(Guid estateId, Guid merchantId, DateTime transactionDateTime, String transactionType, String transactionNumber, String deviceIdentifier, String operatorIdentifier, Decimal transactionAmount, String customerAccountNumber, String customerEmailAddress, + Guid contractId, + Guid productId, + CancellationToken cancellationToken) { SaleTransactionRequest saleTransactionRequest = new SaleTransactionRequest { @@ -333,7 +460,9 @@ private async Task PerformSaleTransaction(Guid estateId, Guid {"Amount", transactionAmount.ToString()}, {"CustomerAccountNumber", customerAccountNumber} }, - CustomerEmailAddress = customerEmailAddres + CustomerEmailAddress = customerEmailAddress, + ProductId = productId, + ContractId = contractId }; SerialisedMessage serialisedMessage = new SerialisedMessage(); diff --git a/TransactionProcessor.IntegrationTests/TransactionProcessor.IntegrationTests.csproj b/TransactionProcessor.IntegrationTests/TransactionProcessor.IntegrationTests.csproj index 49cb5c3c..165b8e83 100644 --- a/TransactionProcessor.IntegrationTests/TransactionProcessor.IntegrationTests.csproj +++ b/TransactionProcessor.IntegrationTests/TransactionProcessor.IntegrationTests.csproj @@ -9,7 +9,7 @@ - + diff --git a/TransactionProcessor.Testing/TestData.cs b/TransactionProcessor.Testing/TestData.cs index 4e2fe0c4..737d4a75 100644 --- a/TransactionProcessor.Testing/TestData.cs +++ b/TransactionProcessor.Testing/TestData.cs @@ -386,7 +386,9 @@ public class TestData TestData.TransactionNumber, TestData.OperatorIdentifier1, TestData.CustomerEmailAddress, - TestData.AdditionalTransactionMetaData); + TestData.AdditionalTransactionMetaData, + TestData.ContractId, + TestData.ProductId); public static ProcessSaleTransactionResponse ProcessSaleTransactionResponseModel => new ProcessSaleTransactionResponse diff --git a/TransactionProcessor.Transaction.DomainEvents/ProductDetailsAddedToTransactionEvent.cs b/TransactionProcessor.Transaction.DomainEvents/ProductDetailsAddedToTransactionEvent.cs index 3c6614bc..ee415fc8 100644 --- a/TransactionProcessor.Transaction.DomainEvents/ProductDetailsAddedToTransactionEvent.cs +++ b/TransactionProcessor.Transaction.DomainEvents/ProductDetailsAddedToTransactionEvent.cs @@ -1,6 +1,7 @@ namespace TransactionProcessor.Transaction.DomainEvents { using System; + using System.Diagnostics.CodeAnalysis; using Newtonsoft.Json; using Shared.DomainDrivenDesign.EventSourcing; @@ -13,6 +14,15 @@ public class ProductDetailsAddedToTransactionEvent : DomainEvent { #region Constructors + /// + /// Initializes a new instance of the class. + /// + [ExcludeFromCodeCoverage] + public ProductDetailsAddedToTransactionEvent() + { + + } + /// /// Initializes a new instance of the class. /// diff --git a/TransactionProcessor/Controllers/TransactionController.cs b/TransactionProcessor/Controllers/TransactionController.cs index f6316b52..98ff8cc5 100644 --- a/TransactionProcessor/Controllers/TransactionController.cs +++ b/TransactionProcessor/Controllers/TransactionController.cs @@ -136,7 +136,9 @@ private async Task ProcessSpecificMessage(SaleTransactionRequ saleTransactionRequest.TransactionNumber, saleTransactionRequest.OperatorIdentifier, saleTransactionRequest.CustomerEmailAddress, - saleTransactionRequest.AdditionalTransactionMetadata); + saleTransactionRequest.AdditionalTransactionMetadata, + saleTransactionRequest.ContractId, + saleTransactionRequest.ProductId); ProcessSaleTransactionResponse response = await this.Mediator.Send(request, cancellationToken);