diff --git a/TransactionProcessor.BusinessLogic.Tests/OperatorInterfaces/SafaricomPinlessProxyTests.cs b/TransactionProcessor.BusinessLogic.Tests/OperatorInterfaces/SafaricomPinlessProxyTests.cs index 4ecdec39..d0bcefe3 100644 --- a/TransactionProcessor.BusinessLogic.Tests/OperatorInterfaces/SafaricomPinlessProxyTests.cs +++ b/TransactionProcessor.BusinessLogic.Tests/OperatorInterfaces/SafaricomPinlessProxyTests.cs @@ -35,6 +35,7 @@ public async Task SafaricomPinlessProxy_ProcessSaleMessage_TopupSuccessful_SaleM OperatorResponse operatorResponse = await safaricomPinlessproxy.ProcessSaleMessage(TestData.TransactionId, TestData.Merchant, TestData.TransactionDateTime, + TestData.TransactionReference, TestData.AdditionalTransactionMetaData, CancellationToken.None); @@ -61,6 +62,7 @@ public async Task SafaricomPinlessProxy_ProcessSaleMessage_TopupFailed_SaleMessa OperatorResponse operatorResponse = await safaricomPinlessproxy.ProcessSaleMessage(TestData.TransactionId, TestData.Merchant, TestData.TransactionDateTime, + TestData.TransactionReference, TestData.AdditionalTransactionMetaData, CancellationToken.None); @@ -88,11 +90,48 @@ public async Task SafaricomPinlessProxy_ProcessSaleMessage_FailedToSend_ErrorThr await safaricomPinlessproxy.ProcessSaleMessage(TestData.TransactionId, TestData.Merchant, TestData.TransactionDateTime, + TestData.TransactionReference, TestData.AdditionalTransactionMetaData, CancellationToken.None); }); } + [Theory] + [InlineData("", "123456789")] + [InlineData(null, "123456789")] + [InlineData("A", "123456789")] + [InlineData("1000.00", "")] + [InlineData("1000.00", null)] + public async Task SafaricomPinlessProxy_ProcessSaleMessage_InvalidData_ErrorThrown(String transactionAmount, String customerAccountNumber) + { + HttpResponseMessage responseMessage = new HttpResponseMessage + { + StatusCode = HttpStatusCode.OK, + Content = new StringContent(TestData.SuccessfulSafaricomTopup) + }; + + SafaricomConfiguration safaricomConfiguration = TestData.SafaricomConfiguration; + HttpClient httpClient = SetupMockHttpClient(responseMessage); + + IOperatorProxy safaricomPinlessproxy = new SafaricomPinlessProxy(safaricomConfiguration, httpClient); + + Dictionary additionalMetatdata = new Dictionary + { + {"Amount", transactionAmount}, + {"CustomerAccountNumber",customerAccountNumber } + }; + + Should.Throw(async () => + { + await safaricomPinlessproxy.ProcessSaleMessage(TestData.TransactionId, + TestData.Merchant, + TestData.TransactionDateTime, + TestData.TransactionReference, + additionalMetatdata, + CancellationToken.None); + }); + } + private HttpClient SetupMockHttpClient(HttpResponseMessage responseMessage) { Mock handlerMock = new Mock(MockBehavior.Strict); diff --git a/TransactionProcessor.BusinessLogic.Tests/Services/TransactionAggregateManagerTests.cs b/TransactionProcessor.BusinessLogic.Tests/Services/TransactionAggregateManagerTests.cs index 26ef8a89..455a8e5e 100644 --- a/TransactionProcessor.BusinessLogic.Tests/Services/TransactionAggregateManagerTests.cs +++ b/TransactionProcessor.BusinessLogic.Tests/Services/TransactionAggregateManagerTests.cs @@ -204,6 +204,7 @@ await transactionAggregateManager.StartTransaction(TestData.TransactionId, TestData.TransactionDateTime, TestData.TransactionNumber, transactionType, + TestData.TransactionReference, TestData.EstateId, TestData.MerchantId, TestData.DeviceIdentifier, diff --git a/TransactionProcessor.BusinessLogic.Tests/Services/TransactionDomainServiceTests.cs b/TransactionProcessor.BusinessLogic.Tests/Services/TransactionDomainServiceTests.cs index c1573b26..15488e12 100644 --- a/TransactionProcessor.BusinessLogic.Tests/Services/TransactionDomainServiceTests.cs +++ b/TransactionProcessor.BusinessLogic.Tests/Services/TransactionDomainServiceTests.cs @@ -268,6 +268,7 @@ public async Task TransactionDomainService_ProcessSaleTransaction_SuccesfulOpera operatorProxy.Setup(o => o.ProcessSaleMessage(It.IsAny(), It.IsAny(), It.IsAny(), + It.IsAny(), It.IsAny>(), It.IsAny())).ReturnsAsync(new OperatorResponse { @@ -319,6 +320,7 @@ public async Task TransactionDomainService_ProcessSaleTransaction_FailedOperator operatorProxy.Setup(o => o.ProcessSaleMessage(It.IsAny(), It.IsAny(), It.IsAny(), + It.IsAny(), It.IsAny>(), It.IsAny())).ReturnsAsync(new OperatorResponse { diff --git a/TransactionProcessor.BusinessLogic/OperatorInterfaces/IOperatorProxy.cs b/TransactionProcessor.BusinessLogic/OperatorInterfaces/IOperatorProxy.cs index 1c4d2476..39ed4abf 100644 --- a/TransactionProcessor.BusinessLogic/OperatorInterfaces/IOperatorProxy.cs +++ b/TransactionProcessor.BusinessLogic/OperatorInterfaces/IOperatorProxy.cs @@ -19,12 +19,14 @@ public interface IOperatorProxy /// The transaction identifier. /// The merchant. /// The transaction date time. + /// The transaction reference. /// The additional transaction metadata. /// The cancellation token. /// Task ProcessSaleMessage(Guid transactionId, MerchantResponse merchant, DateTime transactionDateTime, + String transactionReference, Dictionary additionalTransactionMetadata, CancellationToken cancellationToken); diff --git a/TransactionProcessor.BusinessLogic/OperatorInterfaces/SafaricomPinless/SafaricomPinlessProxy.cs b/TransactionProcessor.BusinessLogic/OperatorInterfaces/SafaricomPinless/SafaricomPinlessProxy.cs index 65164205..f99ca631 100644 --- a/TransactionProcessor.BusinessLogic/OperatorInterfaces/SafaricomPinless/SafaricomPinlessProxy.cs +++ b/TransactionProcessor.BusinessLogic/OperatorInterfaces/SafaricomPinless/SafaricomPinlessProxy.cs @@ -52,16 +52,39 @@ public SafaricomPinlessProxy(SafaricomConfiguration safaricomConfiguration, /// The transaction identifier. /// The merchant. /// The transaction date time. + /// The transaction reference. /// The additional transaction metadata. /// The cancellation token. /// + /// + /// Amount is a required field for this transaction type + /// or + /// CustomerAccountNumber is a required field for this transaction type + /// or + /// Error sending request [{requestUrl}] to Safaricom. Status Code [{responseMessage.StatusCode}] + /// public async Task ProcessSaleMessage(Guid transactionId, MerchantResponse merchant, DateTime transactionDateTime, + String transactionReference, Dictionary additionalTransactionMetadata, CancellationToken cancellationToken) { - String requestUrl = this.BuildRequest(transactionDateTime, "123456789", "123456789", "1000"); + // Extract the required fields + String transactionAmount = additionalTransactionMetadata.GetValueOrDefault("Amount"); + String customerMsisdn = additionalTransactionMetadata.GetValueOrDefault("CustomerAccountNumber"); + + if (String.IsNullOrEmpty(transactionAmount)) + { + throw new Exception("Amount is a required field for this transaction type"); + } + + if (String.IsNullOrEmpty(customerMsisdn)) + { + throw new Exception("CustomerAccountNumber is a required field for this transaction type"); + } + + String requestUrl = this.BuildRequest(transactionDateTime, transactionReference, customerMsisdn, transactionAmount); // Concatenate the request message HttpRequestMessage requestMessage = new HttpRequestMessage(HttpMethod.Get, new Uri(requestUrl)); @@ -98,6 +121,12 @@ private String BuildRequest(DateTime transactionDateTime, StringBuilder xmlData = new StringBuilder(); + // Covert the transaction amount to Decimal and remove decimal places + if (Decimal.TryParse(transactionAmount, out Decimal amountAsDecimal) == false) + { + throw new Exception("Transaction Amount is not a valid decimal value"); + } + // Now build up the XML part of the message xmlData.Append(""); xmlData.Append(""); @@ -111,7 +140,7 @@ private String BuildRequest(DateTime transactionDateTime, xmlData.Append($"{this.SafaricomConfiguration.ExtCode}"); xmlData.Append($"{externalReference}"); xmlData.Append($"{customerMsisdn}"); - xmlData.Append($"{transactionAmount}"); + xmlData.Append($"{amountAsDecimal:G0}"); xmlData.Append("0"); xmlData.Append("0"); xmlData.Append("0"); diff --git a/TransactionProcessor.BusinessLogic/Services/ITransactionAggregateManager.cs b/TransactionProcessor.BusinessLogic/Services/ITransactionAggregateManager.cs index 657a8a6e..aa9240b6 100644 --- a/TransactionProcessor.BusinessLogic/Services/ITransactionAggregateManager.cs +++ b/TransactionProcessor.BusinessLogic/Services/ITransactionAggregateManager.cs @@ -132,6 +132,7 @@ Task RecordAdditionalResponseData(Guid estateId, /// The transaction date time. /// The transaction number. /// Type of the transaction. + /// The transaction reference. /// The estate identifier. /// The merchant identifier. /// The device identifier. @@ -141,6 +142,7 @@ Task StartTransaction(Guid transactionId, DateTime transactionDateTime, String transactionNumber, TransactionType transactionType, + String transactionReference, Guid estateId, Guid merchantId, String deviceIdentifier, diff --git a/TransactionProcessor.BusinessLogic/Services/TransactionAggregateManager.cs b/TransactionProcessor.BusinessLogic/Services/TransactionAggregateManager.cs index 5c5d1f72..da6cc1a1 100644 --- a/TransactionProcessor.BusinessLogic/Services/TransactionAggregateManager.cs +++ b/TransactionProcessor.BusinessLogic/Services/TransactionAggregateManager.cs @@ -244,6 +244,7 @@ public async Task RecordAdditionalResponseData(Guid estateId, /// The transaction date time. /// The transaction number. /// Type of the transaction. + /// The transaction reference. /// The estate identifier. /// The merchant identifier. /// The device identifier. @@ -252,6 +253,7 @@ public async Task StartTransaction(Guid transactionId, DateTime transactionDateTime, String transactionNumber, TransactionType transactionType, + String transactionReference, Guid estateId, Guid merchantId, String deviceIdentifier, @@ -262,7 +264,7 @@ public async Task StartTransaction(Guid transactionId, TransactionAggregate transactionAggregate = await transactionAggregateRepository.GetLatestVersion(transactionId, cancellationToken); - transactionAggregate.StartTransaction(transactionDateTime, transactionNumber, transactionType, estateId, merchantId, deviceIdentifier); + transactionAggregate.StartTransaction(transactionDateTime, transactionNumber, transactionType, transactionReference, estateId, merchantId, deviceIdentifier); await transactionAggregateRepository.SaveChanges(transactionAggregate, cancellationToken); } diff --git a/TransactionProcessor.BusinessLogic/Services/TransactionDomainService.cs b/TransactionProcessor.BusinessLogic/Services/TransactionDomainService.cs index b2c36a73..124bffb1 100644 --- a/TransactionProcessor.BusinessLogic/Services/TransactionDomainService.cs +++ b/TransactionProcessor.BusinessLogic/Services/TransactionDomainService.cs @@ -91,10 +91,14 @@ public async Task ProcessLogonTransaction(Guid { TransactionType transactionType = TransactionType.Logon; + // Generate a transaction reference + String transactionReference = this.GenerateTransactionReference(); + await this.TransactionAggregateManager.StartTransaction(transactionId, transactionDateTime, transactionNumber, transactionType, + transactionReference, estateId, merchantId, deviceIdentifier, @@ -127,6 +131,20 @@ await this.TransactionAggregateManager.StartTransaction(transactionId, }; } + /// + /// Generates the transaction reference. + /// + /// + private String GenerateTransactionReference() + { + Int64 i = 1; + foreach (Byte b in Guid.NewGuid().ToByteArray()) + { + i *= ((Int32)b + 1); + } + return $"{i - DateTime.Now.Ticks:x}"; + } + /// /// Processes the sale transaction. /// @@ -152,10 +170,14 @@ public async Task ProcessSaleTransaction(Guid tr { TransactionType transactionType = TransactionType.Sale; + // Generate a transaction reference + String transactionReference = this.GenerateTransactionReference(); + await this.TransactionAggregateManager.StartTransaction(transactionId, transactionDateTime, transactionNumber, transactionType, + transactionReference, estateId, merchantId, deviceIdentifier, @@ -171,7 +193,7 @@ await this.TransactionAggregateManager.StartTransaction(transactionId, // Do the online processing with the operator here MerchantResponse merchant = await this.GetMerchant(estateId, merchantId, cancellationToken); IOperatorProxy operatorProxy = OperatorProxyResolver(operatorIdentifier); - OperatorResponse operatorResponse = await operatorProxy.ProcessSaleMessage(transactionId, merchant, transactionDateTime, additionalTransactionMetadata, cancellationToken); + OperatorResponse operatorResponse = await operatorProxy.ProcessSaleMessage(transactionId, merchant, transactionDateTime, transactionReference, additionalTransactionMetadata, cancellationToken); if (operatorResponse.IsSuccessful) { diff --git a/TransactionProcessor.IntegrationTests/SaleTransaction/SaleTransactionFeature.feature b/TransactionProcessor.IntegrationTests/SaleTransaction/SaleTransactionFeature.feature index 0830cf70..acb94deb 100644 --- a/TransactionProcessor.IntegrationTests/SaleTransaction/SaleTransactionFeature.feature +++ b/TransactionProcessor.IntegrationTests/SaleTransaction/SaleTransactionFeature.feature @@ -48,10 +48,10 @@ Background: Scenario: Sale Transactions When I perform the following transactions - | DateTime | TransactionNumber | TransactionType | MerchantName | DeviceIdentifier | EstateName | OperatorName | TransactionAmount | - | Today | 1 | Sale | Test Merchant 1 | 123456780 | Test Estate 1 | Safaricom | 100.00 | - | Today | 2 | Sale | Test Merchant 2 | 123456781 | Test Estate 1 | Safaricom | 100.00 | - | Today | 3 | Sale | Test Merchant 3 | 123456782 | Test Estate 2 | Safaricom | 100.00 | + | DateTime | TransactionNumber | TransactionType | MerchantName | DeviceIdentifier | EstateName | OperatorName | TransactionAmount | CustomerAccountNumber | + | Today | 1 | Sale | Test Merchant 1 | 123456780 | Test Estate 1 | Safaricom | 1000.00 | 123456789 | + | Today | 2 | Sale | Test Merchant 2 | 123456781 | Test Estate 1 | Safaricom | 1000.00 |123456789 | + | Today | 3 | Sale | Test Merchant 3 | 123456782 | Test Estate 2 | Safaricom | 1000.00 |123456789 | Then transaction response should contain the following information | EstateName | MerchantName | TransactionNumber | ResponseCode | ResponseMessage | @@ -64,7 +64,7 @@ Scenario: Sale Transaction with Invalid Device When I perform the following transactions | DateTime | TransactionNumber | TransactionType | MerchantName | DeviceIdentifier | EstateName | OperatorName | TransactionAmount | - | Today | 1 | Sale | Test Merchant 1 | 123456781 | Test Estate 1 | Safaricom | 100.00 | + | Today | 1 | Sale | Test Merchant 1 | 123456781 | Test Estate 1 | Safaricom | 1000.00 | Then transaction response should contain the following information | EstateName | MerchantName | TransactionNumber | ResponseCode | ResponseMessage | @@ -74,7 +74,7 @@ Scenario: Sale Transaction with Invalid Estate When I perform the following transactions | DateTime | TransactionNumber | TransactionType | MerchantName | DeviceIdentifier | EstateName |OperatorName |TransactionAmount | - | Today | 1 | Sale | Test Merchant 1 | 123456780 | InvalidEstate |Safaricom | 100.00 | + | Today | 1 | Sale | Test Merchant 1 | 123456780 | InvalidEstate |Safaricom | 1000.00 | Then transaction response should contain the following information | EstateName | MerchantName | TransactionNumber | ResponseCode | ResponseMessage | @@ -84,7 +84,7 @@ Scenario: Sale Transaction with Invalid Merchant When I perform the following transactions | DateTime | TransactionNumber | TransactionType | MerchantName | DeviceIdentifier | EstateName |OperatorName |TransactionAmount | - | Today | 1 | Sale | InvalidMerchant | 123456780 | Test Estate 1 |Safaricom | 100.00 | + | Today | 1 | Sale | InvalidMerchant | 123456780 | Test Estate 1 |Safaricom | 1000.00 | Then transaction response should contain the following information | EstateName | MerchantName | TransactionNumber | ResponseCode | ResponseMessage | diff --git a/TransactionProcessor.IntegrationTests/SaleTransaction/SaleTransactionFeature.feature.cs b/TransactionProcessor.IntegrationTests/SaleTransaction/SaleTransactionFeature.feature.cs index 10814203..ca401de0 100644 --- a/TransactionProcessor.IntegrationTests/SaleTransaction/SaleTransactionFeature.feature.cs +++ b/TransactionProcessor.IntegrationTests/SaleTransaction/SaleTransactionFeature.feature.cs @@ -289,7 +289,8 @@ public virtual void SaleTransactions() "DeviceIdentifier", "EstateName", "OperatorName", - "TransactionAmount"}); + "TransactionAmount", + "CustomerAccountNumber"}); table30.AddRow(new string[] { "Today", "1", @@ -298,7 +299,8 @@ public virtual void SaleTransactions() "123456780", "Test Estate 1", "Safaricom", - "100.00"}); + "1000.00", + "123456789"}); table30.AddRow(new string[] { "Today", "2", @@ -307,7 +309,8 @@ public virtual void SaleTransactions() "123456781", "Test Estate 1", "Safaricom", - "100.00"}); + "1000.00", + "123456789"}); table30.AddRow(new string[] { "Today", "3", @@ -316,7 +319,8 @@ public virtual void SaleTransactions() "123456782", "Test Estate 2", "Safaricom", - "100.00"}); + "1000.00", + "123456789"}); #line 50 testRunner.When("I perform the following transactions", ((string)(null)), table30, "When "); #line hidden @@ -401,7 +405,7 @@ public virtual void SaleTransactionWithInvalidDevice() "123456781", "Test Estate 1", "Safaricom", - "100.00"}); + "1000.00"}); #line 65 testRunner.When("I perform the following transactions", ((string)(null)), table32, "When "); #line hidden @@ -471,7 +475,7 @@ public virtual void SaleTransactionWithInvalidEstate() "123456780", "InvalidEstate", "Safaricom", - "100.00"}); + "1000.00"}); #line 75 testRunner.When("I perform the following transactions", ((string)(null)), table34, "When "); #line hidden @@ -541,7 +545,7 @@ public virtual void SaleTransactionWithInvalidMerchant() "123456780", "Test Estate 1", "Safaricom", - "100.00"}); + "1000.00"}); #line 85 testRunner.When("I perform the following transactions", ((string)(null)), table36, "When "); #line hidden diff --git a/TransactionProcessor.IntegrationTests/Shared/SharedSteps.cs b/TransactionProcessor.IntegrationTests/Shared/SharedSteps.cs index d79aca20..a3d568da 100644 --- a/TransactionProcessor.IntegrationTests/Shared/SharedSteps.cs +++ b/TransactionProcessor.IntegrationTests/Shared/SharedSteps.cs @@ -250,6 +250,7 @@ public async Task WhenIPerformTheFollowingTransactions(Table table) // Get specific sale fields String operatorName = SpecflowTableHelper.GetStringRowValue(tableRow, "OperatorName"); Decimal transactionAmount = SpecflowTableHelper.GetDecimalValue(tableRow, "TransactionAmount"); + String customerAccountNumber = SpecflowTableHelper.GetStringRowValue(tableRow, "CustomerAccountNumber"); transactionResponse = await this.PerformSaleTransaction(estateDetails.EstateId, merchantId, @@ -259,6 +260,7 @@ public async Task WhenIPerformTheFollowingTransactions(Table table) deviceIdentifier, operatorName, transactionAmount, + customerAccountNumber, CancellationToken.None); break; @@ -307,22 +309,23 @@ await this.TestingContext.DockerHelper.TransactionProcessorClient.PerformTransac return responseSerialisedMessage; } - private async Task PerformSaleTransaction(Guid estateId, Guid merchantId, DateTime transactionDateTime, String transactionType, String transactionNumber, String deviceIdentifier, String operatorIdentifier, Decimal transactionAmount, CancellationToken cancellationToken) + private async Task PerformSaleTransaction(Guid estateId, Guid merchantId, DateTime transactionDateTime, String transactionType, String transactionNumber, String deviceIdentifier, String operatorIdentifier, Decimal transactionAmount, String customerAccountNumber, CancellationToken cancellationToken) { SaleTransactionRequest saleTransactionRequest = new SaleTransactionRequest - { - MerchantId = merchantId, - EstateId = estateId, - TransactionDateTime = transactionDateTime, - TransactionNumber = transactionNumber, - DeviceIdentifier = deviceIdentifier, - TransactionType = transactionType, - OperatorIdentifier = operatorIdentifier, - AdditionalTransactionMetadata = new Dictionary - { - { "Amount", transactionAmount.ToString() } - } - }; + { + MerchantId = merchantId, + EstateId = estateId, + TransactionDateTime = transactionDateTime, + TransactionNumber = transactionNumber, + DeviceIdentifier = deviceIdentifier, + TransactionType = transactionType, + OperatorIdentifier = operatorIdentifier, + AdditionalTransactionMetadata = new Dictionary + { + {"Amount", transactionAmount.ToString()}, + {"CustomerAccountNumber", customerAccountNumber} + } + }; SerialisedMessage serialisedMessage = new SerialisedMessage(); serialisedMessage.Metadata.Add(MetadataContants.KeyNameEstateId, estateId.ToString()); diff --git a/TransactionProcessor.Testing/TestData.cs b/TransactionProcessor.Testing/TestData.cs index 12568f3c..a7a1b12d 100644 --- a/TransactionProcessor.Testing/TestData.cs +++ b/TransactionProcessor.Testing/TestData.cs @@ -63,6 +63,8 @@ public class TestData public static TransactionType TransactionTypeLogon = TransactionType.Logon; + public static String TransactionReference = "ABCDEFGHI"; + public static TransactionType TransactionTypeSale = TransactionType.Sale; private static readonly String MerchantName = "Test Merchant Name"; @@ -127,7 +129,8 @@ public class TestData public static Dictionary AdditionalTransactionMetaData => new Dictionary { - {"Amount", "100.00"} + {"Amount", "100.00"}, + {"CustomerAccountNumber", "123456789" } }; public static IReadOnlyDictionary DefaultAppSettings => @@ -377,6 +380,7 @@ public static TransactionAggregate GetCompletedTransactionAggregate() transactionAggregate.StartTransaction(TestData.TransactionDateTime, TestData.TransactionNumber, TestData.TransactionTypeLogon, + TestData.TransactionReference, TestData.EstateId, TestData.MerchantId, TestData.DeviceIdentifier); @@ -400,6 +404,7 @@ public static TransactionAggregate GetLocallyAuthorisedTransactionAggregate() transactionAggregate.StartTransaction(TestData.TransactionDateTime, TestData.TransactionNumber, TestData.TransactionTypeLogon, + TestData.TransactionReference, TestData.EstateId, TestData.MerchantId, TestData.DeviceIdentifier); @@ -416,6 +421,7 @@ public static TransactionAggregate GetLocallyDeclinedTransactionAggregate(Transa transactionAggregate.StartTransaction(TestData.TransactionDateTime, TestData.TransactionNumber, TestData.TransactionTypeLogon, + TestData.TransactionReference, TestData.EstateId, TestData.MerchantId, TestData.DeviceIdentifier); @@ -433,6 +439,7 @@ public static TransactionAggregate GetDeclinedTransactionAggregate(TransactionRe transactionAggregate.StartTransaction(TestData.TransactionDateTime, TestData.TransactionNumber, TestData.TransactionTypeLogon, + TestData.TransactionReference, TestData.EstateId, TestData.MerchantId, TestData.DeviceIdentifier); @@ -462,6 +469,7 @@ public static TransactionAggregate GetStartedTransactionAggregate() transactionAggregate.StartTransaction(TestData.TransactionDateTime, TestData.TransactionNumber, TestData.TransactionTypeLogon, + TestData.TransactionReference, TestData.EstateId, TestData.MerchantId, TestData.DeviceIdentifier); diff --git a/TransactionProcessor.Transaction.DomainEvents/TransactionHasStartedEvent.cs b/TransactionProcessor.Transaction.DomainEvents/TransactionHasStartedEvent.cs index 7ccda29d..4bbd77fd 100644 --- a/TransactionProcessor.Transaction.DomainEvents/TransactionHasStartedEvent.cs +++ b/TransactionProcessor.Transaction.DomainEvents/TransactionHasStartedEvent.cs @@ -40,6 +40,7 @@ public TransactionHasStartedEvent(Guid aggregateId, DateTime transactionDateTime, String transactionNumber, String transactionType, + String transactionReference, String deviceIdentifier) : base(aggregateId, eventId) { this.TransactionId = aggregateId; @@ -48,6 +49,7 @@ public TransactionHasStartedEvent(Guid aggregateId, this.TransactionDateTime = transactionDateTime; this.TransactionNumber = transactionNumber; this.TransactionType = transactionType; + this.TransactionReference = transactionReference; this.DeviceIdentifier = deviceIdentifier; } @@ -118,6 +120,9 @@ public TransactionHasStartedEvent(Guid aggregateId, [JsonProperty] public String TransactionType { get; private set; } + [JsonProperty] + public String TransactionReference { get; private set; } + #endregion #region Methods @@ -131,6 +136,7 @@ public TransactionHasStartedEvent(Guid aggregateId, /// The transaction date time. /// The transaction number. /// Type of the transaction. + /// The transaction reference. /// The device identifier. /// public static TransactionHasStartedEvent Create(Guid aggregateId, @@ -139,9 +145,10 @@ public static TransactionHasStartedEvent Create(Guid aggregateId, DateTime transactionDateTime, String transactionNumber, String transactionType, + String transactionReference, String deviceIdentifier) { - return new TransactionHasStartedEvent(aggregateId, Guid.NewGuid(), estateId, merchantId, transactionDateTime, transactionNumber, transactionType, deviceIdentifier); + return new TransactionHasStartedEvent(aggregateId, Guid.NewGuid(), estateId, merchantId, transactionDateTime, transactionNumber, transactionType, transactionReference, deviceIdentifier); } #endregion diff --git a/TransactionProcessor.TransactionAggregate.Tests/DomainEventTests.cs b/TransactionProcessor.TransactionAggregate.Tests/DomainEventTests.cs index 21b2a242..32159455 100644 --- a/TransactionProcessor.TransactionAggregate.Tests/DomainEventTests.cs +++ b/TransactionProcessor.TransactionAggregate.Tests/DomainEventTests.cs @@ -23,6 +23,7 @@ public void TransactionHasStartedEvent_CanBeCreated_IsCreated(TransactionType tr TestData.TransactionDateTime, TestData.TransactionNumber, transactionType.ToString(), + TestData.TransactionReference, TestData.DeviceIdentifier); transactionHasStartedEvent.ShouldNotBeNull(); transactionHasStartedEvent.AggregateId.ShouldBe(TestData.TransactionId); @@ -35,6 +36,7 @@ public void TransactionHasStartedEvent_CanBeCreated_IsCreated(TransactionType tr transactionHasStartedEvent.TransactionDateTime.ShouldBe(TestData.TransactionDateTime); transactionHasStartedEvent.TransactionNumber.ShouldBe(TestData.TransactionNumber); transactionHasStartedEvent.TransactionType.ShouldBe(transactionType.ToString()); + transactionHasStartedEvent.TransactionReference.ShouldBe(TestData.TransactionReference); } [Fact] diff --git a/TransactionProcessor.TransactionAggregate.Tests/TransactionAggregateTests.cs b/TransactionProcessor.TransactionAggregate.Tests/TransactionAggregateTests.cs index 646a4c90..3743bf54 100644 --- a/TransactionProcessor.TransactionAggregate.Tests/TransactionAggregateTests.cs +++ b/TransactionProcessor.TransactionAggregate.Tests/TransactionAggregateTests.cs @@ -23,7 +23,8 @@ public void TransactionAggregate_CanBeCreated_IsCreated() public void TransactionAggregate_StartTransaction_TransactionIsStarted(TransactionType transactionType) { TransactionAggregate transactionAggregate = TransactionAggregate.Create(TestData.TransactionId); - transactionAggregate.StartTransaction(TestData.TransactionDateTime, TestData.TransactionNumber, transactionType, TestData.EstateId, TestData.MerchantId, TestData.DeviceIdentifier); + transactionAggregate.StartTransaction(TestData.TransactionDateTime, TestData.TransactionNumber, transactionType, + TestData.TransactionReference, TestData.EstateId, TestData.MerchantId, TestData.DeviceIdentifier); transactionAggregate.IsStarted.ShouldBeTrue(); transactionAggregate.TransactionDateTime.ShouldBe(TestData.TransactionDateTime); @@ -32,6 +33,7 @@ public void TransactionAggregate_StartTransaction_TransactionIsStarted(Transacti transactionAggregate.EstateId.ShouldBe(TestData.EstateId); transactionAggregate.MerchantId.ShouldBe(TestData.MerchantId); transactionAggregate.DeviceIdentifier.ShouldBe(TestData.DeviceIdentifier); + transactionAggregate.TransactionReference.ShouldBe(TestData.TransactionReference); } [Theory] @@ -40,13 +42,14 @@ public void TransactionAggregate_StartTransaction_TransactionIsStarted(Transacti public void TransactionAggregate_StartTransaction_TransactionAlreadyStarted_ErrorThrown(TransactionType transactionType) { TransactionAggregate transactionAggregate = TransactionAggregate.Create(TestData.TransactionId); - transactionAggregate.StartTransaction(TestData.TransactionDateTime, TestData.TransactionNumber, transactionType, TestData.EstateId, TestData.MerchantId, TestData.DeviceIdentifier); + transactionAggregate.StartTransaction(TestData.TransactionDateTime, TestData.TransactionNumber, transactionType, TestData.TransactionReference, TestData.EstateId, TestData.MerchantId, TestData.DeviceIdentifier); Should.Throw(() => { transactionAggregate.StartTransaction(TestData.TransactionDateTime, TestData.TransactionNumber, transactionType, + TestData.TransactionReference, TestData.EstateId, TestData.MerchantId, TestData.DeviceIdentifier); @@ -59,7 +62,7 @@ public void TransactionAggregate_StartTransaction_TransactionAlreadyStarted_Erro public void TransactionAggregate_StartTransaction_TransactionAlreadyCompleted_ErrorThrown(TransactionType transactionType) { TransactionAggregate transactionAggregate = TransactionAggregate.Create(TestData.TransactionId); - transactionAggregate.StartTransaction(TestData.TransactionDateTime, TestData.TransactionNumber, transactionType, TestData.EstateId, TestData.MerchantId, TestData.DeviceIdentifier); + transactionAggregate.StartTransaction(TestData.TransactionDateTime, TestData.TransactionNumber, transactionType, TestData.TransactionReference, TestData.EstateId, TestData.MerchantId, TestData.DeviceIdentifier); if (transactionType == TransactionType.Logon) { @@ -82,6 +85,7 @@ public void TransactionAggregate_StartTransaction_TransactionAlreadyCompleted_Er transactionAggregate.StartTransaction(TestData.TransactionDateTime, TestData.TransactionNumber, transactionType, + TestData.TransactionReference, TestData.EstateId, TestData.MerchantId, TestData.DeviceIdentifier); @@ -89,26 +93,30 @@ public void TransactionAggregate_StartTransaction_TransactionAlreadyCompleted_Er } [Theory] - [InlineData(false, "0001", TransactionType.Logon, true, true, "A1234567890" )] - [InlineData(true, "", TransactionType.Logon, true, true, "A1234567890")] - [InlineData(true, null, TransactionType.Logon, true, true, "A1234567890")] - [InlineData(true, "ABCD", TransactionType.Logon, true, true, "A1234567890")] - [InlineData(true, "0001", TransactionType.Logon, false, true, "A1234567890")] - [InlineData(true, "0001", TransactionType.Logon, true, false, "A1234567890")] - [InlineData(true, "0001", TransactionType.Logon, true, true, "")] - [InlineData(true, "0001", TransactionType.Logon, true, true, null)] - [InlineData(true, "0001", TransactionType.Logon, true, true, "A!234567890")] - [InlineData(true, "0001", (TransactionType)99, true, true, "A1234567890")] - [InlineData(false, "0001", TransactionType.Sale, true, true, "A1234567890")] - [InlineData(true, "", TransactionType.Sale, true, true, "A1234567890")] - [InlineData(true, null, TransactionType.Sale, true, true, "A1234567890")] - [InlineData(true, "ABCD", TransactionType.Sale, true, true, "A1234567890")] - [InlineData(true, "0001", TransactionType.Sale, false, true, "A1234567890")] - [InlineData(true, "0001", TransactionType.Sale, true, false, "A1234567890")] - [InlineData(true, "0001", TransactionType.Sale, true, true, "")] - [InlineData(true, "0001", TransactionType.Sale, true, true, null)] - [InlineData(true, "0001", TransactionType.Sale, true, true, "A!234567890")] - public void TransactionAggregate_StartTransaction_InvalidData_ErrorThrown(Boolean validTransactionDateTime, String transactionNumber, TransactionType transactionType, Boolean validEstateId, Boolean validMerchantId, String deviceIdentifier) + [InlineData(false, "0001", TransactionType.Logon,"ABCDEFG", true, true, "A1234567890" )] + [InlineData(true, "", TransactionType.Logon, "ABCDEFG", true, true, "A1234567890")] + [InlineData(true, null, TransactionType.Logon, "ABCDEFG", true, true, "A1234567890")] + [InlineData(true, "ABCD", TransactionType.Logon, "ABCDEFG", true, true, "A1234567890")] + [InlineData(true, "0001", TransactionType.Logon, "ABCDEFG", false, true, "A1234567890")] + [InlineData(true, "0001", TransactionType.Logon, "ABCDEFG", true, false, "A1234567890")] + [InlineData(true, "0001", TransactionType.Logon, "ABCDEFG", true, true, "")] + [InlineData(true, "0001", TransactionType.Logon, "ABCDEFG", true, true, null)] + [InlineData(true, "0001", TransactionType.Logon, "ABCDEFG", true, true, "A!234567890")] + [InlineData(true, "0001", (TransactionType)99, "ABCDEFG", true, true, "A1234567890")] + [InlineData(true, "0001", TransactionType.Logon, "", true, true, "A1234567890")] + [InlineData(true, "0001", TransactionType.Logon, null, true, true, "A1234567890")] + [InlineData(false, "0001", TransactionType.Sale, "ABCDEFG", true, true, "A1234567890")] + [InlineData(true, "", TransactionType.Sale, "ABCDEFG", true, true, "A1234567890")] + [InlineData(true, null, TransactionType.Sale, "ABCDEFG", true, true, "A1234567890")] + [InlineData(true, "ABCD", TransactionType.Sale, "ABCDEFG", true, true, "A1234567890")] + [InlineData(true, "0001", TransactionType.Sale, "ABCDEFG", false, true, "A1234567890")] + [InlineData(true, "0001", TransactionType.Sale, "ABCDEFG", true, false, "A1234567890")] + [InlineData(true, "0001", TransactionType.Sale, "ABCDEFG", true, true, "")] + [InlineData(true, "0001", TransactionType.Sale, "ABCDEFG", true, true, null)] + [InlineData(true, "0001", TransactionType.Sale, "ABCDEFG", true, true, "A!234567890")] + [InlineData(true, "0001", TransactionType.Sale, "", true, true, "A1234567890")] + [InlineData(true, "0001", TransactionType.Sale, null, true, true, "A1234567890")] + public void TransactionAggregate_StartTransaction_InvalidData_ErrorThrown(Boolean validTransactionDateTime, String transactionNumber, TransactionType transactionType, String transactionReference, Boolean validEstateId, Boolean validMerchantId, String deviceIdentifier) { DateTime transactionDateTime = validTransactionDateTime ? TestData.TransactionDateTime : DateTime.MinValue; Guid estateId = validEstateId ? TestData.EstateId : Guid.Empty; @@ -121,6 +129,7 @@ public void TransactionAggregate_StartTransaction_InvalidData_ErrorThrown(Boolea transactionAggregate.StartTransaction(transactionDateTime, transactionNumber, transactionType, + transactionReference, estateId, merchantId, deviceIdentifier); @@ -132,7 +141,7 @@ public void TransactionAggregate_StartTransaction_InvalidData_ErrorThrown(Boolea public void TransactionAggregate_AuthoriseTransactionLocally_TransactionIsAuthorised(TransactionType transactionType) { TransactionAggregate transactionAggregate = TransactionAggregate.Create(TestData.TransactionId); - transactionAggregate.StartTransaction(TestData.TransactionDateTime, TestData.TransactionNumber, transactionType, TestData.EstateId, TestData.MerchantId, TestData.DeviceIdentifier); + transactionAggregate.StartTransaction(TestData.TransactionDateTime, TestData.TransactionNumber, transactionType, TestData.TransactionReference, TestData.EstateId, TestData.MerchantId, TestData.DeviceIdentifier); transactionAggregate.AuthoriseTransactionLocally(TestData.AuthorisationCode, TestData.ResponseCode, TestData.ResponseMessage); @@ -161,7 +170,7 @@ public void TransactionAggregate_AuthoriseTransactionLocally_TransactionNotStart public void TransactionAggregate_AuthoriseTransactionLocally_TransactionAlreadyAuthorisedLocally_ErrorThrown(TransactionType transactionType) { TransactionAggregate transactionAggregate = TransactionAggregate.Create(TestData.TransactionId); - transactionAggregate.StartTransaction(TestData.TransactionDateTime, TestData.TransactionNumber, transactionType, TestData.EstateId, TestData.MerchantId, TestData.DeviceIdentifier); + transactionAggregate.StartTransaction(TestData.TransactionDateTime, TestData.TransactionNumber, transactionType, TestData.TransactionReference, TestData.EstateId, TestData.MerchantId, TestData.DeviceIdentifier); transactionAggregate.AuthoriseTransactionLocally(TestData.AuthorisationCode, TestData.ResponseCode, TestData.ResponseMessage); Should.Throw(() => @@ -177,7 +186,7 @@ public void TransactionAggregate_AuthoriseTransactionLocally_TransactionAlreadyA public void TransactionAggregate_AuthoriseTransactionLocally_TransactionAlreadyAuthorised_ErrorThrown(TransactionType transactionType) { TransactionAggregate transactionAggregate = TransactionAggregate.Create(TestData.TransactionId); - transactionAggregate.StartTransaction(TestData.TransactionDateTime, TestData.TransactionNumber, transactionType, TestData.EstateId, TestData.MerchantId, TestData.DeviceIdentifier); + transactionAggregate.StartTransaction(TestData.TransactionDateTime, TestData.TransactionNumber, transactionType, TestData.TransactionReference, TestData.EstateId, TestData.MerchantId, TestData.DeviceIdentifier); transactionAggregate.AuthoriseTransaction(TestData.OperatorAuthorisationCode, TestData.OperatorResponseCode, TestData.OperatorResponseMessage, TestData.OperatorTransactionId, TestData.ResponseCode, TestData.ResponseMessage); Should.Throw(() => @@ -193,7 +202,7 @@ public void TransactionAggregate_AuthoriseTransactionLocally_TransactionAlreadyA public void TransactionAggregate_AuthoriseTransactionLocally_TransactionCannotBeLocallyyAuthorised_ErrorThrown(TransactionType transactionType) { TransactionAggregate transactionAggregate = TransactionAggregate.Create(TestData.TransactionId); - transactionAggregate.StartTransaction(TestData.TransactionDateTime, TestData.TransactionNumber, transactionType, TestData.EstateId, TestData.MerchantId, TestData.DeviceIdentifier); + transactionAggregate.StartTransaction(TestData.TransactionDateTime, TestData.TransactionNumber, transactionType, TestData.TransactionReference, TestData.EstateId, TestData.MerchantId, TestData.DeviceIdentifier); Should.Throw(() => { @@ -210,7 +219,7 @@ public void TransactionAggregate_AuthoriseTransactionLocally_TransactionCannotBe public void TransactionAggregate_AuthoriseTransaction_TransactionIsAuthorised(TransactionType transactionType) { TransactionAggregate transactionAggregate = TransactionAggregate.Create(TestData.TransactionId); - transactionAggregate.StartTransaction(TestData.TransactionDateTime, TestData.TransactionNumber, transactionType, TestData.EstateId, TestData.MerchantId, TestData.DeviceIdentifier); + transactionAggregate.StartTransaction(TestData.TransactionDateTime, TestData.TransactionNumber, transactionType, TestData.TransactionReference, TestData.EstateId, TestData.MerchantId, TestData.DeviceIdentifier); transactionAggregate.AuthoriseTransaction(TestData.OperatorAuthorisationCode, TestData.OperatorResponseCode, TestData.OperatorResponseMessage, TestData.OperatorTransactionId, TestData.ResponseCode, TestData.ResponseMessage); @@ -239,7 +248,7 @@ public void TransactionAggregate_AuthoriseTransaction_TransactionNotStarted_Erro public void TransactionAggregate_AuthoriseTransaction_TransactionAlreadyAuthorised_ErrorThrown(TransactionType transactionType) { TransactionAggregate transactionAggregate = TransactionAggregate.Create(TestData.TransactionId); - transactionAggregate.StartTransaction(TestData.TransactionDateTime, TestData.TransactionNumber, transactionType, TestData.EstateId, TestData.MerchantId, TestData.DeviceIdentifier); + transactionAggregate.StartTransaction(TestData.TransactionDateTime, TestData.TransactionNumber, transactionType, TestData.TransactionReference, TestData.EstateId, TestData.MerchantId, TestData.DeviceIdentifier); transactionAggregate.AuthoriseTransaction(TestData.OperatorAuthorisationCode, TestData.OperatorResponseCode, TestData.OperatorResponseMessage, TestData.OperatorTransactionId, TestData.ResponseCode, TestData.ResponseMessage); Should.Throw(() => @@ -254,7 +263,7 @@ public void TransactionAggregate_AuthoriseTransaction_TransactionAlreadyAuthoris public void TransactionAggregate_DeclineTransactionLocally_TransactionIsDeclined(TransactionType transactionType) { TransactionAggregate transactionAggregate = TransactionAggregate.Create(TestData.TransactionId); - transactionAggregate.StartTransaction(TestData.TransactionDateTime, TestData.TransactionNumber, transactionType, TestData.EstateId, TestData.MerchantId, TestData.DeviceIdentifier); + transactionAggregate.StartTransaction(TestData.TransactionDateTime, TestData.TransactionNumber, transactionType, TestData.TransactionReference, TestData.EstateId, TestData.MerchantId, TestData.DeviceIdentifier); transactionAggregate.DeclineTransactionLocally(TestData.DeclinedResponseCode, TestData.DeclinedResponseMessage); @@ -283,7 +292,7 @@ public void TransactionAggregate_DeclineTransactionLocally_TransactionNotStarted public void TransactionAggregate_DeclineTransactionLocally_TransactionAlreadyAuthorisedLocally_ErrorThrown(TransactionType transactionType) { TransactionAggregate transactionAggregate = TransactionAggregate.Create(TestData.TransactionId); - transactionAggregate.StartTransaction(TestData.TransactionDateTime, TestData.TransactionNumber, transactionType, TestData.EstateId, TestData.MerchantId, TestData.DeviceIdentifier); + transactionAggregate.StartTransaction(TestData.TransactionDateTime, TestData.TransactionNumber, transactionType, TestData.TransactionReference, TestData.EstateId, TestData.MerchantId, TestData.DeviceIdentifier); transactionAggregate.AuthoriseTransactionLocally(TestData.AuthorisationCode, TestData.ResponseCode, TestData.ResponseMessage); Should.Throw(() => @@ -298,7 +307,7 @@ public void TransactionAggregate_DeclineTransactionLocally_TransactionAlreadyAut public void TransactionAggregate_DeclineTransactionLocally_TransactionAlreadyAuthorised_ErrorThrown(TransactionType transactionType) { TransactionAggregate transactionAggregate = TransactionAggregate.Create(TestData.TransactionId); - transactionAggregate.StartTransaction(TestData.TransactionDateTime, TestData.TransactionNumber, transactionType, TestData.EstateId, TestData.MerchantId, TestData.DeviceIdentifier); + transactionAggregate.StartTransaction(TestData.TransactionDateTime, TestData.TransactionNumber, transactionType, TestData.TransactionReference, TestData.EstateId, TestData.MerchantId, TestData.DeviceIdentifier); transactionAggregate.AuthoriseTransaction(TestData.OperatorAuthorisationCode, TestData.OperatorResponseCode, TestData.OperatorResponseMessage, TestData.OperatorTransactionId, TestData.ResponseCode, TestData.ResponseMessage); Should.Throw(() => @@ -313,7 +322,7 @@ public void TransactionAggregate_DeclineTransactionLocally_TransactionAlreadyAut public void TransactionAggregate_DeclineTransactionLocally_TransactionAlreadyDeclinedLocally_ErrorThrown(TransactionType transactionType) { TransactionAggregate transactionAggregate = TransactionAggregate.Create(TestData.TransactionId); - transactionAggregate.StartTransaction(TestData.TransactionDateTime, TestData.TransactionNumber, transactionType, TestData.EstateId, TestData.MerchantId, TestData.DeviceIdentifier); + transactionAggregate.StartTransaction(TestData.TransactionDateTime, TestData.TransactionNumber, transactionType, TestData.TransactionReference, TestData.EstateId, TestData.MerchantId, TestData.DeviceIdentifier); transactionAggregate.DeclineTransactionLocally(TestData.ResponseCode, TestData.ResponseMessage); Should.Throw(() => @@ -328,7 +337,7 @@ public void TransactionAggregate_DeclineTransactionLocally_TransactionAlreadyDec public void TransactionAggregate_DeclineTransactionLocally_TransactionAlreadyDeclined_ErrorThrown(TransactionType transactionType) { TransactionAggregate transactionAggregate = TransactionAggregate.Create(TestData.TransactionId); - transactionAggregate.StartTransaction(TestData.TransactionDateTime, TestData.TransactionNumber, transactionType, TestData.EstateId, TestData.MerchantId, TestData.DeviceIdentifier); + transactionAggregate.StartTransaction(TestData.TransactionDateTime, TestData.TransactionNumber, transactionType, TestData.TransactionReference, TestData.EstateId, TestData.MerchantId, TestData.DeviceIdentifier); transactionAggregate.DeclineTransaction(TestData.OperatorResponseCode, TestData.OperatorResponseMessage, TestData.DeclinedResponseCode, TestData.DeclinedResponseMessage); Should.Throw(() => @@ -343,7 +352,7 @@ public void TransactionAggregate_DeclineTransactionLocally_TransactionAlreadyDec public void TransactionAggregate_DeclineTransaction_TransactionIsDeclined(TransactionType transactionType) { TransactionAggregate transactionAggregate = TransactionAggregate.Create(TestData.TransactionId); - transactionAggregate.StartTransaction(TestData.TransactionDateTime, TestData.TransactionNumber, transactionType, TestData.EstateId, TestData.MerchantId, TestData.DeviceIdentifier); + transactionAggregate.StartTransaction(TestData.TransactionDateTime, TestData.TransactionNumber, transactionType, TestData.TransactionReference, TestData.EstateId, TestData.MerchantId, TestData.DeviceIdentifier); transactionAggregate.DeclineTransaction(TestData.DeclinedOperatorResponseCode, TestData.DeclinedOperatorResponseMessage, TestData.DeclinedResponseCode, TestData.DeclinedResponseMessage); @@ -388,7 +397,7 @@ public void TransactionAggregate_DeclineTransaction_TransactionNotStarted_ErrorT public void TransactionAggregate_DeclineTransaction_TransactionAlreadyAuthorised_ErrorThrown(TransactionType transactionType) { TransactionAggregate transactionAggregate = TransactionAggregate.Create(TestData.TransactionId); - transactionAggregate.StartTransaction(TestData.TransactionDateTime, TestData.TransactionNumber, transactionType, TestData.EstateId, TestData.MerchantId, TestData.DeviceIdentifier); + transactionAggregate.StartTransaction(TestData.TransactionDateTime, TestData.TransactionNumber, transactionType, TestData.TransactionReference, TestData.EstateId, TestData.MerchantId, TestData.DeviceIdentifier); transactionAggregate.AuthoriseTransaction(TestData.OperatorAuthorisationCode, TestData.OperatorResponseCode, TestData.OperatorResponseMessage, TestData.OperatorTransactionId, TestData.ResponseCode, TestData.ResponseMessage); Should.Throw(() => @@ -403,7 +412,7 @@ public void TransactionAggregate_DeclineTransaction_TransactionAlreadyAuthorised public void TransactionAggregate_DeclineTransaction_TransactionAlreadyDeclinedLocally_ErrorThrown(TransactionType transactionType) { TransactionAggregate transactionAggregate = TransactionAggregate.Create(TestData.TransactionId); - transactionAggregate.StartTransaction(TestData.TransactionDateTime, TestData.TransactionNumber, transactionType, TestData.EstateId, TestData.MerchantId, TestData.DeviceIdentifier); + transactionAggregate.StartTransaction(TestData.TransactionDateTime, TestData.TransactionNumber, transactionType, TestData.TransactionReference, TestData.EstateId, TestData.MerchantId, TestData.DeviceIdentifier); transactionAggregate.DeclineTransactionLocally(TestData.ResponseCode, TestData.ResponseMessage); Should.Throw(() => @@ -418,7 +427,7 @@ public void TransactionAggregate_DeclineTransaction_TransactionAlreadyDeclinedLo public void TransactionAggregate_DeclineTransaction_TransactionAlreadyDeclined_ErrorThrown(TransactionType transactionType) { TransactionAggregate transactionAggregate = TransactionAggregate.Create(TestData.TransactionId); - transactionAggregate.StartTransaction(TestData.TransactionDateTime, TestData.TransactionNumber, transactionType, TestData.EstateId, TestData.MerchantId, TestData.DeviceIdentifier); + transactionAggregate.StartTransaction(TestData.TransactionDateTime, TestData.TransactionNumber, transactionType, TestData.TransactionReference, TestData.EstateId, TestData.MerchantId, TestData.DeviceIdentifier); transactionAggregate.DeclineTransaction(TestData.DeclinedOperatorResponseCode, TestData.DeclinedOperatorResponseMessage, TestData.DeclinedResponseCode, TestData.DeclinedResponseMessage); Should.Throw(() => @@ -433,7 +442,7 @@ public void TransactionAggregate_DeclineTransaction_TransactionAlreadyDeclined_E public void TransactionAggregate_CompleteTransaction_TransactionIsCompleted(TransactionType transactionType) { TransactionAggregate transactionAggregate = TransactionAggregate.Create(TestData.TransactionId); - transactionAggregate.StartTransaction(TestData.TransactionDateTime, TestData.TransactionNumber, transactionType, TestData.EstateId, TestData.MerchantId, TestData.DeviceIdentifier); + transactionAggregate.StartTransaction(TestData.TransactionDateTime, TestData.TransactionNumber, transactionType, TestData.TransactionReference, TestData.EstateId, TestData.MerchantId, TestData.DeviceIdentifier); if (transactionType == TransactionType.Logon) { @@ -467,7 +476,7 @@ public void TransactionAggregate_CompleteTransaction_TransactionNotStarted_Error public void TransactionAggregate_CompleteTransaction_TransactionNotAuthorised_ErrorThrown(TransactionType transactionType) { TransactionAggregate transactionAggregate = TransactionAggregate.Create(TestData.TransactionId); - transactionAggregate.StartTransaction(TestData.TransactionDateTime, TestData.TransactionNumber, transactionType, TestData.EstateId, TestData.MerchantId, TestData.DeviceIdentifier); + transactionAggregate.StartTransaction(TestData.TransactionDateTime, TestData.TransactionNumber, transactionType, TestData.TransactionReference, TestData.EstateId, TestData.MerchantId, TestData.DeviceIdentifier); Should.Throw(() => { @@ -481,7 +490,7 @@ public void TransactionAggregate_CompleteTransaction_TransactionNotAuthorised_Er public void TransactionAggregate_CompleteTransaction_TransactionAlreadyCompleted_ErrorThrown(TransactionType transactionType) { TransactionAggregate transactionAggregate = TransactionAggregate.Create(TestData.TransactionId); - transactionAggregate.StartTransaction(TestData.TransactionDateTime, TestData.TransactionNumber, transactionType, TestData.EstateId, TestData.MerchantId, TestData.DeviceIdentifier); + transactionAggregate.StartTransaction(TestData.TransactionDateTime, TestData.TransactionNumber, transactionType, TestData.TransactionReference, TestData.EstateId, TestData.MerchantId, TestData.DeviceIdentifier); if (transactionType == TransactionType.Logon) { @@ -506,7 +515,7 @@ public void TransactionAggregate_CompleteTransaction_TransactionAlreadyCompleted public void TransactionAggregate_RecordAdditionalRequestData_RequestDataRecorded(TransactionType transactionType) { TransactionAggregate transactionAggregate = TransactionAggregate.Create(TestData.TransactionId); - transactionAggregate.StartTransaction(TestData.TransactionDateTime, TestData.TransactionNumber, transactionType, TestData.EstateId, TestData.MerchantId, TestData.DeviceIdentifier); + transactionAggregate.StartTransaction(TestData.TransactionDateTime, TestData.TransactionNumber, transactionType, TestData.TransactionReference, TestData.EstateId, TestData.MerchantId, TestData.DeviceIdentifier); Should.NotThrow(() => { @@ -534,7 +543,7 @@ public void TransactionAggregate_RecordAdditionalRequestData_TransactionNotStart public void TransactionAggregate_RecordAdditionalRequestData_AdditionalRequestDataAlreadyRecorded_ErrorThrown(TransactionType transactionType) { TransactionAggregate transactionAggregate = TransactionAggregate.Create(TestData.TransactionId); - transactionAggregate.StartTransaction(TestData.TransactionDateTime, TestData.TransactionNumber, transactionType, TestData.EstateId, TestData.MerchantId, TestData.DeviceIdentifier); + transactionAggregate.StartTransaction(TestData.TransactionDateTime, TestData.TransactionNumber, transactionType, TestData.TransactionReference, TestData.EstateId, TestData.MerchantId, TestData.DeviceIdentifier); transactionAggregate.RecordAdditionalRequestData(TestData.AdditionalTransactionMetaData); Should.Throw(() => @@ -549,7 +558,7 @@ public void TransactionAggregate_RecordAdditionalRequestData_AdditionalRequestDa public void TransactionAggregate_RecordAdditionalRequestData_AlreadyAuthorised_ErrorThrown(TransactionType transactionType) { TransactionAggregate transactionAggregate = TransactionAggregate.Create(TestData.TransactionId); - transactionAggregate.StartTransaction(TestData.TransactionDateTime, TestData.TransactionNumber, transactionType, TestData.EstateId, TestData.MerchantId, TestData.DeviceIdentifier); + transactionAggregate.StartTransaction(TestData.TransactionDateTime, TestData.TransactionNumber, transactionType, TestData.TransactionReference, TestData.EstateId, TestData.MerchantId, TestData.DeviceIdentifier); transactionAggregate.RecordAdditionalRequestData(TestData.AdditionalTransactionMetaData); if (transactionType == TransactionType.Logon) @@ -573,7 +582,7 @@ public void TransactionAggregate_RecordAdditionalRequestData_AlreadyAuthorised_E public void TransactionAggregate_RecordAdditionalRequestData_AlreadyDeclined_ErrorThrown(TransactionType transactionType) { TransactionAggregate transactionAggregate = TransactionAggregate.Create(TestData.TransactionId); - transactionAggregate.StartTransaction(TestData.TransactionDateTime, TestData.TransactionNumber, transactionType, TestData.EstateId, TestData.MerchantId, TestData.DeviceIdentifier); + transactionAggregate.StartTransaction(TestData.TransactionDateTime, TestData.TransactionNumber, transactionType, TestData.TransactionReference, TestData.EstateId, TestData.MerchantId, TestData.DeviceIdentifier); transactionAggregate.RecordAdditionalRequestData(TestData.AdditionalTransactionMetaData); if (transactionType == TransactionType.Logon) @@ -597,7 +606,7 @@ public void TransactionAggregate_RecordAdditionalRequestData_AlreadyDeclined_Err public void TransactionAggregate_RecordAdditionalRequestData_AlreadyCompleted_ErrorThrown(TransactionType transactionType) { TransactionAggregate transactionAggregate = TransactionAggregate.Create(TestData.TransactionId); - transactionAggregate.StartTransaction(TestData.TransactionDateTime, TestData.TransactionNumber, transactionType, TestData.EstateId, TestData.MerchantId, TestData.DeviceIdentifier); + transactionAggregate.StartTransaction(TestData.TransactionDateTime, TestData.TransactionNumber, transactionType, TestData.TransactionReference, TestData.EstateId, TestData.MerchantId, TestData.DeviceIdentifier); transactionAggregate.RecordAdditionalRequestData(TestData.AdditionalTransactionMetaData); if (transactionType == TransactionType.Logon) { @@ -624,7 +633,7 @@ public void TransactionAggregate_RecordAdditionalRequestData_AlreadyCompleted_Er public void TransactionAggregate_RecordAdditionalResponseData_ResponseDataRecorded(TransactionType transactionType) { TransactionAggregate transactionAggregate = TransactionAggregate.Create(TestData.TransactionId); - transactionAggregate.StartTransaction(TestData.TransactionDateTime, TestData.TransactionNumber, transactionType, TestData.EstateId, TestData.MerchantId, TestData.DeviceIdentifier); + transactionAggregate.StartTransaction(TestData.TransactionDateTime, TestData.TransactionNumber, transactionType, TestData.TransactionReference, TestData.EstateId, TestData.MerchantId, TestData.DeviceIdentifier); if (transactionType == TransactionType.Logon) { transactionAggregate.AuthoriseTransactionLocally(TestData.AuthorisationCode, TestData.ResponseCode, TestData.ResponseMessage); @@ -660,7 +669,7 @@ public void TransactionAggregate_RecordAdditionalResponseData_TransactionNotStar public void TransactionAggregate_RecordAdditionalResponseData_AdditionalResponseDataAlreadyRecorded_ErrorThrown(TransactionType transactionType) { TransactionAggregate transactionAggregate = TransactionAggregate.Create(TestData.TransactionId); - transactionAggregate.StartTransaction(TestData.TransactionDateTime, TestData.TransactionNumber, transactionType, TestData.EstateId, TestData.MerchantId, TestData.DeviceIdentifier); + transactionAggregate.StartTransaction(TestData.TransactionDateTime, TestData.TransactionNumber, transactionType, TestData.TransactionReference, TestData.EstateId, TestData.MerchantId, TestData.DeviceIdentifier); transactionAggregate.RecordAdditionalRequestData(TestData.AdditionalTransactionMetaData); if (transactionType == TransactionType.Logon) { @@ -684,7 +693,7 @@ public void TransactionAggregate_RecordAdditionalResponseData_AdditionalResponse public void TransactionAggregate_RecordAdditionalResponseData_AlreadyCompleted_ErrorThrown(TransactionType transactionType) { TransactionAggregate transactionAggregate = TransactionAggregate.Create(TestData.TransactionId); - transactionAggregate.StartTransaction(TestData.TransactionDateTime, TestData.TransactionNumber, transactionType, TestData.EstateId, TestData.MerchantId, TestData.DeviceIdentifier); + transactionAggregate.StartTransaction(TestData.TransactionDateTime, TestData.TransactionNumber, transactionType, TestData.TransactionReference, TestData.EstateId, TestData.MerchantId, TestData.DeviceIdentifier); transactionAggregate.RecordAdditionalRequestData(TestData.AdditionalTransactionMetaData); if (transactionType == TransactionType.Logon) { diff --git a/TransactionProcessor.TransactionAgrgegate/TransactionAggregate.cs b/TransactionProcessor.TransactionAgrgegate/TransactionAggregate.cs index fad2e65e..36689fd8 100644 --- a/TransactionProcessor.TransactionAgrgegate/TransactionAggregate.cs +++ b/TransactionProcessor.TransactionAgrgegate/TransactionAggregate.cs @@ -200,6 +200,14 @@ private TransactionAggregate(Guid aggregateId) /// public TransactionType TransactionType { get; private set; } + /// + /// Gets the transaction reference. + /// + /// + /// The transaction reference. + /// + public String TransactionReference { get; private set; } + #endregion #region Methods @@ -367,6 +375,7 @@ public void RecordAdditionalResponseData(Dictionary additionalTr /// The transaction date time. /// The transaction number. /// Type of the transaction. + /// The transaction reference. /// The estate identifier. /// The merchant identifier. /// The device identifier. @@ -378,12 +387,14 @@ public void RecordAdditionalResponseData(Dictionary additionalTr public void StartTransaction(DateTime transactionDateTime, String transactionNumber, TransactionType transactionType, + String transactionReference, Guid estateId, Guid merchantId, String deviceIdentifier) { 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) { throw new ArgumentException("Transaction Number must be numeric"); @@ -411,6 +422,7 @@ public void StartTransaction(DateTime transactionDateTime, transactionDateTime, transactionNumber, transactionType.ToString(), + transactionReference, deviceIdentifier); this.ApplyAndPend(transactionHasStartedEvent); @@ -580,6 +592,7 @@ private void PlayEvent(TransactionHasStartedEvent domainEvent) this.TransactionDateTime = domainEvent.TransactionDateTime; this.TransactionNumber = domainEvent.TransactionNumber; this.TransactionType = Enum.Parse(domainEvent.TransactionType); + this.TransactionReference = domainEvent.TransactionReference; this.IsLocallyDeclined = false; this.IsDeclined = false; this.IsLocallyAuthorised = false;