diff --git a/TransactionProcessor.BusinessLogic.Tests/Requests/RequestTests.cs b/TransactionProcessor.BusinessLogic.Tests/Requests/RequestTests.cs index 62715730..7dff2cb9 100644 --- a/TransactionProcessor.BusinessLogic.Tests/Requests/RequestTests.cs +++ b/TransactionProcessor.BusinessLogic.Tests/Requests/RequestTests.cs @@ -36,7 +36,8 @@ public void ProcessSaleTransactionRequest_CanBeCreated_IsCreated() TestData.CustomerEmailAddress, TestData.AdditionalTransactionMetaData(), TestData.ContractId, - TestData.ProductId); + TestData.ProductId, + TestData.TransactionSource); processSaleTransactionRequest.ShouldNotBeNull(); processSaleTransactionRequest.EstateId.ShouldBe(TestData.EstateId); @@ -52,6 +53,7 @@ public void ProcessSaleTransactionRequest_CanBeCreated_IsCreated() processSaleTransactionRequest.AdditionalTransactionMetadata.Count.ShouldBe(TestData.AdditionalTransactionMetaData().Count); processSaleTransactionRequest.ContractId.ShouldBe(TestData.ContractId); processSaleTransactionRequest.ProductId.ShouldBe(TestData.ProductId); + processSaleTransactionRequest.TransactionSource.ShouldBe(TestData.TransactionSource); } [Fact] diff --git a/TransactionProcessor.BusinessLogic.Tests/Services/TransactionAggregateManagerTests.cs b/TransactionProcessor.BusinessLogic.Tests/Services/TransactionAggregateManagerTests.cs index b5315106..74229cd6 100644 --- a/TransactionProcessor.BusinessLogic.Tests/Services/TransactionAggregateManagerTests.cs +++ b/TransactionProcessor.BusinessLogic.Tests/Services/TransactionAggregateManagerTests.cs @@ -237,6 +237,19 @@ await transactionAggregateManager.AddProductDetails(TestData.EstateId, CancellationToken.None); } + [Fact] + public async Task TransactionAggregateManager_AddTransactionSource_TransactionSourceAddedToTransaction() + { + Mock> aggregateRepository = new Mock>(); + aggregateRepository.Setup(a => a.GetLatestVersion(It.IsAny(), It.IsAny())).ReturnsAsync(TestData.GetCompletedAuthorisedSaleTransactionAggregate); + TransactionAggregateManager transactionAggregateManager = new TransactionAggregateManager(aggregateRepository.Object); + + await transactionAggregateManager.AddTransactionSource(TestData.EstateId, + TestData.TransactionId, + (TransactionSource)TestData.TransactionSource, + CancellationToken.None); + } + [Fact] public async Task TransactionAggregateManager_AddFee_FeeAddedToTransaction() { diff --git a/TransactionProcessor.BusinessLogic.Tests/Services/TransactionDomainServiceTests.cs b/TransactionProcessor.BusinessLogic.Tests/Services/TransactionDomainServiceTests.cs index e2677ad9..3e6f3457 100644 --- a/TransactionProcessor.BusinessLogic.Tests/Services/TransactionDomainServiceTests.cs +++ b/TransactionProcessor.BusinessLogic.Tests/Services/TransactionDomainServiceTests.cs @@ -527,6 +527,7 @@ public async Task TransactionDomainService_ProcessSaleTransaction_SuccesfulOpera TestData.AdditionalTransactionMetaData(), TestData.ContractId, TestData.ProductId, + TestData.TransactionSource, CancellationToken.None); this.ValidateResponse(response, TransactionResponseCode.Success); @@ -573,6 +574,7 @@ public async Task TransactionDomainService_ProcessSaleTransaction_InvalidTransac TestData.AdditionalTransactionMetaData(amount:"0.00"), TestData.ContractId, TestData.ProductId, + TestData.TransactionSource, CancellationToken.None); this.ValidateResponse(response, TransactionResponseCode.InvalidSaleTransactionAmount); @@ -638,6 +640,7 @@ public async Task TransactionDomainService_ProcessSaleTransaction_MetaDataCaseTe TestData.AdditionalTransactionMetaData(amountName:amountFieldName), TestData.ContractId, TestData.ProductId, + TestData.TransactionSource, CancellationToken.None); this.ValidateResponse(response, TransactionResponseCode.Success); @@ -703,6 +706,7 @@ public async Task TransactionDomainService_ProcessSaleTransaction_MetaDataCaseTe TestData.AdditionalTransactionMetaData(customerAccountNumberName: customerAccountNumberFieldName), TestData.ContractId, TestData.ProductId, + TestData.TransactionSource, CancellationToken.None); this.ValidateResponse(response, TransactionResponseCode.Success); @@ -761,6 +765,7 @@ public async Task TransactionDomainService_ProcessSaleTransaction_FailedOperator TestData.AdditionalTransactionMetaData(), TestData.ContractId, TestData.ProductId, + TestData.TransactionSource, CancellationToken.None); this.ValidateResponse(response, TransactionResponseCode.TransactionDeclinedByOperator); @@ -805,6 +810,7 @@ public async Task TransactionDomainService_ProcessSaleTransaction_MerchantWithNu TestData.AdditionalTransactionMetaData(), TestData.ContractId, TestData.ProductId, + TestData.TransactionSource, CancellationToken.None); this.ValidateResponse(response, TransactionResponseCode.NoValidDevices); @@ -850,6 +856,7 @@ public async Task TransactionDomainService_ProcessSaleTransaction_MerchantWithNo TestData.AdditionalTransactionMetaData(), TestData.ContractId, TestData.ProductId, + TestData.TransactionSource, CancellationToken.None); this.ValidateResponse(response, TransactionResponseCode.NoValidDevices); @@ -894,6 +901,7 @@ public async Task TransactionDomainService_ProcessSaleTransaction_IncorrectDevic TestData.AdditionalTransactionMetaData(), TestData.ContractId, TestData.ProductId, + TestData.TransactionSource, CancellationToken.None); this.ValidateResponse(response, TransactionResponseCode.InvalidDeviceIdentifier); @@ -938,6 +946,7 @@ public async Task TransactionDomainService_ProcessSaleTransaction_InvalidEstate_ TestData.AdditionalTransactionMetaData(), TestData.ContractId, TestData.ProductId, + TestData.TransactionSource, CancellationToken.None); this.ValidateResponse(response, TransactionResponseCode.InvalidEstateId); @@ -983,6 +992,7 @@ public async Task TransactionDomainService_ProcessSaleTransaction_NotEnoughCredi TestData.AdditionalTransactionMetaData(), TestData.ContractId, TestData.ProductId, + TestData.TransactionSource, CancellationToken.None); this.ValidateResponse(response, TransactionResponseCode.MerchantDoesNotHaveEnoughCredit); @@ -1026,6 +1036,7 @@ public async Task TransactionDomainService_ProcessSaleTransaction_InvalidMerchan TestData.AdditionalTransactionMetaData(), TestData.ContractId, TestData.ProductId, + TestData.TransactionSource, CancellationToken.None); this.ValidateResponse(response, TransactionResponseCode.InvalidMerchantId); @@ -1069,6 +1080,7 @@ public async Task TransactionDomainService_ProcessSaleTransaction_EstateWithEmpt TestData.AdditionalTransactionMetaData(), TestData.ContractId, TestData.ProductId, + TestData.TransactionSource, CancellationToken.None); this.ValidateResponse(response, TransactionResponseCode.NoEstateOperators); @@ -1113,6 +1125,7 @@ public async Task TransactionDomainService_ProcessSaleTransaction_EstateWithNull TestData.AdditionalTransactionMetaData(), TestData.ContractId, TestData.ProductId, + TestData.TransactionSource, CancellationToken.None); this.ValidateResponse(response, TransactionResponseCode.NoEstateOperators); @@ -1157,6 +1170,7 @@ public async Task TransactionDomainService_ProcessSaleTransaction_OperatorNotSup TestData.AdditionalTransactionMetaData(), TestData.ContractId, TestData.ProductId, + TestData.TransactionSource, CancellationToken.None); this.ValidateResponse(response, TransactionResponseCode.OperatorNotValidForEstate); @@ -1202,6 +1216,7 @@ public async Task TransactionDomainService_ProcessSaleTransaction_MerchantWithEm TestData.AdditionalTransactionMetaData(), TestData.ContractId, TestData.ProductId, + TestData.TransactionSource, CancellationToken.None); this.ValidateResponse(response, TransactionResponseCode.NoMerchantOperators); @@ -1246,6 +1261,7 @@ public async Task TransactionDomainService_ProcessSaleTransaction_MerchantWithNu TestData.AdditionalTransactionMetaData(), TestData.ContractId, TestData.ProductId, + TestData.TransactionSource, CancellationToken.None); this.ValidateResponse(response, TransactionResponseCode.NoMerchantOperators); @@ -1290,6 +1306,7 @@ public async Task TransactionDomainService_ProcessSaleTransaction_OperatorNotSup TestData.AdditionalTransactionMetaData(), TestData.ContractId, TestData.ProductId, + TestData.TransactionSource, CancellationToken.None); this.ValidateResponse(response, TransactionResponseCode.OperatorNotValidForMerchant); @@ -1343,6 +1360,7 @@ public async Task TransactionDomainService_ProcessSaleTransaction_ErrorInOperato TestData.AdditionalTransactionMetaData(), TestData.ContractId, TestData.ProductId, + TestData.TransactionSource, CancellationToken.None); this.ValidateResponse(response, TransactionResponseCode.OperatorCommsError); diff --git a/TransactionProcessor.BusinessLogic/RequestHandlers/TransactionRequestHandler.cs b/TransactionProcessor.BusinessLogic/RequestHandlers/TransactionRequestHandler.cs index b8e8c39d..113a2f6d 100644 --- a/TransactionProcessor.BusinessLogic/RequestHandlers/TransactionRequestHandler.cs +++ b/TransactionProcessor.BusinessLogic/RequestHandlers/TransactionRequestHandler.cs @@ -88,6 +88,7 @@ public async Task Handle(ProcessSaleTransactionR request.AdditionalTransactionMetadata, request.ContractId, request.ProductId, + request.TransactionSource, cancellationToken); return saleResponse; diff --git a/TransactionProcessor.BusinessLogic/Requests/ProcessSaleTransactionRequest.cs b/TransactionProcessor.BusinessLogic/Requests/ProcessSaleTransactionRequest.cs index ecfb45b0..1074f452 100644 --- a/TransactionProcessor.BusinessLogic/Requests/ProcessSaleTransactionRequest.cs +++ b/TransactionProcessor.BusinessLogic/Requests/ProcessSaleTransactionRequest.cs @@ -8,22 +8,7 @@ public class ProcessSaleTransactionRequest : IRequest { #region Constructors - - /// - /// Initializes a new instance of the class. - /// - /// The transaction identifier. - /// The estate identifier. - /// The merchant identifier. - /// The device identifier. - /// Type of the transaction. - /// The transaction date time. - /// The transaction number. - /// The operator identifier. - /// The customer email address. - /// The additional transaction metadata. - /// The contract identifier. - /// The product identifier. + private ProcessSaleTransactionRequest(Guid transactionId, Guid estateId, Guid merchantId, @@ -35,7 +20,8 @@ private ProcessSaleTransactionRequest(Guid transactionId, String customerEmailAddress, Dictionary additionalTransactionMetadata, Guid contractId, - Guid productId) + Guid productId, + Int32 transactionSource) { this.TransactionId = transactionId; this.EstateId = estateId; @@ -48,6 +34,7 @@ private ProcessSaleTransactionRequest(Guid transactionId, this.AdditionalTransactionMetadata = additionalTransactionMetadata; this.ContractId = contractId; this.ProductId = productId; + this.TransactionSource = transactionSource; this.TransactionType = transactionType; } @@ -151,26 +138,12 @@ private ProcessSaleTransactionRequest(Guid transactionId, /// public Guid ProductId { get; } + public Int32 TransactionSource { get; } + #endregion #region Methods - /// - /// Creates the specified estate identifier. - /// - /// The transaction identifier. - /// The estate identifier. - /// The merchant identifier. - /// The device identifier. - /// Type of the transaction. - /// The transaction date time. - /// The transaction number. - /// 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, Guid merchantId, @@ -182,7 +155,8 @@ public static ProcessSaleTransactionRequest Create(Guid transactionId, String customerEmailAddress, Dictionary additionalTransactionMetadata, Guid contractId, - Guid productId) + Guid productId, + Int32 transactionSource) { return new ProcessSaleTransactionRequest(transactionId, estateId, @@ -195,7 +169,8 @@ public static ProcessSaleTransactionRequest Create(Guid transactionId, customerEmailAddress, additionalTransactionMetadata, contractId, - productId); + productId, + transactionSource); } #endregion diff --git a/TransactionProcessor.BusinessLogic/Services/ITransactionAggregateManager.cs b/TransactionProcessor.BusinessLogic/Services/ITransactionAggregateManager.cs index 8054d6a8..acbaa97c 100644 --- a/TransactionProcessor.BusinessLogic/Services/ITransactionAggregateManager.cs +++ b/TransactionProcessor.BusinessLogic/Services/ITransactionAggregateManager.cs @@ -31,6 +31,11 @@ Task AddProductDetails(Guid estateId, Guid productId, CancellationToken cancellationToken); + Task AddTransactionSource(Guid estateId, + Guid transactionId, + TransactionSource transactionSource, + CancellationToken cancellationToken); + /// /// Adds the fee. /// diff --git a/TransactionProcessor.BusinessLogic/Services/ITransactionDomainService.cs b/TransactionProcessor.BusinessLogic/Services/ITransactionDomainService.cs index e55afd88..6799310d 100644 --- a/TransactionProcessor.BusinessLogic/Services/ITransactionDomainService.cs +++ b/TransactionProcessor.BusinessLogic/Services/ITransactionDomainService.cs @@ -28,23 +28,7 @@ Task ProcessLogonTransaction(Guid transactionId String transactionNumber, String deviceIdentifier, CancellationToken cancellationToken); - - /// - /// Processes the sale transaction. - /// - /// The transaction identifier. - /// The estate identifier. - /// The merchant identifier. - /// The transaction date time. - /// The transaction number. - /// The device identifier. - /// The operator identifier. - /// The customer email address. - /// The additional transaction metadata. - /// The contract identifier. - /// The product identifier. - /// The cancellation token. - /// + Task ProcessSaleTransaction(Guid transactionId, Guid estateId, Guid merchantId, @@ -56,6 +40,7 @@ Task ProcessSaleTransaction(Guid transactionId, Dictionary additionalTransactionMetadata, Guid contractId, Guid productId, + Int32 transactionSource, CancellationToken cancellationToken); /// diff --git a/TransactionProcessor.BusinessLogic/Services/TransactionAggregateManager.cs b/TransactionProcessor.BusinessLogic/Services/TransactionAggregateManager.cs index e612af9b..f25bb955 100644 --- a/TransactionProcessor.BusinessLogic/Services/TransactionAggregateManager.cs +++ b/TransactionProcessor.BusinessLogic/Services/TransactionAggregateManager.cs @@ -5,13 +5,10 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; - using EventHandling; - using Microsoft.EntityFrameworkCore.Internal; using Models; using OperatorInterfaces; using Shared.DomainDrivenDesign.EventSourcing; using Shared.EventStore.Aggregate; - using Shared.EventStore.EventStore; using TransactionAggregate; /// @@ -22,21 +19,13 @@ public class TransactionAggregateManager : ITransactionAggregateManager { #region Fields - /// - /// The transaction aggregate repository - /// - private readonly IAggregateRepository TransactionAggregateRepository; + private readonly IAggregateRepository TransactionAggregateRepository; #endregion #region Constructors - /// - /// Initializes a new instance of the class. - /// - /// The transaction aggregate repository. - public TransactionAggregateManager(IAggregateRepository transactionAggregateRepository) - { + public TransactionAggregateManager(IAggregateRepository transactionAggregateRepository) { this.TransactionAggregateRepository = transactionAggregateRepository; } @@ -44,45 +33,27 @@ public TransactionAggregateManager(IAggregateRepository - /// 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) - { + public async Task AddFee(Guid estateId, + Guid transactionId, + CalculatedFee calculatedFee, + CancellationToken cancellationToken) { TransactionAggregate transactionAggregate = await this.TransactionAggregateRepository.GetLatestVersion(transactionId, cancellationToken); - transactionAggregate.AddProductDetails(contractId, productId); + transactionAggregate.AddFee(calculatedFee); await this.TransactionAggregateRepository.SaveChanges(transactionAggregate, cancellationToken); } - /// - /// Adds the fee. - /// - /// The estate identifier. - /// The transaction identifier. - /// The calculated fee. - /// The cancellation token. - public async Task AddFee(Guid estateId, - Guid transactionId, - CalculatedFee calculatedFee, - CancellationToken cancellationToken) - { + public async Task AddProductDetails(Guid estateId, + Guid transactionId, + Guid contractId, + Guid productId, + CancellationToken cancellationToken) { TransactionAggregate transactionAggregate = await this.TransactionAggregateRepository.GetLatestVersion(transactionId, cancellationToken); - - transactionAggregate.AddFee(calculatedFee); - await this.TransactionAggregateRepository.SaveChanges(transactionAggregate, cancellationToken); + transactionAggregate.AddProductDetails(contractId, productId); + await this.TransactionAggregateRepository.SaveChanges(transactionAggregate, cancellationToken); } public async Task AddSettledFee(Guid estateId, @@ -90,8 +61,7 @@ public async Task AddSettledFee(Guid estateId, CalculatedFee calculatedFee, DateTime settlementDueDate, DateTime settledDateTime, - CancellationToken cancellationToken) - { + CancellationToken cancellationToken) { TransactionAggregate transactionAggregate = await this.TransactionAggregateRepository.GetLatestVersion(transactionId, cancellationToken); transactionAggregate.AddSettledFee(calculatedFee, settlementDueDate, settledDateTime); @@ -99,25 +69,25 @@ public async Task AddSettledFee(Guid estateId, await this.TransactionAggregateRepository.SaveChanges(transactionAggregate, cancellationToken); } - /// - /// Authorises the transaction. - /// - /// The estate identifier. - /// The transaction identifier. - /// The operator identifier. - /// The operator response. - /// The transaction response code. - /// The response message. - /// The cancellation token. - /// + public async Task AddTransactionSource(Guid estateId, + Guid transactionId, + TransactionSource transactionSource, + CancellationToken cancellationToken) { + TransactionAggregate transactionAggregate = await this.TransactionAggregateRepository.GetLatestVersion(transactionId, cancellationToken); + + transactionAggregate.AddTransactionSource(transactionSource); + + await this.TransactionAggregateRepository.SaveChanges(transactionAggregate, cancellationToken); + + } + public async Task AuthoriseTransaction(Guid estateId, Guid transactionId, String operatorIdentifier, OperatorResponse operatorResponse, TransactionResponseCode transactionResponseCode, String responseMessage, - CancellationToken cancellationToken) - { + CancellationToken cancellationToken) { TransactionAggregate transactionAggregate = await this.TransactionAggregateRepository.GetLatestVersion(transactionId, cancellationToken); transactionAggregate.AuthoriseTransaction(operatorIdentifier, @@ -131,20 +101,11 @@ public async Task AuthoriseTransaction(Guid estateId, await this.TransactionAggregateRepository.SaveChanges(transactionAggregate, cancellationToken); } - /// - /// Authorises the transaction locally. - /// - /// The estate identifier. - /// The transaction identifier. - /// The authorisation code. - /// The validation result. - /// The cancellation token. public async Task AuthoriseTransactionLocally(Guid estateId, Guid transactionId, String authorisationCode, (String responseMessage, TransactionResponseCode responseCode) validationResult, - CancellationToken cancellationToken) - { + CancellationToken cancellationToken) { TransactionAggregate transactionAggregate = await this.TransactionAggregateRepository.GetLatestVersion(transactionId, cancellationToken); transactionAggregate.AuthoriseTransactionLocally(authorisationCode, @@ -154,16 +115,9 @@ public async Task AuthoriseTransactionLocally(Guid estateId, await this.TransactionAggregateRepository.SaveChanges(transactionAggregate, cancellationToken); } - /// - /// Completes the transaction. - /// - /// The estate identifier. - /// The transaction identifier. - /// The cancellation token. public async Task CompleteTransaction(Guid estateId, Guid transactionId, - CancellationToken cancellationToken) - { + CancellationToken cancellationToken) { TransactionAggregate transactionAggregate = await this.TransactionAggregateRepository.GetLatestVersion(transactionId, cancellationToken); transactionAggregate.CompleteTransaction(); @@ -171,23 +125,13 @@ public async Task CompleteTransaction(Guid estateId, await this.TransactionAggregateRepository.SaveChanges(transactionAggregate, cancellationToken); } - /// - /// Declines the transaction. - /// - /// The estate identifier. - /// The transaction identifier. - /// The operator response. - /// The transaction response code. - /// The response message. - /// The cancellation token. public async Task DeclineTransaction(Guid estateId, Guid transactionId, String operatorIdentifier, OperatorResponse operatorResponse, TransactionResponseCode transactionResponseCode, String responseMessage, - CancellationToken cancellationToken) - { + CancellationToken cancellationToken) { TransactionAggregate transactionAggregate = await this.TransactionAggregateRepository.GetLatestVersion(transactionId, cancellationToken); transactionAggregate.DeclineTransaction(operatorIdentifier, @@ -199,18 +143,10 @@ public async Task DeclineTransaction(Guid estateId, await this.TransactionAggregateRepository.SaveChanges(transactionAggregate, cancellationToken); } - /// - /// Declines the transaction locally. - /// - /// The estate identifier. - /// The transaction identifier. - /// The validation result. - /// The cancellation token. public async Task DeclineTransactionLocally(Guid estateId, Guid transactionId, (String responseMessage, TransactionResponseCode responseCode) validationResult, - CancellationToken cancellationToken) - { + CancellationToken cancellationToken) { TransactionAggregate transactionAggregate = await this.TransactionAggregateRepository.GetLatestVersion(transactionId, cancellationToken); transactionAggregate.DeclineTransactionLocally(((Int32)validationResult.responseCode).ToString().PadLeft(4, '0'), validationResult.responseMessage); @@ -218,37 +154,19 @@ public async Task DeclineTransactionLocally(Guid estateId, await this.TransactionAggregateRepository.SaveChanges(transactionAggregate, cancellationToken); } - /// - /// Gets the aggregate. - /// - /// The estate identifier. - /// The transaction identifier. - /// The cancellation token. - /// public async Task GetAggregate(Guid estateId, Guid transactionId, - CancellationToken cancellationToken) - { + CancellationToken cancellationToken) { TransactionAggregate transactionAggregate = await this.TransactionAggregateRepository.GetLatestVersion(transactionId, cancellationToken); return transactionAggregate; } - /// - /// Records the additional request data. - /// - /// The estate identifier. - /// The transaction identifier. - /// The operator identifier. - /// The additional transaction request metadata. - /// The cancellation token. public async Task RecordAdditionalRequestData(Guid estateId, Guid transactionId, String operatorIdentifier, Dictionary additionalTransactionRequestMetadata, - CancellationToken cancellationToken) - { - if (additionalTransactionRequestMetadata != null && additionalTransactionRequestMetadata.Any()) - { + CancellationToken cancellationToken) { + if (additionalTransactionRequestMetadata != null && additionalTransactionRequestMetadata.Any()) { TransactionAggregate transactionAggregate = await this.TransactionAggregateRepository.GetLatestVersion(transactionId, cancellationToken); transactionAggregate.RecordAdditionalRequestData(operatorIdentifier, additionalTransactionRequestMetadata); @@ -257,21 +175,12 @@ public async Task RecordAdditionalRequestData(Guid estateId, } } - /// - /// Records the additional response data. - /// - /// The estate identifier. - /// The transaction identifier. - /// The additional transaction response metadata. - /// The cancellation token. public async Task RecordAdditionalResponseData(Guid estateId, Guid transactionId, String operatorIdentifier, Dictionary additionalTransactionResponseMetadata, - CancellationToken cancellationToken) - { - if (additionalTransactionResponseMetadata != null && additionalTransactionResponseMetadata.Any()) - { + CancellationToken cancellationToken) { + if (additionalTransactionResponseMetadata != null && additionalTransactionResponseMetadata.Any()) { TransactionAggregate transactionAggregate = await this.TransactionAggregateRepository.GetLatestVersion(transactionId, cancellationToken); transactionAggregate.RecordAdditionalResponseData(operatorIdentifier, additionalTransactionResponseMetadata); @@ -280,17 +189,10 @@ public async Task RecordAdditionalResponseData(Guid estateId, } } - /// - /// Requests the email receipt. - /// - /// The estate identifier. - /// The transaction identifier. - /// The cancellation token. public async Task RequestEmailReceipt(Guid estateId, Guid transactionId, String customerEmailAddress, - CancellationToken cancellationToken) - { + CancellationToken cancellationToken) { TransactionAggregate transactionAggregate = await this.TransactionAggregateRepository.GetLatestVersion(transactionId, cancellationToken); transactionAggregate.RequestEmailReceipt(customerEmailAddress); @@ -298,19 +200,6 @@ public async Task RequestEmailReceipt(Guid estateId, await this.TransactionAggregateRepository.SaveChanges(transactionAggregate, cancellationToken); } - /// - /// Starts the transaction. - /// - /// The transaction identifier. - /// The transaction date time. - /// The transaction number. - /// Type of the transaction. - /// The transaction reference. - /// The estate identifier. - /// The merchant identifier. - /// The device identifier. - /// The transaction amount. - /// The cancellation token. public async Task StartTransaction(Guid transactionId, DateTime transactionDateTime, String transactionNumber, @@ -320,8 +209,7 @@ public async Task StartTransaction(Guid transactionId, Guid merchantId, String deviceIdentifier, Decimal? transactionAmount, - CancellationToken cancellationToken) - { + CancellationToken cancellationToken) { TransactionAggregate transactionAggregate = await this.TransactionAggregateRepository.GetLatestVersion(transactionId, cancellationToken); transactionAggregate.StartTransaction(transactionDateTime, diff --git a/TransactionProcessor.BusinessLogic/Services/TransactionDomainService.cs b/TransactionProcessor.BusinessLogic/Services/TransactionDomainService.cs index ca863ee0..73434cfc 100644 --- a/TransactionProcessor.BusinessLogic/Services/TransactionDomainService.cs +++ b/TransactionProcessor.BusinessLogic/Services/TransactionDomainService.cs @@ -182,9 +182,12 @@ public async Task ProcessSaleTransaction(Guid tr Dictionary additionalTransactionMetadata, Guid contractId, Guid productId, + Int32 transactionSource, CancellationToken cancellationToken) { TransactionType transactionType = TransactionType.Sale; + TransactionSource transactionSourceValue = (TransactionSource)transactionSource; + // Generate a transaction reference String transactionReference = this.GenerateTransactionReference(); @@ -212,6 +215,9 @@ await this.TransactionAggregateManager.StartTransaction(transactionId, await this.TransactionAggregateManager.AddProductDetails(estateId, transactionId, contractId, productId, cancellationToken); } + // Add the transaction source + await this.TransactionAggregateManager.AddTransactionSource(estateId, transactionId, transactionSourceValue, cancellationToken); + if (validationResult.responseCode == TransactionResponseCode.Success) { // Record any additional request metadata diff --git a/TransactionProcessor.DataTransferObjects/SaleTransactionRequest.cs b/TransactionProcessor.DataTransferObjects/SaleTransactionRequest.cs index d354dc88..304921e7 100644 --- a/TransactionProcessor.DataTransferObjects/SaleTransactionRequest.cs +++ b/TransactionProcessor.DataTransferObjects/SaleTransactionRequest.cs @@ -10,84 +10,33 @@ public class SaleTransactionRequest : DataTransferObject { #region Properties - /// - /// Gets or sets the additional transaction metadata. - /// - /// - /// The additional transaction metadata. - /// [JsonProperty("additional_transaction_metadata")] public Dictionary AdditionalTransactionMetadata { get; set; } - /// - /// Gets or sets the contract identifier. - /// - /// - /// The contract identifier. - /// [JsonProperty("contact_id")] public Guid ContractId { get; set; } - /// - /// Gets or sets the customer email address. - /// - /// - /// The customer email address. - /// [JsonProperty("customer_email_address")] public String CustomerEmailAddress { get; set; } - /// - /// Gets or sets the device identifier. - /// - /// - /// The device identifier. - /// [JsonProperty("device_identifier")] public String DeviceIdentifier { get; set; } - /// - /// Gets or sets the operator identifier. - /// - /// - /// The operator identifier. - /// [JsonProperty("operator_identifier")] public String OperatorIdentifier { get; set; } - /// - /// Gets or sets the product identifier. - /// - /// - /// The product identifier. - /// [JsonProperty("product_id")] public Guid ProductId { get; set; } - /// - /// Gets or sets the transaction date time. - /// - /// - /// The transaction date time. - /// [JsonProperty("transaction_date_time")] public DateTime TransactionDateTime { get; set; } - /// - /// Gets or sets the transaction number. - /// - /// - /// The transaction number. - /// [JsonProperty("transaction_number")] public String TransactionNumber { get; set; } - /// - /// Gets or sets the type of the transaction. - /// - /// - /// The type of the transaction. - /// + [JsonProperty("transaction_source")] + public Int32? TransactionSource { get; set; } + [JsonProperty("transaction_type")] public String TransactionType { get; set; } diff --git a/TransactionProcessor.IntegrationTests/SaleTransaction/SaleTransactionFeature.feature b/TransactionProcessor.IntegrationTests/SaleTransaction/SaleTransactionFeature.feature index b38e927d..b80545f9 100644 --- a/TransactionProcessor.IntegrationTests/SaleTransaction/SaleTransactionFeature.feature +++ b/TransactionProcessor.IntegrationTests/SaleTransaction/SaleTransactionFeature.feature @@ -85,14 +85,14 @@ Background: Scenario: Sale Transactions When I perform the following transactions - | DateTime | TransactionNumber | TransactionType | MerchantName | DeviceIdentifier | EstateName | OperatorName | TransactionAmount | CustomerAccountNumber | CustomerEmailAddress | ContractDescription | ProductName | RecipientEmail | RecipientMobile | - | Today | 1 | Sale | Test Merchant 1 | 123456780 | Test Estate 1 | Safaricom | 100.00 | 123456789 | | Safaricom Contract | Variable Topup | | | - | Today | 2 | Sale | Test Merchant 2 | 123456781 | Test Estate 1 | Safaricom | 100.00 | 123456789 | | Safaricom Contract | Variable Topup | | | - | Today | 3 | Sale | Test Merchant 3 | 123456782 | Test Estate 2 | Safaricom | 100.00 | 123456789 | | Safaricom Contract | Variable Topup | | | - | Today | 4 | Sale | Test Merchant 1 | 123456780 | Test Estate 1 | Safaricom | 100.00 | 123456789 | testcustomer@customer.co.uk | Safaricom Contract | Variable Topup | | | - | Today | 5 | Sale | Test Merchant 1 | 123456780 | Test Estate 1 | Voucher | 10.00 | | | Hospital 1 Contract | 10 KES | test@recipient.co.uk | | - | Today | 6 | Sale | Test Merchant 2 | 123456781 | Test Estate 1 | Voucher | 10.00 | | | Hospital 1 Contract | 10 KES | | 123456789 | - | Today | 7 | Sale | Test Merchant 3 | 123456782 | Test Estate 2 | Voucher | 10.00 | | | Hospital 1 Contract | 10 KES | test@recipient.co.uk | | + | DateTime | TransactionNumber | TransactionType | TransactionSource | MerchantName | DeviceIdentifier | EstateName | OperatorName | TransactionAmount | CustomerAccountNumber | CustomerEmailAddress | ContractDescription | ProductName | RecipientEmail | RecipientMobile | + | Today | 1 | Sale | 1 | Test Merchant 1 | 123456780 | Test Estate 1 | Safaricom | 100.00 | 123456789 | | Safaricom Contract | Variable Topup | | | + | Today | 2 | Sale | 1 | Test Merchant 2 | 123456781 | Test Estate 1 | Safaricom | 100.00 | 123456789 | | Safaricom Contract | Variable Topup | | | + | Today | 3 | Sale | 2 | Test Merchant 3 | 123456782 | Test Estate 2 | Safaricom | 100.00 | 123456789 | | Safaricom Contract | Variable Topup | | | + | Today | 4 | Sale | 1 | Test Merchant 1 | 123456780 | Test Estate 1 | Safaricom | 100.00 | 123456789 | testcustomer@customer.co.uk | Safaricom Contract | Variable Topup | | | + | Today | 5 | Sale | 1 | Test Merchant 1 | 123456780 | Test Estate 1 | Voucher | 10.00 | | | Hospital 1 Contract | 10 KES | test@recipient.co.uk | | + | Today | 6 | Sale | 1 | Test Merchant 2 | 123456781 | Test Estate 1 | Voucher | 10.00 | | | Hospital 1 Contract | 10 KES | | 123456789 | + | Today | 7 | Sale | 2 | Test Merchant 3 | 123456782 | Test Estate 2 | Voucher | 10.00 | | | Hospital 1 Contract | 10 KES | test@recipient.co.uk | | Then transaction response should contain the following information | EstateName | MerchantName | TransactionNumber | ResponseCode | ResponseMessage | @@ -107,8 +107,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 | ContractDescription | ProductName | - | Today | 1 | Sale | Test Merchant 1 | 123456781 | Test Estate 1 | Safaricom | 100.00 | 123456789 | testcustomer@customer.co.uk | Safaricom Contract | Variable Topup | + | DateTime | TransactionNumber | TransactionType | TransactionSource | MerchantName | DeviceIdentifier | EstateName | OperatorName | TransactionAmount | CustomerAccountNumber | CustomerEmailAddress | ContractDescription | ProductName | + | Today | 1 | Sale | 1 | Test Merchant 1 | 123456781 | Test Estate 1 | Safaricom | 100.00 | 123456789 | testcustomer@customer.co.uk | Safaricom Contract | Variable Topup | Then transaction response should contain the following information | EstateName | MerchantName | TransactionNumber | ResponseCode | ResponseMessage | @@ -117,8 +117,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 | ContractDescription | ProductName | - | Today | 1 | Sale | Test Merchant 1 | 123456780 | InvalidEstate | Safaricom | 100.00 | 123456789 | testcustomer@customer.co.uk | Safaricom Contract | Variable Topup | + | DateTime | TransactionNumber | TransactionType | TransactionSource | MerchantName | DeviceIdentifier | EstateName | OperatorName | TransactionAmount | CustomerAccountNumber | CustomerEmailAddress | ContractDescription | ProductName | + | Today | 1 | Sale | 1 | Test Merchant 1 | 123456780 | InvalidEstate | Safaricom | 100.00 | 123456789 | testcustomer@customer.co.uk | Safaricom Contract | Variable Topup | Then transaction response should contain the following information | EstateName | MerchantName | TransactionNumber | ResponseCode | ResponseMessage | @@ -127,8 +127,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 | ContractDescription | ProductName | - | Today | 1 | Sale | InvalidMerchant | 123456780 | Test Estate 1 | Safaricom | 100.00 | 123456789 | testcustomer@customer.co.uk | Safaricom Contract | Variable Topup | + | DateTime | TransactionNumber | TransactionType | TransactionSource | MerchantName | DeviceIdentifier | EstateName | OperatorName | TransactionAmount | CustomerAccountNumber | CustomerEmailAddress | ContractDescription | ProductName | + | Today | 1 | Sale | 1 | InvalidMerchant | 123456780 | Test Estate 1 | Safaricom | 100.00 | 123456789 | testcustomer@customer.co.uk | Safaricom Contract | Variable Topup | Then transaction response should contain the following information | EstateName | MerchantName | TransactionNumber | ResponseCode | ResponseMessage | @@ -137,8 +137,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 | ContractDescription | ProductName | - | Today | 1 | Sale | Test Merchant 1 | 123456780 | Test Estate 1 | Safaricom | 300.00 | 123456789 | testcustomer@customer.co.uk | Safaricom Contract | Variable Topup | + | DateTime | TransactionNumber | TransactionType | TransactionSource | MerchantName | DeviceIdentifier | EstateName | OperatorName | TransactionAmount | CustomerAccountNumber | CustomerEmailAddress | ContractDescription | ProductName | + | Today | 1 | Sale | 1 | Test Merchant 1 | 123456780 | Test Estate 1 | Safaricom | 300.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 d3038317..fed498fd 100644 --- a/TransactionProcessor.IntegrationTests/SaleTransaction/SaleTransactionFeature.feature.cs +++ b/TransactionProcessor.IntegrationTests/SaleTransaction/SaleTransactionFeature.feature.cs @@ -441,6 +441,7 @@ public void SaleTransactions() "DateTime", "TransactionNumber", "TransactionType", + "TransactionSource", "MerchantName", "DeviceIdentifier", "EstateName", @@ -456,6 +457,7 @@ public void SaleTransactions() "Today", "1", "Sale", + "1", "Test Merchant 1", "123456780", "Test Estate 1", @@ -471,6 +473,7 @@ public void SaleTransactions() "Today", "2", "Sale", + "1", "Test Merchant 2", "123456781", "Test Estate 1", @@ -486,6 +489,7 @@ public void SaleTransactions() "Today", "3", "Sale", + "2", "Test Merchant 3", "123456782", "Test Estate 2", @@ -501,6 +505,7 @@ public void SaleTransactions() "Today", "4", "Sale", + "1", "Test Merchant 1", "123456780", "Test Estate 1", @@ -516,6 +521,7 @@ public void SaleTransactions() "Today", "5", "Sale", + "1", "Test Merchant 1", "123456780", "Test Estate 1", @@ -531,6 +537,7 @@ public void SaleTransactions() "Today", "6", "Sale", + "1", "Test Merchant 2", "123456781", "Test Estate 1", @@ -546,6 +553,7 @@ public void SaleTransactions() "Today", "7", "Sale", + "2", "Test Merchant 3", "123456782", "Test Estate 2", @@ -640,6 +648,7 @@ public void SaleTransactionWithInvalidDevice() "DateTime", "TransactionNumber", "TransactionType", + "TransactionSource", "MerchantName", "DeviceIdentifier", "EstateName", @@ -653,6 +662,7 @@ public void SaleTransactionWithInvalidDevice() "Today", "1", "Sale", + "1", "Test Merchant 1", "123456781", "Test Estate 1", @@ -709,6 +719,7 @@ public void SaleTransactionWithInvalidEstate() "DateTime", "TransactionNumber", "TransactionType", + "TransactionSource", "MerchantName", "DeviceIdentifier", "EstateName", @@ -722,6 +733,7 @@ public void SaleTransactionWithInvalidEstate() "Today", "1", "Sale", + "1", "Test Merchant 1", "123456780", "InvalidEstate", @@ -778,6 +790,7 @@ public void SaleTransactionWithInvalidMerchant() "DateTime", "TransactionNumber", "TransactionType", + "TransactionSource", "MerchantName", "DeviceIdentifier", "EstateName", @@ -791,6 +804,7 @@ public void SaleTransactionWithInvalidMerchant() "Today", "1", "Sale", + "1", "InvalidMerchant", "123456780", "Test Estate 1", @@ -848,6 +862,7 @@ public void SaleTransactionWithNotEnoughCreditAvailable() "DateTime", "TransactionNumber", "TransactionType", + "TransactionSource", "MerchantName", "DeviceIdentifier", "EstateName", @@ -861,6 +876,7 @@ public void SaleTransactionWithNotEnoughCreditAvailable() "Today", "1", "Sale", + "1", "Test Merchant 1", "123456780", "Test Estate 1", diff --git a/TransactionProcessor.IntegrationTests/Settlement/Settlement.feature b/TransactionProcessor.IntegrationTests/Settlement/Settlement.feature index a576d39e..3ca8746b 100644 --- a/TransactionProcessor.IntegrationTests/Settlement/Settlement.feature +++ b/TransactionProcessor.IntegrationTests/Settlement/Settlement.feature @@ -75,15 +75,15 @@ Scenario: Get Pending Settlement | Deposit1 | 120.00 | Today | Test Merchant 3 | Test Estate 1 | When I perform the following transactions - | DateTime | TransactionNumber | TransactionType | MerchantName | DeviceIdentifier | EstateName | OperatorName | TransactionAmount | CustomerAccountNumber | CustomerEmailAddress | ContractDescription | ProductName | RecipientEmail | RecipientMobile | - | 2022-01-06 | 1 | Sale | Test Merchant 1 | 123456780 | Test Estate 1 | Safaricom | 100.00 | 123456789 | | Safaricom Contract | Variable Topup | | | - | 2022-01-06 | 2 | Sale | Test Merchant 2 | 123456781 | Test Estate 1 | Safaricom | 100.00 | 123456789 | | Safaricom Contract | Variable Topup | | | - | 2022-01-06 | 3 | Sale | Test Merchant 3 | 123456782 | Test Estate 1 | Safaricom | 100.00 | 123456789 | | Safaricom Contract | Variable Topup | | | - | 2022-01-06 | 4 | Sale | Test Merchant 1 | 123456780 | Test Estate 1 | Safaricom | 100.00 | 123456789 | testcustomer@customer.co.uk | Safaricom Contract | Variable Topup | | | - | 2022-01-06 | 5 | Sale | Test Merchant 1 | 123456780 | Test Estate 1 | Voucher | 10.00 | | | Hospital 1 Contract | 10 KES | test@recipient.co.uk | | - | 2022-01-06 | 6 | Sale | Test Merchant 2 | 123456781 | Test Estate 1 | Voucher | 10.00 | | | Hospital 1 Contract | 10 KES | | 123456789 | - | 2022-01-06 | 7 | Sale | Test Merchant 3 | 123456782 | Test Estate 1 | Voucher | 10.00 | | | Hospital 1 Contract | 10 KES | test@recipient.co.uk | | - | 2022-01-06 | 8 | Sale | Test Merchant 3 | 123456782 | Test Estate 1 | Voucher | 10.00 | | | Hospital 1 Contract | 10 KES | test@recipient.co.uk | | + | DateTime | TransactionNumber | TransactionType | TransactionSource | MerchantName | DeviceIdentifier | EstateName | OperatorName | TransactionAmount | CustomerAccountNumber | CustomerEmailAddress | ContractDescription | ProductName | RecipientEmail | RecipientMobile | + | 2022-01-06 | 1 | Sale | 1 | Test Merchant 1 | 123456780 | Test Estate 1 | Safaricom | 100.00 | 123456789 | | Safaricom Contract | Variable Topup | | | + | 2022-01-06 | 2 | Sale | 1 | Test Merchant 2 | 123456781 | Test Estate 1 | Safaricom | 100.00 | 123456789 | | Safaricom Contract | Variable Topup | | | + | 2022-01-06 | 3 | Sale | 2 | Test Merchant 3 | 123456782 | Test Estate 1 | Safaricom | 100.00 | 123456789 | | Safaricom Contract | Variable Topup | | | + | 2022-01-06 | 4 | Sale | 1 | Test Merchant 1 | 123456780 | Test Estate 1 | Safaricom | 100.00 | 123456789 | testcustomer@customer.co.uk | Safaricom Contract | Variable Topup | | | + | 2022-01-06 | 5 | Sale | 1 | Test Merchant 1 | 123456780 | Test Estate 1 | Voucher | 10.00 | | | Hospital 1 Contract | 10 KES | test@recipient.co.uk | | + | 2022-01-06 | 6 | Sale | 1 | Test Merchant 2 | 123456781 | Test Estate 1 | Voucher | 10.00 | | | Hospital 1 Contract | 10 KES | | 123456789 | + | 2022-01-06 | 7 | Sale | 2 | Test Merchant 3 | 123456782 | Test Estate 1 | Voucher | 10.00 | | | Hospital 1 Contract | 10 KES | test@recipient.co.uk | | + | 2022-01-06 | 8 | Sale | 1 | Test Merchant 3 | 123456782 | Test Estate 1 | Voucher | 10.00 | | | Hospital 1 Contract | 10 KES | test@recipient.co.uk | | Then transaction response should contain the following information | EstateName | MerchantName | TransactionNumber | ResponseCode | ResponseMessage | @@ -130,12 +130,12 @@ Scenario: Process Settlement | Deposit1 | 110.00 | Today | Test Merchant 2 | Test Estate 1 | When I perform the following transactions - | DateTime | TransactionNumber | TransactionType | MerchantName | DeviceIdentifier | EstateName | OperatorName | TransactionAmount | CustomerAccountNumber | CustomerEmailAddress | ContractDescription | ProductName | RecipientEmail | RecipientMobile | - | 2022-01-06 | 1 | Sale | Test Merchant 1 | 123456780 | Test Estate 1 | Safaricom | 100.00 | 123456789 | | Safaricom Contract | Variable Topup | | | - | 2022-01-06 | 2 | Sale | Test Merchant 2 | 123456781 | Test Estate 1 | Safaricom | 100.00 | 123456789 | | Safaricom Contract | Variable Topup | | | - | 2022-01-06 | 4 | Sale | Test Merchant 1 | 123456780 | Test Estate 1 | Safaricom | 100.00 | 123456789 | testcustomer@customer.co.uk | Safaricom Contract | Variable Topup | | | - | 2022-01-06 | 5 | Sale | Test Merchant 1 | 123456780 | Test Estate 1 | Voucher | 10.00 | | | Hospital 1 Contract | 10 KES | test@recipient.co.uk | | - | 2022-01-06 | 6 | Sale | Test Merchant 2 | 123456781 | Test Estate 1 | Voucher | 10.00 | | | Hospital 1 Contract | 10 KES | | 123456789 | + | DateTime | TransactionNumber | TransactionType | TransactionSource | MerchantName | DeviceIdentifier | EstateName | OperatorName | TransactionAmount | CustomerAccountNumber | CustomerEmailAddress | ContractDescription | ProductName | RecipientEmail | RecipientMobile | + | 2022-01-06 | 1 | Sale | 1 | Test Merchant 1 | 123456780 | Test Estate 1 | Safaricom | 100.00 | 123456789 | | Safaricom Contract | Variable Topup | | | + | 2022-01-06 | 2 | Sale | 1 | Test Merchant 2 | 123456781 | Test Estate 1 | Safaricom | 100.00 | 123456789 | | Safaricom Contract | Variable Topup | | | + | 2022-01-06 | 4 | Sale | 1 | Test Merchant 1 | 123456780 | Test Estate 1 | Safaricom | 100.00 | 123456789 | testcustomer@customer.co.uk | Safaricom Contract | Variable Topup | | | + | 2022-01-06 | 5 | Sale | 1 | Test Merchant 1 | 123456780 | Test Estate 1 | Voucher | 10.00 | | | Hospital 1 Contract | 10 KES | test@recipient.co.uk | | + | 2022-01-06 | 6 | Sale | 1 | Test Merchant 2 | 123456781 | Test Estate 1 | Voucher | 10.00 | | | Hospital 1 Contract | 10 KES | | 123456789 | Then transaction response should contain the following information | EstateName | MerchantName | TransactionNumber | ResponseCode | ResponseMessage | diff --git a/TransactionProcessor.IntegrationTests/Settlement/Settlement.feature.cs b/TransactionProcessor.IntegrationTests/Settlement/Settlement.feature.cs index e50220e8..d307ea98 100644 --- a/TransactionProcessor.IntegrationTests/Settlement/Settlement.feature.cs +++ b/TransactionProcessor.IntegrationTests/Settlement/Settlement.feature.cs @@ -401,6 +401,7 @@ public void GetPendingSettlement() "DateTime", "TransactionNumber", "TransactionType", + "TransactionSource", "MerchantName", "DeviceIdentifier", "EstateName", @@ -416,6 +417,7 @@ public void GetPendingSettlement() "2022-01-06", "1", "Sale", + "1", "Test Merchant 1", "123456780", "Test Estate 1", @@ -431,6 +433,7 @@ public void GetPendingSettlement() "2022-01-06", "2", "Sale", + "1", "Test Merchant 2", "123456781", "Test Estate 1", @@ -446,6 +449,7 @@ public void GetPendingSettlement() "2022-01-06", "3", "Sale", + "2", "Test Merchant 3", "123456782", "Test Estate 1", @@ -461,6 +465,7 @@ public void GetPendingSettlement() "2022-01-06", "4", "Sale", + "1", "Test Merchant 1", "123456780", "Test Estate 1", @@ -476,6 +481,7 @@ public void GetPendingSettlement() "2022-01-06", "5", "Sale", + "1", "Test Merchant 1", "123456780", "Test Estate 1", @@ -491,6 +497,7 @@ public void GetPendingSettlement() "2022-01-06", "6", "Sale", + "1", "Test Merchant 2", "123456781", "Test Estate 1", @@ -506,6 +513,7 @@ public void GetPendingSettlement() "2022-01-06", "7", "Sale", + "2", "Test Merchant 3", "123456782", "Test Estate 1", @@ -521,6 +529,7 @@ public void GetPendingSettlement() "2022-01-06", "8", "Sale", + "1", "Test Merchant 3", "123456782", "Test Estate 1", @@ -751,6 +760,7 @@ public void ProcessSettlement() "DateTime", "TransactionNumber", "TransactionType", + "TransactionSource", "MerchantName", "DeviceIdentifier", "EstateName", @@ -766,6 +776,7 @@ public void ProcessSettlement() "2022-01-06", "1", "Sale", + "1", "Test Merchant 1", "123456780", "Test Estate 1", @@ -781,6 +792,7 @@ public void ProcessSettlement() "2022-01-06", "2", "Sale", + "1", "Test Merchant 2", "123456781", "Test Estate 1", @@ -796,6 +808,7 @@ public void ProcessSettlement() "2022-01-06", "4", "Sale", + "1", "Test Merchant 1", "123456780", "Test Estate 1", @@ -811,6 +824,7 @@ public void ProcessSettlement() "2022-01-06", "5", "Sale", + "1", "Test Merchant 1", "123456780", "Test Estate 1", @@ -826,6 +840,7 @@ public void ProcessSettlement() "2022-01-06", "6", "Sale", + "1", "Test Merchant 2", "123456781", "Test Estate 1", diff --git a/TransactionProcessor.IntegrationTests/Shared/SharedSteps.cs b/TransactionProcessor.IntegrationTests/Shared/SharedSteps.cs index e3170d38..ca723ad0 100644 --- a/TransactionProcessor.IntegrationTests/Shared/SharedSteps.cs +++ b/TransactionProcessor.IntegrationTests/Shared/SharedSteps.cs @@ -308,6 +308,7 @@ public async Task WhenIPerformTheFollowingTransactions(Table table) String customerEmailAddress = SpecflowTableHelper.GetStringRowValue(tableRow, "CustomerEmailAddress"); String contractDescription = SpecflowTableHelper.GetStringRowValue(tableRow, "ContractDescription"); String productName = SpecflowTableHelper.GetStringRowValue(tableRow, "ProductName"); + Int32 transactionSource = SpecflowTableHelper.GetIntValue(tableRow, "TransactionSource"); Guid contractId = Guid.Empty; Guid productId = Guid.Empty; @@ -335,6 +336,7 @@ public async Task WhenIPerformTheFollowingTransactions(Table table) productId, recipientEmail, recipientMobile, + transactionSource, CancellationToken.None); break; @@ -504,6 +506,7 @@ private async Task PerformSaleTransaction(Guid estateId, Guid Guid productId, String recipientEmail, String recipientMobile, + Int32 transactionSource, CancellationToken cancellationToken) { SaleTransactionRequest saleTransactionRequest = new SaleTransactionRequest @@ -517,7 +520,8 @@ private async Task PerformSaleTransaction(Guid estateId, Guid OperatorIdentifier = operatorIdentifier, CustomerEmailAddress = customerEmailAddress, ProductId = productId, - ContractId = contractId + ContractId = contractId, + TransactionSource = transactionSource }; if (operatorIdentifier == "Voucher") diff --git a/TransactionProcessor.Models/TransactionSource.cs b/TransactionProcessor.Models/TransactionSource.cs new file mode 100644 index 00000000..60520ef5 --- /dev/null +++ b/TransactionProcessor.Models/TransactionSource.cs @@ -0,0 +1,8 @@ +namespace TransactionProcessor.Models; + +public enum TransactionSource +{ + NotSet = 0, + OnlineSale =1, + FileImport = 2 +} \ No newline at end of file diff --git a/TransactionProcessor.Testing/TestData.cs b/TransactionProcessor.Testing/TestData.cs index cfbdb7ad..a4f2da16 100644 --- a/TransactionProcessor.Testing/TestData.cs +++ b/TransactionProcessor.Testing/TestData.cs @@ -50,6 +50,8 @@ public class TestData public static Guid MerchantId = Guid.Parse("833B5AAC-A5C5-46C2-A499-F2B4252B2942"); + public static Int32 TransactionSource = 1; + public static Guid OperatorId = Guid.Parse("804E9D8D-C6FE-4A46-9E55-6A04EA3E1AE5"); public static String CustomerEmailAddress = "testcustomer1@customer.co.uk"; @@ -412,7 +414,8 @@ public static Dictionary AdditionalTransactionMetaDataForVoucher TestData.CustomerEmailAddress, TestData.AdditionalTransactionMetaData(), TestData.ContractId, - TestData.ProductId); + TestData.ProductId, + TestData.TransactionSource); public static ProcessSaleTransactionResponse ProcessSaleTransactionResponseModel => new ProcessSaleTransactionResponse diff --git a/TransactionProcessor.Transaction.DomainEvents/TransactionSourceAddedToTransactionEvent.cs b/TransactionProcessor.Transaction.DomainEvents/TransactionSourceAddedToTransactionEvent.cs new file mode 100644 index 00000000..8a4f5826 --- /dev/null +++ b/TransactionProcessor.Transaction.DomainEvents/TransactionSourceAddedToTransactionEvent.cs @@ -0,0 +1,34 @@ +namespace TransactionProcessor.Transaction.DomainEvents; + +using System; +using Shared.DomainDrivenDesign.EventSourcing; + +public record TransactionSourceAddedToTransactionEvent : DomainEvent +{ + #region Constructors + + public TransactionSourceAddedToTransactionEvent(Guid aggregateId, + Guid estateId, + Guid merchantId, + Int32 transactionSource) : base(aggregateId, Guid.NewGuid()) + { + this.TransactionId = aggregateId; + this.EstateId = estateId; + this.MerchantId = merchantId; + this.TransactionSource = transactionSource; + } + + #endregion + + #region Properties + + public Guid EstateId { get; init; } + + public Guid MerchantId { get; init; } + + public Int32 TransactionSource { get; init; } + + public Guid TransactionId { get; init; } + + #endregion +} \ No newline at end of file diff --git a/TransactionProcessor.TransactionAggregate.Tests/DomainEventTests.cs b/TransactionProcessor.TransactionAggregate.Tests/DomainEventTests.cs index a83c7e78..d71d1cb4 100644 --- a/TransactionProcessor.TransactionAggregate.Tests/DomainEventTests.cs +++ b/TransactionProcessor.TransactionAggregate.Tests/DomainEventTests.cs @@ -296,7 +296,23 @@ public void ServiceProviderFeeAddedToTransactionEvent_CanBeCreated_IsCreated() serviceProviderFeeAddedToTransactionEvent.FeeId.ShouldBe(TestData.TransactionFeeId); serviceProviderFeeAddedToTransactionEvent.FeeValue.ShouldBe(TestData.TransactionFeeValue); serviceProviderFeeAddedToTransactionEvent.FeeCalculatedDateTime.ShouldBe(TestData.TransactionFeeCalculateDateTime); + } + + [Fact] + public void TransactionSourceAddedToTransactionEvent_CanBeCreated_IsCreated() + { + TransactionSourceAddedToTransactionEvent transactionSourceAddedToTransactionEvent = new TransactionSourceAddedToTransactionEvent(TestData.TransactionId, + TestData.EstateId, + TestData.MerchantId, + TestData.TransactionSource); + transactionSourceAddedToTransactionEvent.ShouldNotBeNull(); + transactionSourceAddedToTransactionEvent.AggregateId.ShouldBe(TestData.TransactionId); + transactionSourceAddedToTransactionEvent.EventId.ShouldNotBe(Guid.Empty); + transactionSourceAddedToTransactionEvent.TransactionId.ShouldBe(TestData.TransactionId); + transactionSourceAddedToTransactionEvent.EstateId.ShouldBe(TestData.EstateId); + transactionSourceAddedToTransactionEvent.MerchantId.ShouldBe(TestData.MerchantId); + transactionSourceAddedToTransactionEvent.TransactionSource.ShouldBe(TestData.TransactionSource); } } } diff --git a/TransactionProcessor.TransactionAggregate.Tests/TransactionAggregateTests.cs b/TransactionProcessor.TransactionAggregate.Tests/TransactionAggregateTests.cs index 0a5d46ed..2372eadd 100644 --- a/TransactionProcessor.TransactionAggregate.Tests/TransactionAggregateTests.cs +++ b/TransactionProcessor.TransactionAggregate.Tests/TransactionAggregateTests.cs @@ -6,6 +6,7 @@ namespace TransactionProcessor.TransactionAggregate.Tests { using System.Collections.Generic; using System.Linq; + using Microsoft.AspNetCore.SignalR; using Models; using Shouldly; @@ -185,6 +186,56 @@ public void TransactionAggregate_AddProductDetails_ProductDetailsAdded(Transacti transactionAggregate.ProductId.ShouldBe(TestData.ProductId); } + [Theory] + [InlineData(TransactionSource.OnlineSale)] + [InlineData(TransactionSource.FileImport)] + public void TransactionAggregate_AddTransactionSource_TransactionSourceAdded(TransactionSource transactionSource) + { + TransactionAggregate transactionAggregate = TransactionAggregate.Create(TestData.TransactionId); + transactionAggregate.StartTransaction(TestData.TransactionDateTime, TestData.TransactionNumber, + TransactionType.Sale, TestData.TransactionReference, TestData.EstateId, + TestData.MerchantId, TestData.DeviceIdentifier, + TestData.TransactionAmount); + + transactionAggregate.AddProductDetails(TestData.ContractId, TestData.ProductId); + transactionAggregate.AddTransactionSource(transactionSource); + + transactionAggregate.TransactionSource.ShouldBe(transactionSource); + } + + [Fact] + public void TransactionAggregate_AddTransactionSource_InvalidSource_ErrorThrown() + { + TransactionAggregate transactionAggregate = TransactionAggregate.Create(TestData.TransactionId); + transactionAggregate.StartTransaction(TestData.TransactionDateTime, TestData.TransactionNumber, + TransactionType.Sale, TestData.TransactionReference, TestData.EstateId, + TestData.MerchantId, TestData.DeviceIdentifier, + TestData.TransactionAmount); + + transactionAggregate.AddProductDetails(TestData.ContractId, TestData.ProductId); + Should.Throw(() => { + transactionAggregate.AddTransactionSource((TransactionSource)99); + }); + } + + [Theory] + [InlineData(TransactionSource.OnlineSale)] + [InlineData(TransactionSource.FileImport)] + public void TransactionAggregate_AddTransactionSource_SourceAlreadySet_NoErrorThrown(TransactionSource transactionSource) + { + TransactionAggregate transactionAggregate = TransactionAggregate.Create(TestData.TransactionId); + transactionAggregate.StartTransaction(TestData.TransactionDateTime, TestData.TransactionNumber, + TransactionType.Sale, TestData.TransactionReference, TestData.EstateId, + TestData.MerchantId, TestData.DeviceIdentifier, + TestData.TransactionAmount); + + transactionAggregate.AddProductDetails(TestData.ContractId, TestData.ProductId); + transactionAggregate.AddTransactionSource(transactionSource); + Should.NotThrow(() => { + transactionAggregate.AddTransactionSource(transactionSource); + }); + } + [Theory] [InlineData(TransactionType.Sale)] public void TransactionAggregate_AddProductDetails_InvalidContractId_ErrorThrown(TransactionType transactionType) diff --git a/TransactionProcessor.TransactionAgrgegate/TransactionAggregate.cs b/TransactionProcessor.TransactionAgrgegate/TransactionAggregate.cs index 19572c2f..6e110150 100644 --- a/TransactionProcessor.TransactionAgrgegate/TransactionAggregate.cs +++ b/TransactionProcessor.TransactionAgrgegate/TransactionAggregate.cs @@ -8,7 +8,6 @@ using Models; using Shared.DomainDrivenDesign.EventSourcing; using Shared.EventStore.Aggregate; - using Shared.EventStore.EventStore; using Shared.General; using Transaction.DomainEvents; @@ -21,48 +20,22 @@ public class TransactionAggregate : Aggregate { #region Fields - /// - /// The additional transaction request metadata - /// private Dictionary AdditionalTransactionRequestMetadata; - /// - /// The additional transaction response metadata - /// private Dictionary AdditionalTransactionResponseMetadata; - /// - /// The calculated fees - /// private readonly List CalculatedFees; - /// - /// Gets the operator identifier. - /// - /// - /// The operator identifier. - /// - public String OperatorIdentifier { get; private set; } - #endregion #region Constructors - /// - /// Initializes a new instance of the class. - /// [ExcludeFromCodeCoverage] - public TransactionAggregate() - { + public TransactionAggregate() { this.CalculatedFees = new List(); } - /// - /// Initializes a new instance of the class. - /// - /// The aggregate identifier. - private TransactionAggregate(Guid aggregateId) - { + private TransactionAggregate(Guid aggregateId) { Guard.ThrowIfInvalidGuid(aggregateId, "Aggregate Id cannot be an Empty Guid"); this.AggregateId = aggregateId; @@ -73,215 +46,66 @@ private TransactionAggregate(Guid aggregateId) #region Properties - /// - /// Gets the authorisation code. - /// - /// - /// The authorisation code. - /// public String AuthorisationCode { get; private set; } - /// - /// Gets the contract identifier. - /// - /// - /// The contract identifier. - /// public Guid ContractId { get; private set; } - /// - /// Gets a value indicating whether [customer email receipt has been requested]. - /// - /// - /// true if [customer email receipt has been requested]; otherwise, false. - /// public Boolean CustomerEmailReceiptHasBeenRequested { get; private set; } - /// - /// Gets the device identifier. - /// - /// - /// The device identifier. - /// public String DeviceIdentifier { get; private set; } - /// - /// Gets the estate identifier. - /// - /// - /// The estate identifier. - /// public Guid EstateId { get; private set; } - /// - /// Gets a value indicating whether this instance is authorised. - /// - /// - /// true if this instance is authorised; otherwise, false. - /// public Boolean IsAuthorised { get; private set; } - /// - /// Gets a value indicating whether this instance is completed. - /// - /// - /// true if this instance is completed; otherwise, false. - /// public Boolean IsCompleted { get; private set; } - /// - /// Gets a value indicating whether this instance is declined. - /// - /// - /// true if this instance is declined; otherwise, false. - /// public Boolean IsDeclined { get; private set; } - /// - /// Gets a value indicating whether this instance is locally authorised. - /// - /// - /// true if this instance is locally authorised; otherwise, false. - /// public Boolean IsLocallyAuthorised { get; private set; } - /// - /// Gets a value indicating whether this instance is locally declined. - /// - /// - /// true if this instance is locally declined; otherwise, false. - /// public Boolean IsLocallyDeclined { get; private set; } - /// - /// Gets a value indicating whether this instance is product details added. - /// - /// - /// true if this instance is product details added; otherwise, false. - /// public Boolean IsProductDetailsAdded { get; private set; } - /// - /// Gets a value indicating whether this instance is started. - /// - /// - /// true if this instance is started; otherwise, false. - /// public Boolean IsStarted { get; private set; } - /// - /// Gets the merchant identifier. - /// - /// - /// The merchant identifier. - /// public Guid MerchantId { get; private set; } - /// - /// Gets the operator response code. - /// - /// - /// The operator response code. - /// + public String OperatorIdentifier { get; private set; } + public String OperatorResponseCode { get; private set; } - /// - /// Gets the operator response message. - /// - /// - /// The operator response message. - /// public String OperatorResponseMessage { get; private set; } - /// - /// Gets the operator transaction identifier. - /// - /// - /// The operator transaction identifier. - /// public String OperatorTransactionId { get; private set; } - /// - /// Gets the product identifier. - /// - /// - /// The product identifier. - /// public Guid ProductId { get; private set; } - /// - /// Gets the response code. - /// - /// - /// The response code. - /// public String ResponseCode { get; private set; } - /// - /// Gets the response message. - /// - /// - /// The response message. - /// public String ResponseMessage { get; private set; } - /// - /// Gets the transaction amount. - /// - /// - /// The transaction amount. - /// public Decimal? TransactionAmount { get; private set; } - /// - /// Gets the transaction date time. - /// - /// - /// The transaction date time. - /// public DateTime TransactionDateTime { get; private set; } - /// - /// Gets the transaction number. - /// - /// - /// The transaction number. - /// public String TransactionNumber { get; private set; } - /// - /// Gets the transaction reference. - /// - /// - /// The transaction reference. - /// public String TransactionReference { get; private set; } - /// - /// Gets the type of the transaction. - /// - /// - /// The type of the transaction. - /// + public TransactionSource TransactionSource { get; private set; } + public TransactionType TransactionType { get; private set; } #endregion #region Methods - /// - /// Adds the fee. - /// - /// The calculated fee. - /// calculatedFee - /// Unsupported Fee Type - /// calculatedFee - /// Unsupported Fee Type - public void AddFee(CalculatedFee calculatedFee) - { + public void AddFee(CalculatedFee calculatedFee) { Guard.ThrowIfNull(calculatedFee, nameof(calculatedFee)); - if (HasFeeAlreadyBeenAdded(calculatedFee) == true) + if (this.HasFeeAlreadyBeenAdded(calculatedFee)) return; this.CheckTransactionHasBeenAuthorised(); @@ -289,37 +113,49 @@ public void AddFee(CalculatedFee calculatedFee) this.CheckTransactionCanAttractFees(); DomainEvent @event = null; - if (calculatedFee.FeeType == FeeType.ServiceProvider) - { + if (calculatedFee.FeeType == FeeType.ServiceProvider) { // This is an operational (service provider) fee @event = new ServiceProviderFeeAddedToTransactionEvent(this.AggregateId, - this.EstateId, - this.MerchantId, - calculatedFee.CalculatedValue, - (Int32)calculatedFee.FeeCalculationType, - calculatedFee.FeeId, - calculatedFee.FeeValue, - calculatedFee.FeeCalculatedDateTime); + this.EstateId, + this.MerchantId, + calculatedFee.CalculatedValue, + (Int32)calculatedFee.FeeCalculationType, + calculatedFee.FeeId, + calculatedFee.FeeValue, + calculatedFee.FeeCalculatedDateTime); } - else - { + else { throw new InvalidOperationException("Unsupported Fee Type"); } - if (@event != null) - { + if (@event != null) { this.ApplyAndAppend(@event); } } - public void AddSettledFee(CalculatedFee calculatedFee, DateTime settlementDueDate, DateTime settledDateTime) - { - if (calculatedFee == null) - { + public void AddProductDetails(Guid contractId, + Guid productId) { + Guard.ThrowIfInvalidGuid(contractId, typeof(ArgumentException), $"Contract Id must not be [{Guid.Empty}]"); + Guard.ThrowIfInvalidGuid(productId, typeof(ArgumentException), $"Product Id must not be [{Guid.Empty}]"); + + this.CheckTransactionHasBeenStarted(); + this.CheckTransactionNotAlreadyCompleted(); + this.CheckProductDetailsNotAlreadyAdded(); + + ProductDetailsAddedToTransactionEvent productDetailsAddedToTransactionEvent = + new ProductDetailsAddedToTransactionEvent(this.AggregateId, this.EstateId, this.MerchantId, contractId, productId); + + this.ApplyAndAppend(productDetailsAddedToTransactionEvent); + } + + public void AddSettledFee(CalculatedFee calculatedFee, + DateTime settlementDueDate, + DateTime settledDateTime) { + if (calculatedFee == null) { throw new ArgumentNullException(nameof(calculatedFee)); } - if (this.HasFeeAlreadyBeenAdded(calculatedFee) == true) + if (this.HasFeeAlreadyBeenAdded(calculatedFee)) return; this.CheckTransactionHasBeenAuthorised(); @@ -327,96 +163,66 @@ public void AddSettledFee(CalculatedFee calculatedFee, DateTime settlementDueDat this.CheckTransactionCanAttractFees(); DomainEvent @event = null; - if (calculatedFee.FeeType == FeeType.Merchant) - { + if (calculatedFee.FeeType == FeeType.Merchant) { // This is a merchant fee @event = new MerchantFeeAddedToTransactionEvent(this.AggregateId, - this.EstateId, - this.MerchantId, - calculatedFee.CalculatedValue, - (Int32)calculatedFee.FeeCalculationType, - calculatedFee.FeeId, - calculatedFee.FeeValue, - calculatedFee.FeeCalculatedDateTime, - settlementDueDate, - settledDateTime); + this.EstateId, + this.MerchantId, + calculatedFee.CalculatedValue, + (Int32)calculatedFee.FeeCalculationType, + calculatedFee.FeeId, + calculatedFee.FeeValue, + calculatedFee.FeeCalculatedDateTime, + settlementDueDate, + settledDateTime); } - else - { + else { throw new InvalidOperationException("Unsupported Fee Type"); } - if (@event != null) - { + if (@event != null) { this.ApplyAndAppend(@event); } } - /// - /// Adds the product details. - /// - /// The contract identifier. - /// The product identifier. - public void AddProductDetails(Guid contractId, - Guid productId) - { - Guard.ThrowIfInvalidGuid(contractId, typeof(ArgumentException), $"Contract Id must not be [{Guid.Empty}]"); - Guard.ThrowIfInvalidGuid(productId, typeof(ArgumentException), $"Product Id must not be [{Guid.Empty}]"); + public void AddTransactionSource(TransactionSource transactionSource) { + Guard.ThrowIfInvalidEnum(typeof(TransactionSource), transactionSource, typeof(ArgumentException), "Transaction Source must be a valid source"); - this.CheckTransactionHasBeenStarted(); - this.CheckTransactionNotAlreadyCompleted(); - this.CheckProductDetailsNotAlreadyAdded(); + if (this.TransactionSource != TransactionSource.NotSet) + return; - ProductDetailsAddedToTransactionEvent productDetailsAddedToTransactionEvent = - new ProductDetailsAddedToTransactionEvent(this.AggregateId, this.EstateId, this.MerchantId, contractId, productId); + TransactionSourceAddedToTransactionEvent transactionSourceAddedToTransactionEvent = + new TransactionSourceAddedToTransactionEvent(this.AggregateId, this.EstateId, this.MerchantId, (Int32)transactionSource); - this.ApplyAndAppend(productDetailsAddedToTransactionEvent); + this.ApplyAndAppend(transactionSourceAddedToTransactionEvent); } - /// - /// Authorises the transaction. - /// - /// The operator identifier. - /// The authorisation code. - /// The operator response code. - /// The operator response message. - /// The operator transaction identifier. - /// The response code. - /// The response message. public void AuthoriseTransaction(String operatorIdentifier, String authorisationCode, String operatorResponseCode, String operatorResponseMessage, String operatorTransactionId, String responseCode, - String responseMessage) - { + String responseMessage) { this.CheckTransactionHasBeenStarted(); this.CheckTransactionNotAlreadyAuthorised(); TransactionAuthorisedByOperatorEvent transactionAuthorisedByOperatorEvent = new TransactionAuthorisedByOperatorEvent(this.AggregateId, - this.EstateId, - this.MerchantId, - operatorIdentifier, - authorisationCode, - operatorResponseCode, - operatorResponseMessage, - operatorTransactionId, - responseCode, - responseMessage); + this.EstateId, + this.MerchantId, + operatorIdentifier, + authorisationCode, + operatorResponseCode, + operatorResponseMessage, + operatorTransactionId, + responseCode, + responseMessage); this.ApplyAndAppend(transactionAuthorisedByOperatorEvent); } - /// - /// Authorises the transaction. - /// - /// The authorisation code. - /// The response code. - /// The response message. public void AuthoriseTransactionLocally(String authorisationCode, String responseCode, - String responseMessage) - { + String responseMessage) { this.CheckTransactionHasBeenStarted(); this.CheckTransactionNotAlreadyAuthorised(); this.CheckTransactionCanBeLocallyAuthorised(); @@ -426,76 +232,51 @@ public void AuthoriseTransactionLocally(String authorisationCode, this.ApplyAndAppend(transactionHasBeenLocallyAuthorisedEvent); } - /// - /// Completes the transaction. - /// - public void CompleteTransaction() - { + public void CompleteTransaction() { this.CheckTransactionHasBeenStarted(); this.CheckTransactionHasBeenAuthorisedOrDeclined(); this.CheckTransactionNotAlreadyCompleted(); TransactionHasBeenCompletedEvent transactionHasBeenCompletedEvent = new TransactionHasBeenCompletedEvent(this.AggregateId, - this.EstateId, - this.MerchantId, - this.ResponseCode, - this.ResponseMessage, - this.IsAuthorised || this.IsLocallyAuthorised, - this.TransactionDateTime, - this.TransactionType != TransactionType.Logon ? this.TransactionAmount : null); + this.EstateId, + this.MerchantId, + this.ResponseCode, + this.ResponseMessage, + this.IsAuthorised || this.IsLocallyAuthorised, + this.TransactionDateTime, + this.TransactionType != TransactionType.Logon ? this.TransactionAmount : null); this.ApplyAndAppend(transactionHasBeenCompletedEvent); } - /// - /// Creates the specified aggregate identifier. - /// - /// The aggregate identifier. - /// - public static TransactionAggregate Create(Guid aggregateId) - { + public static TransactionAggregate Create(Guid aggregateId) { return new TransactionAggregate(aggregateId); } - /// - /// Declines the transaction. - /// - /// The operator identifier. - /// The operator response code. - /// The operator response message. - /// The response code. - /// The response message. public void DeclineTransaction(String operatorIdentifier, String operatorResponseCode, String operatorResponseMessage, String responseCode, - String responseMessage) - { + String responseMessage) { this.CheckTransactionHasBeenStarted(); this.CheckTransactionNotAlreadyAuthorised(); this.CheckTransactionNotAlreadyDeclined(); TransactionDeclinedByOperatorEvent transactionDeclinedByOperatorEvent = new TransactionDeclinedByOperatorEvent(this.AggregateId, - this.EstateId, - this.MerchantId, - operatorIdentifier, - operatorResponseCode, - operatorResponseMessage, - responseCode, - responseMessage); + this.EstateId, + this.MerchantId, + operatorIdentifier, + operatorResponseCode, + operatorResponseMessage, + responseCode, + responseMessage); this.ApplyAndAppend(transactionDeclinedByOperatorEvent); } - /// - /// Declines the transaction. - /// - /// The response code. - /// The response message. public void DeclineTransactionLocally(String responseCode, - String responseMessage) - { + String responseMessage) { this.CheckTransactionHasBeenStarted(); this.CheckTransactionNotAlreadyAuthorised(); this.CheckTransactionNotAlreadyDeclined(); @@ -505,23 +286,33 @@ public void DeclineTransactionLocally(String responseCode, this.ApplyAndAppend(transactionHasBeenLocallyDeclinedEvent); } - /// - /// Gets the fees. - /// - /// - public List GetFees() - { + public List GetFees() { return this.CalculatedFees; } - /// - /// Records the additional request data. - /// - /// The operator identifier. - /// The additional transaction request metadata. + public Transaction GetTransaction() { + return new Transaction { + AuthorisationCode = this.AuthorisationCode, + MerchantId = this.MerchantId, + OperatorTransactionId = this.OperatorTransactionId, + ResponseMessage = this.ResponseMessage, + TransactionAmount = this.TransactionAmount.HasValue ? this.TransactionAmount.Value : 0, + TransactionDateTime = this.TransactionDateTime, + TransactionNumber = this.TransactionNumber, + TransactionReference = this.TransactionReference, + OperatorIdentifier = this.OperatorIdentifier, + AdditionalRequestMetadata = this.AdditionalTransactionRequestMetadata, + AdditionalResponseMetadata = this.AdditionalTransactionResponseMetadata, + ResponseCode = this.ResponseCode + }; + } + + public override void PlayEvent(IDomainEvent domainEvent) { + this.PlayEvent((dynamic)domainEvent); + } + public void RecordAdditionalRequestData(String operatorIdentifier, - Dictionary additionalTransactionRequestMetadata) - { + Dictionary additionalTransactionRequestMetadata) { this.CheckTransactionNotAlreadyCompleted(); this.CheckTransactionHasBeenStarted(); this.CheckTransactionNotAlreadyAuthorised(); @@ -534,14 +325,8 @@ public void RecordAdditionalRequestData(String operatorIdentifier, this.ApplyAndAppend(additionalRequestDataRecordedEvent); } - /// - /// Records the additional response data. - /// - /// The operator identifier. - /// The additional transaction response metadata. public void RecordAdditionalResponseData(String operatorIdentifier, - Dictionary additionalTransactionResponseMetadata) - { + Dictionary additionalTransactionResponseMetadata) { this.CheckTransactionHasBeenStarted(); this.CheckAdditionalResponseDataNotAlreadyRecorded(); @@ -551,12 +336,7 @@ public void RecordAdditionalResponseData(String operatorIdentifier, this.ApplyAndAppend(additionalResponseDataRecordedEvent); } - /// - /// Requests the email receipt. - /// - /// The customer email address. - public void RequestEmailReceipt(String customerEmailAddress) - { + public void RequestEmailReceipt(String customerEmailAddress) { this.CheckTransactionHasBeenCompleted(); this.CheckCustomerHasNotAlreadyRequestedEmailReceipt(); @@ -566,27 +346,6 @@ public void RequestEmailReceipt(String customerEmailAddress) this.ApplyAndAppend(customerEmailReceiptRequestedEvent); } - /// - /// Starts the transaction. - /// - /// The transaction date time. - /// The transaction number. - /// Type of the transaction. - /// The transaction reference. - /// The estate identifier. - /// The merchant identifier. - /// The device identifier. - /// The transaction amount. - /// - /// Transaction Number must be numeric - /// or - /// Device Identifier must be alphanumeric - /// - /// Transaction Number must be numeric - /// or - /// Invalid Transaction Type [{transactionType}] - /// or - /// Device Identifier must be alphanumeric public void StartTransaction(DateTime transactionDateTime, String transactionNumber, TransactionType transactionType, @@ -594,13 +353,11 @@ public void StartTransaction(DateTime transactionDateTime, Guid estateId, Guid merchantId, String deviceIdentifier, - Decimal? transactionAmount) - { + Decimal? transactionAmount) { Guard.ThrowIfInvalidDate(transactionDateTime, typeof(ArgumentException), $"Transaction Date Time must not be [{DateTime.MinValue}]"); Guard.ThrowIfNullOrEmpty(transactionNumber, typeof(ArgumentException), "Transaction Number must not be null or empty"); Guard.ThrowIfNullOrEmpty(transactionReference, typeof(ArgumentException), "Transaction Reference must not be null or empty"); - if (int.TryParse(transactionNumber, out Int32 txnnumber) == false) - { + if (Int32.TryParse(transactionNumber, out Int32 txnnumber) == false) { throw new ArgumentException("Transaction Number must be numeric"); } @@ -612,272 +369,136 @@ public void StartTransaction(DateTime transactionDateTime, Guard.ThrowIfNullOrEmpty(deviceIdentifier, typeof(ArgumentException), "Device Identifier must not be null or empty"); Regex r = new Regex("^[a-zA-Z0-9]*$"); - if (r.IsMatch(deviceIdentifier) == false) - { + if (r.IsMatch(deviceIdentifier) == false) { throw new ArgumentException("Device Identifier must be alphanumeric"); } this.CheckTransactionNotAlreadyStarted(); this.CheckTransactionNotAlreadyCompleted(); TransactionHasStartedEvent transactionHasStartedEvent = new TransactionHasStartedEvent(this.AggregateId, - estateId, - merchantId, - transactionDateTime, - transactionNumber, - transactionType.ToString(), - transactionReference, - deviceIdentifier, - transactionAmount); + estateId, + merchantId, + transactionDateTime, + transactionNumber, + transactionType.ToString(), + transactionReference, + deviceIdentifier, + transactionAmount); this.ApplyAndAppend(transactionHasStartedEvent); } - /// - /// Gets the metadata. - /// - /// [ExcludeFromCodeCoverage] - protected override Object GetMetadata() - { - return new - { - this.EstateId - }; - } - - /// - /// Plays the event. - /// - /// The domain event. - public override void PlayEvent(IDomainEvent domainEvent) - { - this.PlayEvent((dynamic)domainEvent); + protected override Object GetMetadata() { + return new { + this.EstateId + }; } - /// - /// Checks the additional request data not already recorded. - /// - /// Additional Request Data already recorded - /// Additional Request Data already recorded - private void CheckAdditionalRequestDataNotAlreadyRecorded() - { - if (this.AdditionalTransactionRequestMetadata != null) - { + private void CheckAdditionalRequestDataNotAlreadyRecorded() { + if (this.AdditionalTransactionRequestMetadata != null) { throw new InvalidOperationException("Additional Request Data already recorded"); } } - /// - /// Checks the additional response data not already recorded. - /// - /// Additional Response Data already recorded - /// Additional Response Data already recorded - private void CheckAdditionalResponseDataNotAlreadyRecorded() - { - if (this.AdditionalTransactionResponseMetadata != null) - { + private void CheckAdditionalResponseDataNotAlreadyRecorded() { + if (this.AdditionalTransactionResponseMetadata != null) { throw new InvalidOperationException("Additional Response Data already recorded"); } } - /// - /// Checks the customer has not already requested email receipt. - /// - /// Customer Email Receipt already requested for Transaction [{this.AggregateId}] - /// Customer Email Receipt already requested for Transaction [{this.AggregateId}] - private void CheckCustomerHasNotAlreadyRequestedEmailReceipt() - { - if (this.CustomerEmailReceiptHasBeenRequested) - { + private void CheckCustomerHasNotAlreadyRequestedEmailReceipt() { + if (this.CustomerEmailReceiptHasBeenRequested) { throw new InvalidOperationException($"Customer Email Receipt already requested for Transaction [{this.AggregateId}]"); } } - private Boolean HasFeeAlreadyBeenAdded(CalculatedFee calculatedFee) - { - return this.CalculatedFees.Any(c => c.FeeId == calculatedFee.FeeId); - } - - /// - /// Checks the product details not already added. - /// - /// Product details already added - /// Product details already added - private void CheckProductDetailsNotAlreadyAdded() - { - if (this.IsProductDetailsAdded) - { + private void CheckProductDetailsNotAlreadyAdded() { + if (this.IsProductDetailsAdded) { throw new InvalidOperationException("Product details already added"); } } - /// - /// Checks the transaction can attract fees. - /// - /// Transactions of type {this.TransactionType} cannot attract fees - /// Transactions of type {this.TransactionType} cannot attract fees - private void CheckTransactionCanAttractFees() - { - if (this.TransactionType != TransactionType.Sale) - { + private void CheckTransactionCanAttractFees() { + if (this.TransactionType != TransactionType.Sale) { throw new NotSupportedException($"Transactions of type {this.TransactionType} cannot attract fees"); } } - /// - /// Checks the transaction can be locally authorised. - /// - /// Sales cannot be locally authorised - /// Sales cannot be locally authorised - /// Sales cannot be locally authorised - private void CheckTransactionCanBeLocallyAuthorised() - { - if (this.TransactionType == TransactionType.Sale) - { + private void CheckTransactionCanBeLocallyAuthorised() { + if (this.TransactionType == TransactionType.Sale) { throw new InvalidOperationException("Sales cannot be locally authorised"); } } - /// - /// Checks the transaction has been authorised. - /// - /// Transaction [{this.AggregateId}] has not been authorised - /// Transaction [{this.AggregateId}] has not been authorised - private void CheckTransactionHasBeenAuthorised() - { - if (this.IsLocallyAuthorised == false && this.IsAuthorised == false) - { + private void CheckTransactionHasBeenAuthorised() { + if (this.IsLocallyAuthorised == false && this.IsAuthorised == false) { throw new InvalidOperationException($"Transaction [{this.AggregateId}] has not been authorised"); } } - /// - /// Checks the transaction has been authorised. - /// - /// Transaction [{this.AggregateId}] has not been authorised or declined - /// Transaction [{this.AggregateId}] has not been authorised - private void CheckTransactionHasBeenAuthorisedOrDeclined() - { - if (this.IsAuthorised == false && this.IsLocallyAuthorised == false && this.IsDeclined == false && this.IsLocallyDeclined == false) - { + private void CheckTransactionHasBeenAuthorisedOrDeclined() { + if (this.IsAuthorised == false && this.IsLocallyAuthorised == false && this.IsDeclined == false && this.IsLocallyDeclined == false) { throw new InvalidOperationException($"Transaction [{this.AggregateId}] has not been authorised or declined"); } } - /// - /// Checks the transaction has been completed. - /// - /// Transaction [{this.AggregateId}] has not been completed - /// Transaction [{this.AggregateId}] has not been completed - private void CheckTransactionHasBeenCompleted() - { - if (this.IsCompleted == false) - { + private void CheckTransactionHasBeenCompleted() { + if (this.IsCompleted == false) { throw new InvalidOperationException($"Transaction [{this.AggregateId}] has not been completed"); } } - /// - /// Checks the transaction has been started. - /// - /// Transaction [{this.AggregateId}] has not been started - /// Transaction [{this.AggregateId}] has not been started - private void CheckTransactionHasBeenStarted() - { - if (this.IsStarted == false) - { + private void CheckTransactionHasBeenStarted() { + if (this.IsStarted == false) { throw new InvalidOperationException($"Transaction [{this.AggregateId}] has not been started"); } } - /// - /// Checks the transaction not already authorised. - /// - /// Transaction [{this.AggregateId}] has already been{authtype}authorised - /// Transaction [{this.AggregateId}] has already been{authtype}authorised - private void CheckTransactionNotAlreadyAuthorised() - { - if (this.IsLocallyAuthorised || this.IsAuthorised) - { + private void CheckTransactionNotAlreadyAuthorised() { + if (this.IsLocallyAuthorised || this.IsAuthorised) { String authtype = this.IsLocallyAuthorised ? " locally " : " "; throw new InvalidOperationException($"Transaction [{this.AggregateId}] has already been{authtype}authorised"); } } - /// - /// Checks the transaction not already completed. - /// - /// Transaction Id [{this.AggregateId}] has already been completed - /// Transaction Id [{this.AggregateId}] has already been completed - private void CheckTransactionNotAlreadyCompleted() - { - if (this.IsCompleted) - { + private void CheckTransactionNotAlreadyCompleted() { + if (this.IsCompleted) { throw new InvalidOperationException($"Transaction Id [{this.AggregateId}] has already been completed"); } } - /// - /// Checks the transaction not already declined. - /// - /// Transaction [{this.AggregateId}] has already been{authtype}declined - /// Transaction [{this.AggregateId}] has already been{authtype}declined - private void CheckTransactionNotAlreadyDeclined() - { - if (this.IsLocallyDeclined || this.IsDeclined) - { + private void CheckTransactionNotAlreadyDeclined() { + if (this.IsLocallyDeclined || this.IsDeclined) { String authtype = this.IsLocallyDeclined ? " locally " : " "; throw new InvalidOperationException($"Transaction [{this.AggregateId}] has already been{authtype}declined"); } } - /// - /// Checks the transaction not already started. - /// - /// Transaction Id [{this.AggregateId}] has already been started - /// Transaction Id [{this.AggregateId}] has already been started - private void CheckTransactionNotAlreadyStarted() - { - if (this.IsStarted) - { + private void CheckTransactionNotAlreadyStarted() { + if (this.IsStarted) { throw new InvalidOperationException($"Transaction Id [{this.AggregateId}] has already been started"); } } - /// - /// Plays the event. - /// - /// The domain event. - private void PlayEvent(CustomerEmailReceiptRequestedEvent domainEvent) - { + private Boolean HasFeeAlreadyBeenAdded(CalculatedFee calculatedFee) { + return this.CalculatedFees.Any(c => c.FeeId == calculatedFee.FeeId); + } + + private void PlayEvent(CustomerEmailReceiptRequestedEvent domainEvent) { this.CustomerEmailReceiptHasBeenRequested = true; } - /// - /// Plays the event. - /// - /// The domain event. - private void PlayEvent(AdditionalRequestDataRecordedEvent domainEvent) - { + private void PlayEvent(AdditionalRequestDataRecordedEvent domainEvent) { this.AdditionalTransactionRequestMetadata = domainEvent.AdditionalTransactionRequestMetadata; this.OperatorIdentifier = domainEvent.OperatorIdentifier; } - /// - /// Plays the event. - /// - /// The domain event. - private void PlayEvent(AdditionalResponseDataRecordedEvent domainEvent) - { + private void PlayEvent(AdditionalResponseDataRecordedEvent domainEvent) { this.AdditionalTransactionResponseMetadata = domainEvent.AdditionalTransactionResponseMetadata; } - /// - /// Plays the event. - /// - /// The domain event. - private void PlayEvent(TransactionHasStartedEvent domainEvent) - { + private void PlayEvent(TransactionHasStartedEvent domainEvent) { this.MerchantId = domainEvent.MerchantId; this.EstateId = domainEvent.EstateId; this.DeviceIdentifier = domainEvent.DeviceIdentifier; @@ -893,45 +514,25 @@ private void PlayEvent(TransactionHasStartedEvent domainEvent) this.TransactionAmount = domainEvent.TransactionAmount.HasValue ? domainEvent.TransactionAmount : null; } - /// - /// Plays the event. - /// - /// The domain event. - private void PlayEvent(TransactionHasBeenLocallyAuthorisedEvent domainEvent) - { + private void PlayEvent(TransactionHasBeenLocallyAuthorisedEvent domainEvent) { this.IsLocallyAuthorised = true; this.ResponseMessage = domainEvent.ResponseMessage; this.ResponseCode = domainEvent.ResponseCode; this.AuthorisationCode = domainEvent.AuthorisationCode; } - /// - /// Plays the event. - /// - /// The domain event. - private void PlayEvent(TransactionHasBeenLocallyDeclinedEvent domainEvent) - { + private void PlayEvent(TransactionHasBeenLocallyDeclinedEvent domainEvent) { this.IsLocallyDeclined = true; this.ResponseMessage = domainEvent.ResponseMessage; this.ResponseCode = domainEvent.ResponseCode; } - /// - /// Plays the event. - /// - /// The domain event. - private void PlayEvent(TransactionHasBeenCompletedEvent domainEvent) - { + private void PlayEvent(TransactionHasBeenCompletedEvent domainEvent) { this.IsStarted = false; // Transaction has reached its final state this.IsCompleted = true; } - /// - /// Plays the event. - /// - /// The domain event. - private void PlayEvent(TransactionAuthorisedByOperatorEvent domainEvent) - { + private void PlayEvent(TransactionAuthorisedByOperatorEvent domainEvent) { this.IsAuthorised = true; this.OperatorResponseCode = domainEvent.OperatorResponseCode; this.OperatorResponseMessage = domainEvent.OperatorResponseMessage; @@ -941,12 +542,7 @@ private void PlayEvent(TransactionAuthorisedByOperatorEvent domainEvent) this.ResponseMessage = domainEvent.ResponseMessage; } - /// - /// Plays the event. - /// - /// The domain event. - private void PlayEvent(TransactionDeclinedByOperatorEvent domainEvent) - { + private void PlayEvent(TransactionDeclinedByOperatorEvent domainEvent) { this.IsDeclined = true; this.OperatorResponseCode = domainEvent.OperatorResponseCode; this.OperatorResponseMessage = domainEvent.OperatorResponseMessage; @@ -954,73 +550,36 @@ private void PlayEvent(TransactionDeclinedByOperatorEvent domainEvent) this.ResponseMessage = domainEvent.ResponseMessage; } - /// - /// Plays the event. - /// - /// The domain event. - private void PlayEvent(ProductDetailsAddedToTransactionEvent domainEvent) - { + private void PlayEvent(ProductDetailsAddedToTransactionEvent domainEvent) { this.IsProductDetailsAdded = true; this.ContractId = domainEvent.ContractId; this.ProductId = domainEvent.ProductId; } - /// - /// Plays the event. - /// - /// The domain event. - private void PlayEvent(MerchantFeeAddedToTransactionEvent domainEvent) - { - this.CalculatedFees.Add(new CalculatedFee - { - CalculatedValue = domainEvent.CalculatedValue, - FeeId = domainEvent.FeeId, - FeeType = FeeType.Merchant, - FeeValue = domainEvent.FeeValue, - FeeCalculationType = (CalculationType)domainEvent.FeeCalculationType - }); + private void PlayEvent(TransactionSourceAddedToTransactionEvent domainEvent) { + this.TransactionSource = (TransactionSource)domainEvent.TransactionSource; } - /// - /// Plays the event. - /// - /// The domain event. - private void PlayEvent(ServiceProviderFeeAddedToTransactionEvent domainEvent) - { - this.CalculatedFees.Add(new CalculatedFee - { - CalculatedValue = domainEvent.CalculatedValue, - FeeId = domainEvent.FeeId, - FeeType = FeeType.ServiceProvider, - FeeValue = domainEvent.FeeValue, - FeeCalculationType = (CalculationType)domainEvent.FeeCalculationType - }); + private void PlayEvent(MerchantFeeAddedToTransactionEvent domainEvent) { + this.CalculatedFees.Add(new CalculatedFee { + CalculatedValue = domainEvent.CalculatedValue, + FeeId = domainEvent.FeeId, + FeeType = FeeType.Merchant, + FeeValue = domainEvent.FeeValue, + FeeCalculationType = (CalculationType)domainEvent.FeeCalculationType + }); } - #endregion - - - /// - /// Gets the transaction. - /// - /// - public Transaction GetTransaction() - { - return new Transaction - { - AuthorisationCode = this.AuthorisationCode, - MerchantId = this.MerchantId, - OperatorTransactionId = this.OperatorTransactionId, - ResponseMessage = this.ResponseMessage, - TransactionAmount = this.TransactionAmount.HasValue ? this.TransactionAmount.Value : 0, - TransactionDateTime = this.TransactionDateTime, - TransactionNumber = this.TransactionNumber, - TransactionReference = this.TransactionReference, - OperatorIdentifier = this.OperatorIdentifier, - AdditionalRequestMetadata = this.AdditionalTransactionRequestMetadata, - AdditionalResponseMetadata = this.AdditionalTransactionResponseMetadata, - ResponseCode = this.ResponseCode - }; + private void PlayEvent(ServiceProviderFeeAddedToTransactionEvent domainEvent) { + this.CalculatedFees.Add(new CalculatedFee { + CalculatedValue = domainEvent.CalculatedValue, + FeeId = domainEvent.FeeId, + FeeType = FeeType.ServiceProvider, + FeeValue = domainEvent.FeeValue, + FeeCalculationType = (CalculationType)domainEvent.FeeCalculationType + }); } + + #endregion } } \ No newline at end of file diff --git a/TransactionProcessor/Common/Examples/ExampleData.cs b/TransactionProcessor/Common/Examples/ExampleData.cs index ed776509..d146cf89 100644 --- a/TransactionProcessor/Common/Examples/ExampleData.cs +++ b/TransactionProcessor/Common/Examples/ExampleData.cs @@ -11,114 +11,52 @@ internal static class ExampleData { #region Fields - /// - /// The contract identifier - /// internal static Guid ContractId = Guid.Parse("64CB4CFC-F7DF-411C-9FB3-A631478B503C"); - - /// - /// The customer email address - /// + internal static String CustomerEmailAddress = "exmaplecustomer@email.com"; - /// - /// The device identifier - /// internal static String DeviceIdentifier = "exampledeviceidentifier1"; - /// - /// The estate identifier - /// internal static Guid EstateId = Guid.Parse("9B3D0726-D1FC-45CE-BBB4-18F83EB93F07"); - /// - /// The estate identifier metadata name - /// internal static String EstateIdMetadataName = "EstateId"; - /// - /// The logon response code - /// internal static String LogonResponseCode = "0000"; - /// - /// The logon response message - /// internal static String LogonResponseMessage = "SUCCESS"; - /// - /// The merchant identifier - /// internal static Guid MerchantId = Guid.Parse("9B3D0726-D1FC-45CE-BBB4-18F83EB93F07"); - /// - /// The merchant identifier metadata name - /// internal static String MerchantIdMetadataName = "MerchantId"; - /// - /// The operator identifier - /// internal static String OperatorIdentifier = "Safaricom"; - /// - /// The product identifier - /// internal static Guid ProductId = Guid.Parse("C0AEC683-587E-4F6A-BB20-B36312D9F712"); - /// - /// The reconciliation response code - /// + internal static Int32 OnlineSaleTransactionSource = 1; + + internal static Int32 FileBasedSaleTransactionSource = 2; + internal static String ReconciliationResponseCode = "0000"; - /// - /// The reconciliation response message - /// internal static String ReconciliationResponseMessage = "SUCCESS"; - /// - /// The sale response code - /// internal static String SaleResponseCode = "0000"; - /// - /// The sale response message - /// internal static String SaleResponseMessage = "SUCCESS"; - /// - /// The transaction count - /// internal static Int32 TransactionCount = 1; - /// - /// The transaction date time - /// internal static DateTime TransactionDateTime = DateTime.Now; - /// - /// The transaction number - /// internal static String TransactionNumber = "1"; - /// - /// The transaction type logon - /// internal static String TransactionTypeLogon = "Logon"; - /// - /// The transaction type sale - /// internal static String TransactionTypeSale = "Sale"; - /// - /// The transaction value - /// internal static Decimal TransactionValue = 10.00m; - /// - /// The transaction identifier - /// internal static Guid TransactionId = Guid.Parse("612970B8-FDF1-4CAA-998A-D84632BD4DE0"); #endregion diff --git a/TransactionProcessor/Common/Examples/TransactionRequestExample.cs b/TransactionProcessor/Common/Examples/TransactionRequestExample.cs index 86408c14..3ca18a8d 100644 --- a/TransactionProcessor/Common/Examples/TransactionRequestExample.cs +++ b/TransactionProcessor/Common/Examples/TransactionRequestExample.cs @@ -16,24 +16,17 @@ public class TransactionRequestExample : IMultipleExamplesProvider - /// Gets the examples. - /// - /// public IEnumerable> GetExamples() { return new List> { this.GetLogonExample(), - this.GetSaleExample(), + this.GetOnlineSaleExample(), + this.GetFileImportSaleExample(), this.GetReconciliationExample() }; } - /// - /// Gets the logon example. - /// - /// private SwaggerExample GetLogonExample() { LogonTransactionRequest request = new LogonTransactionRequest @@ -60,11 +53,7 @@ private SwaggerExample GetLogonExample() } }; } - - /// - /// Gets the reconciliation example. - /// - /// + private SwaggerExample GetReconciliationExample() { ReconciliationRequest request = new ReconciliationRequest @@ -102,13 +91,9 @@ private SwaggerExample GetReconciliationExample() }; } - /// - /// Gets the sale example. - /// - /// - private SwaggerExample GetSaleExample() + private SwaggerExample GetOnlineSaleExample() { - SaleTransactionRequest request = new SaleTransactionRequest + SaleTransactionRequest onlineSaleTransactionRequest = new SaleTransactionRequest { DeviceIdentifier = ExampleData.DeviceIdentifier, EstateId = ExampleData.EstateId, @@ -120,12 +105,13 @@ private SwaggerExample GetSaleExample() ContractId = ExampleData.ContractId, CustomerEmailAddress = ExampleData.CustomerEmailAddress, OperatorIdentifier = ExampleData.OperatorIdentifier, - ProductId = ExampleData.ProductId + ProductId = ExampleData.ProductId, + TransactionSource = ExampleData.OnlineSaleTransactionSource }; return new SwaggerExample { - Name = "Sale Request", + Name = "Online Sale Request", Value = new SerialisedMessage { Metadata = new Dictionary @@ -133,11 +119,44 @@ private SwaggerExample GetSaleExample() {ExampleData.EstateIdMetadataName, ExampleData.EstateId.ToString()}, {ExampleData.MerchantIdMetadataName, ExampleData.MerchantId.ToString()} }, - SerialisedData = JsonConvert.SerializeObject(request, Formatting.Indented) + SerialisedData = JsonConvert.SerializeObject(onlineSaleTransactionRequest, Formatting.Indented) } }; } + private SwaggerExample GetFileImportSaleExample() + { + SaleTransactionRequest onlineSaleTransactionRequest = new SaleTransactionRequest + { + DeviceIdentifier = ExampleData.DeviceIdentifier, + EstateId = ExampleData.EstateId, + MerchantId = ExampleData.MerchantId, + TransactionDateTime = ExampleData.TransactionDateTime, + TransactionNumber = ExampleData.TransactionNumber, + TransactionType = ExampleData.TransactionTypeSale, + AdditionalTransactionMetadata = new Dictionary(), + ContractId = ExampleData.ContractId, + CustomerEmailAddress = ExampleData.CustomerEmailAddress, + OperatorIdentifier = ExampleData.OperatorIdentifier, + ProductId = ExampleData.ProductId, + TransactionSource = ExampleData.FileBasedSaleTransactionSource + }; + + return new SwaggerExample + { + Name = "File Import Sale Request", + Value = new SerialisedMessage + { + Metadata = new Dictionary + { + {ExampleData.EstateIdMetadataName, ExampleData.EstateId.ToString()}, + {ExampleData.MerchantIdMetadataName, ExampleData.MerchantId.ToString()} + }, + SerialisedData = JsonConvert.SerializeObject(onlineSaleTransactionRequest, Formatting.Indented) + } + }; + } + #endregion } } \ No newline at end of file diff --git a/TransactionProcessor/Controllers/DeveloperController.cs b/TransactionProcessor/Controllers/DeveloperController.cs new file mode 100644 index 00000000..c27330f3 --- /dev/null +++ b/TransactionProcessor/Controllers/DeveloperController.cs @@ -0,0 +1,43 @@ +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; + +namespace TransactionProcessor.Controllers +{ + using System; + using System.Threading; + using System.Threading.Tasks; + using Models; + using Shared.DomainDrivenDesign.EventSourcing; + using Shared.EventStore.Aggregate; + using TransactionAggregate; + + [Route("api/[controller]")] + [ApiController] + public class DeveloperController : ControllerBase + { + private readonly IAggregateRepository TransactionAggregateRepository; + + public DeveloperController(IAggregateRepository transactionAggregateRepository) { + this.TransactionAggregateRepository = transactionAggregateRepository; + } + + [HttpPost] + public async Task AddTransactionSourceToTransaction([FromQuery]Guid estateId, + [FromQuery] Guid merchantId, + [FromQuery] Guid transactionId, + [FromQuery] Int32 transactionSource, + CancellationToken cancellationToken) { + var aggregate = await this.TransactionAggregateRepository.GetLatestVersion(transactionId, cancellationToken); + + if (aggregate.IsCompleted && aggregate.EstateId == estateId && aggregate.MerchantId == merchantId) { + aggregate.AddTransactionSource((TransactionSource)transactionSource); + + await this.TransactionAggregateRepository.SaveChanges(aggregate, cancellationToken); + + return this.Ok(); + } + + return this.BadRequest(); + } + } +} diff --git a/TransactionProcessor/Controllers/TransactionController.cs b/TransactionProcessor/Controllers/TransactionController.cs index 9f17a5b2..8acdce20 100644 --- a/TransactionProcessor/Controllers/TransactionController.cs +++ b/TransactionProcessor/Controllers/TransactionController.cs @@ -133,7 +133,7 @@ private async Task ProcessSpecificMessage(SaleTransactionRequ CancellationToken cancellationToken) { Guid transactionId = Guid.NewGuid(); - + ProcessSaleTransactionRequest request = ProcessSaleTransactionRequest.Create(transactionId, saleTransactionRequest.EstateId, saleTransactionRequest.MerchantId, @@ -145,7 +145,9 @@ private async Task ProcessSpecificMessage(SaleTransactionRequ saleTransactionRequest.CustomerEmailAddress, saleTransactionRequest.AdditionalTransactionMetadata, saleTransactionRequest.ContractId, - saleTransactionRequest.ProductId); + saleTransactionRequest.ProductId, + // Default to an online sale + saleTransactionRequest.TransactionSource.GetValueOrDefault(1)); ProcessSaleTransactionResponse response = await this.Mediator.Send(request, cancellationToken);