diff --git a/TransactionProcessor.BusinessLogic.Tests/OperatorInterfaces/AgencyBankingProxyTests.cs b/TransactionProcessor.BusinessLogic.Tests/OperatorInterfaces/AgencyBankingProxyTests.cs index 05ad3ec9..d60efced 100644 --- a/TransactionProcessor.BusinessLogic.Tests/OperatorInterfaces/AgencyBankingProxyTests.cs +++ b/TransactionProcessor.BusinessLogic.Tests/OperatorInterfaces/AgencyBankingProxyTests.cs @@ -194,6 +194,151 @@ public async Task AgencyBankingProxy_ProcessSaleMessage_BalanceEnquirySuccess_Re requestJson.RootElement.GetProperty("accountNumber").GetString().ShouldBe("123456789"); } + [Fact] + public async Task AgencyBankingProxy_ProcessSaleMessage_DepositFailure_ReturnsInvalidResult() + { + HttpResponseMessage responseMessage = new HttpResponseMessage(HttpStatusCode.BadRequest) + { + Content = new StringContent("deposit rejected") + }; + + HttpRequestMessage capturedRequest = null; + HttpClient httpClient = SetupMockHttpClient(responseMessage, request => capturedRequest = request); + AgencyBankingConfiguration configuration = CreateConfiguration(); + IOperatorProxy proxy = new AgencyBankingProxy(httpClient, configuration); + + Dictionary metadata = new Dictionary + { + { "AgencyBankingMessageType", "deposit" }, + { "AgencyBankingAccountNumber", "123456789" }, + { "Amount", "250.75" } + }; + + var result = await proxy.ProcessSaleMessage(TestData.TransactionId, + TestData.OperatorId, + TestData.Merchant, + TestData.TransactionDateTime, + TestData.TransactionReference, + metadata, + CancellationToken.None); + + result.IsFailed.ShouldBeTrue(); + result.Status.ShouldBe(ResultStatus.Invalid); + result.Message.ShouldBe("Failed to process deposit deposit rejected"); + + capturedRequest.ShouldNotBeNull(); + capturedRequest.Method.ShouldBe(HttpMethod.Post); + capturedRequest.RequestUri.ShouldBe(new Uri("http://localhost/transactions/deposit")); + + String requestBody = await capturedRequest.Content.ReadAsStringAsync(); + using JsonDocument requestJson = JsonDocument.Parse(requestBody); + requestJson.RootElement.GetProperty("agentId").GetString().ShouldBe(TestData.Merchant.MerchantId.ToString()); + requestJson.RootElement.GetProperty("accountNumber").GetString().ShouldBe("123456789"); + requestJson.RootElement.GetProperty("amount").GetDecimal().ShouldBe(250.75m); + requestJson.RootElement.GetProperty("transactionId").GetString().ShouldBe(TestData.TransactionId.ToString()); + } + + [Fact] + public async Task AgencyBankingProxy_ProcessSaleMessage_DepositMissingAmount_ReturnsInvalidResult() + { + HttpClient httpClient = SetupMockHttpClient(new HttpResponseMessage(HttpStatusCode.OK)); + AgencyBankingConfiguration configuration = CreateConfiguration(); + IOperatorProxy proxy = new AgencyBankingProxy(httpClient, configuration); + + Dictionary metadata = new Dictionary + { + { "AgencyBankingMessageType", "deposit" }, + { "AgencyBankingAccountNumber", "123456789" } + }; + + var result = await proxy.ProcessSaleMessage(TestData.TransactionId, + TestData.OperatorId, + TestData.Merchant, + TestData.TransactionDateTime, + TestData.TransactionReference, + metadata, + CancellationToken.None); + + result.IsFailed.ShouldBeTrue(); + result.Status.ShouldBe(ResultStatus.Invalid); + result.Message.ShouldBe("Amount - Amount is a required field for this transaction type"); + } + + [Fact] + public async Task AgencyBankingProxy_ProcessSaleMessage_DepositInvalidAmount_ReturnsInvalidResult() + { + Mock handlerMock = new Mock(MockBehavior.Strict); + HttpClient httpClient = new HttpClient(handlerMock.Object); + AgencyBankingConfiguration configuration = CreateConfiguration(); + IOperatorProxy proxy = new AgencyBankingProxy(httpClient, configuration); + + Dictionary metadata = new Dictionary + { + { "AgencyBankingMessageType", "deposit" }, + { "AgencyBankingAccountNumber", "123456789" }, + { "Amount", "not-a-number" } + }; + + var result = await proxy.ProcessSaleMessage(TestData.TransactionId, + TestData.OperatorId, + TestData.Merchant, + TestData.TransactionDateTime, + TestData.TransactionReference, + metadata, + CancellationToken.None); + + result.IsFailed.ShouldBeTrue(); + result.Status.ShouldBe(ResultStatus.Invalid); + result.Message.ShouldBe("Amount - Amount is not a valid decimal value"); + } + + [Fact] + public async Task AgencyBankingProxy_ProcessSaleMessage_DepositSuccess_ReturnsMappedOperatorResponse() + { + HttpResponseMessage responseMessage = new HttpResponseMessage(HttpStatusCode.OK) + { + Content = new StringContent("{\"ResponseCode\":\"0000\",\"TransactionId\":\"abc123\"}") + }; + + HttpRequestMessage capturedRequest = null; + HttpClient httpClient = SetupMockHttpClient(responseMessage, request => capturedRequest = request); + AgencyBankingConfiguration configuration = CreateConfiguration(); + IOperatorProxy proxy = new AgencyBankingProxy(httpClient, configuration); + + Dictionary metadata = new Dictionary + { + { "AgencyBankingMessageType", "deposit" }, + { "AgencyBankingAccountNumber", "123456789" }, + { "Amount", "250.75" } + }; + + var result = await proxy.ProcessSaleMessage(TestData.TransactionId, + TestData.OperatorId, + TestData.Merchant, + TestData.TransactionDateTime, + TestData.TransactionReference, + metadata, + CancellationToken.None); + + result.IsSuccess.ShouldBeTrue(); + result.Data.ShouldNotBeNull(); + result.Data.IsSuccessful.ShouldBeTrue(); + result.Data.ResponseCode.ShouldBe("0000"); + result.Data.ResponseMessage.ShouldBe("SUCCESS"); + result.Data.AdditionalTransactionResponseMetadata.ShouldBeEmpty(); + + capturedRequest.ShouldNotBeNull(); + capturedRequest.Method.ShouldBe(HttpMethod.Post); + capturedRequest.RequestUri.ShouldBe(new Uri("http://localhost/transactions/deposit")); + + String requestBody = await capturedRequest.Content.ReadAsStringAsync(); + using JsonDocument requestJson = JsonDocument.Parse(requestBody); + requestJson.RootElement.GetProperty("agentId").GetString().ShouldBe(TestData.Merchant.MerchantId.ToString()); + requestJson.RootElement.GetProperty("accountNumber").GetString().ShouldBe("123456789"); + requestJson.RootElement.GetProperty("amount").GetDecimal().ShouldBe(250.75m); + requestJson.RootElement.GetProperty("transactionId").GetString().ShouldBe(TestData.TransactionId.ToString()); + } + private static AgencyBankingConfiguration CreateConfiguration() { return new AgencyBankingConfiguration diff --git a/TransactionProcessor.BusinessLogic/OperatorInterfaces/AgencyBanking/AgencyBankingProxy.cs b/TransactionProcessor.BusinessLogic/OperatorInterfaces/AgencyBanking/AgencyBankingProxy.cs index 39871a0f..cfac4f48 100644 --- a/TransactionProcessor.BusinessLogic/OperatorInterfaces/AgencyBanking/AgencyBankingProxy.cs +++ b/TransactionProcessor.BusinessLogic/OperatorInterfaces/AgencyBanking/AgencyBankingProxy.cs @@ -50,15 +50,7 @@ public async Task> ProcessSaleMessage(Guid transactionI Logger.LogWarning($"AgencyBanking sale request rejected. TransactionId=[{transactionId}] missing AgencyBankingMessageType"); return Result.Invalid("AgencyBankingMessageType - Message Type is a required field for this transaction type"); } - - //// Check the meta data for the agent id - //String agentId = additionalTransactionMetadata.ExtractFieldFromMetadata("AgencyBankingAgentId"); - - //if (String.IsNullOrEmpty(agentId)) - //{ - // return Result.Invalid("AgencyBankingAgentId - Agent Id is a required field for this transaction type"); - //} - + // Check the meta data for the account number String accountNumber = additionalTransactionMetadata.ExtractFieldFromMetadata("AgencyBankingAccountNumber"); @@ -70,13 +62,72 @@ public async Task> ProcessSaleMessage(Guid transactionI Logger.LogInformation($"AgencyBanking sale request metadata resolved. TransactionId=[{transactionId}], MessageType=[{messageType}], AccountNumber=[{accountNumber}]"); - if (messageType == "balanceenquiry") + Result result = messageType switch { + "balanceenquiry" => await ProcessBalanceEnquiry(transactionId, merchant.MerchantId.ToString(), accountNumber, cancellationToken), + "deposit" => await ProcessDeposit(transactionId, merchant.MerchantId.ToString(), accountNumber, additionalTransactionMetadata, cancellationToken), + _ => Result.Invalid($"AgencyBankingMessageType - Message Type {messageType} is not supported for this transaction type") + }; + + + if (result.Status == ResultStatus.Invalid) { + Logger.LogWarning($"AgencyBanking sale request rejected. TransactionId=[{transactionId}] unsupported message type [{messageType}]"); + } + + return result; + } + + private async Task> ProcessDeposit(Guid transactionId, + String agentId, + String accountNumber, + Dictionary additionalTransactionMetadata, + CancellationToken cancellationToken) { + + HttpRequestMessage request = new(HttpMethod.Post, $"{this.Configuration.Url}/transactions/deposit"); + // Extract required data from metadata + String amountValue = additionalTransactionMetadata.ExtractFieldFromMetadata("Amount"); + + if (String.IsNullOrWhiteSpace(amountValue)) + { + Logger.LogWarning($"AgencyBanking deposit request rejected. TransactionId=[{transactionId}] missing Amount"); + return Result.Invalid("Amount - Amount is a required field for this transaction type"); + } + + if (Decimal.TryParse(amountValue, out Decimal amount) == false) + { + Logger.LogWarning($"AgencyBanking deposit request rejected. TransactionId=[{transactionId}] invalid Amount [{amountValue}]"); + return Result.Invalid("Amount - Amount is not a valid decimal value"); + } + + DepositRequest body = new() { AgentId = agentId, AccountNumber = accountNumber, Amount = amount, TransactionId = transactionId.ToString() }; + + String requestBody = StringSerialiser.Serialise(body, SerialiserOptions); + request.Content = new StringContent(requestBody, Encoding.UTF8, "application/json"); + + Logger.LogWarning($"AgencyBanking deposit request starting. TransactionId=[{transactionId}], AgentId=[{agentId}], AccountNumber=[{accountNumber}], RequestUri=[{request.RequestUri}], RequestBody=[{requestBody}]"); + + HttpResponseMessage response = await this.HttpClient.SendAsync(request, cancellationToken); + String responseContent = await response.Content.ReadAsStringAsync(cancellationToken); + + Logger.LogWarning($"AgencyBanking deposit response received. TransactionId=[{transactionId}], StatusCode=[{response.StatusCode}], ContentLength=[{responseContent?.Length ?? 0}]"); + + if (response.IsSuccessStatusCode == false) { - return await ProcessBalanceEnquiry(transactionId, merchant.MerchantId.ToString(), accountNumber, cancellationToken); + Logger.LogWarning($"AgencyBanking deposit failed. TransactionId=[{transactionId}], StatusCode=[{response.StatusCode}], ResponseBody=[{responseContent}]"); + return Result.Invalid($"Failed to process deposit {responseContent}"); } - Logger.LogWarning($"AgencyBanking sale request rejected. TransactionId=[{transactionId}] unsupported message type [{messageType}]"); - return Result.Invalid($"AgencyBankingMessageType - Message Type {messageType} is not supported for this transaction type"); + TransactionResult balanceEnquiryResponse = StringSerialiser.Deserialise(responseContent, SerialiserOptions); + Logger.LogWarning($"AgencyBanking deposit completed. TransactionId=[{transactionId}], ResponseCode=[{balanceEnquiryResponse.ResponseCode}]"); + + OperatorResponse operatorResponse = new() + { + IsSuccessful = true, + ResponseCode = "0000", + ResponseMessage = "SUCCESS", + AdditionalTransactionResponseMetadata = new Dictionary() + }; + + return Result.Success(operatorResponse); } private async Task> ProcessBalanceEnquiry(Guid transactionId, diff --git a/TransactionProcessor.BusinessLogic/OperatorInterfaces/AgencyBanking/BalanceEnquiryResponse.cs b/TransactionProcessor.BusinessLogic/OperatorInterfaces/AgencyBanking/BalanceEnquiryResponse.cs index 8dc58b3c..712cc974 100644 --- a/TransactionProcessor.BusinessLogic/OperatorInterfaces/AgencyBanking/BalanceEnquiryResponse.cs +++ b/TransactionProcessor.BusinessLogic/OperatorInterfaces/AgencyBanking/BalanceEnquiryResponse.cs @@ -22,4 +22,27 @@ public class BalanceEnquiryResponse public decimal AvailableBalance { get; set; } } + + public class DepositRequest + { + public string TransactionId { get; set; } + public string CustomerId { get; set; } + + public string AgentId { get; set; } + + public string AccountNumber { get; set; } + + public decimal Amount { get; set; } + public string Currency { get; set; } + public String Channel { get; set; } + public String Narration { get; set; } + public String ReferenceNumber { get; set; } + } + + public class TransactionResult + { + public string ResponseCode { get; set; } = ""; + + public string TransactionId { get; set; } = ""; + } } diff --git a/TransactionProcessor.IntegrationTesting.Helpers/SpecflowExtensions.cs b/TransactionProcessor.IntegrationTesting.Helpers/SpecflowExtensions.cs index f4f3fc01..4247ab9e 100644 --- a/TransactionProcessor.IntegrationTesting.Helpers/SpecflowExtensions.cs +++ b/TransactionProcessor.IntegrationTesting.Helpers/SpecflowExtensions.cs @@ -574,7 +574,7 @@ public static List ToAutomaticDepositRequests(this DataTableRows tableRo "Voucher" => BuildVoucherTransactionMetaData(recipientEmail, recipientMobile, transactionAmount), "PataPawa PostPay" => BuildPataPawaPostPayMetaData(messageType, accountNumber, recipientMobile, customerName, transactionAmount), "PataPawa PrePay" => BuildPataPawaPrePayMetaData(messageType, meterNumber, customerName, transactionAmount), - "AgencyBanking" => BuildAgencyBankingMetaData(messageType, accountNumber), + "AgencyBanking" => BuildAgencyBankingMetaData(messageType, accountNumber, transactionAmount), _ => BuildMobileTopupMetaData(transactionAmount, customerAccountNumber) }; @@ -653,11 +653,19 @@ private static Dictionary BuildMobileTopupMetaData(Decimal trans }; } - private static Dictionary BuildAgencyBankingMetaData(String messageType, String accountNumber){ - return new Dictionary{ + private static Dictionary BuildAgencyBankingMetaData(String messageType, String accountNumber, Decimal amount){ + + // TODO: make this a pattern match with sub functions?? + var metadata = new Dictionary{ { "AgencyBankingMessageType", messageType }, { "AgencyBankingAccountNumber", accountNumber } }; + + if (amount > 0) + { + metadata.Add("Amount", amount.ToString()); + } + return metadata; } private static Dictionary BuildPataPawaPostPayMetaData(String messageType, diff --git a/TransactionProcessor.IntegrationTests/Features/SaleTransactionFeature.feature b/TransactionProcessor.IntegrationTests/Features/SaleTransactionFeature.feature index 22d9f7fc..5aa330bc 100644 --- a/TransactionProcessor.IntegrationTests/Features/SaleTransactionFeature.feature +++ b/TransactionProcessor.IntegrationTests/Features/SaleTransactionFeature.feature @@ -88,6 +88,7 @@ Background: | Test Estate 1 | PataPawa PostPay | PataPawa PostPay Contract | Post Pay Bill Pay | Bill Pay (Post) | | BillPayment | | Test Estate 1 | PataPawa PrePay | PataPawa PrePay Contract | Pre Pay Bill Pay | Bill Pay (Pre) | | BillPayment | | Test Estate 1 | AgencyBanking | AgencyBanking Contract | Balance Enquiry | Balance Enquiry | | MobileTopup | + | Test Estate 1 | AgencyBanking | AgencyBanking Contract | Deposit | Deposit | | MobileTopup | When I add the following Transaction Fees | EstateName | OperatorName | ContractDescription | ProductName | CalculationType | FeeDescription | Value | @@ -134,7 +135,7 @@ Background: Given I make the following manual merchant deposits | Reference | Amount | DateTime | MerchantName | EstateName | - | Deposit1 | 265.00 | Today | Test Merchant 1 | Test Estate 1 | + | Deposit1 | 365.00 | Today | Test Merchant 1 | Test Estate 1 | | Deposit1 | 110.00 | Today | Test Merchant 2 | Test Estate 1 | | Deposit1 | 110.00 | Today | Test Merchant 3 | Test Estate 1 | | Deposit1 | 100.00 | Today | Test Merchant 4 | Test Estate 1 | @@ -176,15 +177,16 @@ Scenario: Sale Transactions | Today | 9 | Sale | 2 | Test Merchant 1 | 123456780 | Test Estate 1 | PataPawa PostPay | 20.00 | | | PataPawa PostPay Contract | Post Pay Bill Pay | test@recipient.co.uk | 123456789 | ProcessBill | 12345678 | Mr Test Customer | | | Today | 10 | Sale | 2 | Test Merchant 1 | 123456780 | Test Estate 1 | PataPawa PrePay | 0.00 | | | PataPawa PrePay Contract | Pre Pay Bill Pay | test@recipient.co.uk | | meter | | | 00000001 | | Today | 11 | Sale | 2 | Test Merchant 1 | 123456780 | Test Estate 1 | PataPawa PrePay | 25.00 | | | PataPawa PrePay Contract | Pre Pay Bill Pay | test@recipient.co.uk | | vend | 00000001 | Customer 1 | 00000001 | - | Today | 12 | Sale | 1 | Test Merchant 1 | 123456780 | Test Estate 1 | AgencyBanking | 0.00 | | | AgencyBanking Contract | Balance Enquiry | balanceenquiry | 12345678 | balanceenquiry | 12345678 | | | - | Today | 13 | Sale | 1 | Test Merchant 1 | 123456781 | Test Estate 1 | Safaricom | 100.00 | 123456789 | testcustomer@customer.co.uk | Safaricom Contract | Variable Topup | | | | | | | - | Today | 14 | Sale | 1 | Test Merchant 1 | 123456780 | InvalidEstate | Safaricom | 100.00 | 123456789 | testcustomer@customer.co.uk | Safaricom Contract | Variable Topup | | | | | | | - | Today | 15 | Sale | 1 | InvalidMerchant | 123456780 | Test Estate 1 | Safaricom | 100.00 | 123456789 | testcustomer@customer.co.uk | Safaricom Contract | Variable Topup | | | | | | | - | Today | 16 | Sale | 1 | Test Merchant 1 | 123456780 | Test Estate 1 | Safaricom | 100.00 | 123456789 | testcustomer@customer.co.uk | EmptyContract | Variable Topup | | | | | | | - | Today | 17 | Sale | 1 | Test Merchant 1 | 123456780 | Test Estate 1 | Safaricom | 100.00 | 123456789 | testcustomer@customer.co.uk | InvalidContract | Variable Topup | | | | | | | - | Today | 18 | Sale | 1 | Test Merchant 1 | 123456780 | Test Estate 1 | Safaricom | 100.00 | 123456789 | testcustomer@customer.co.uk | Safaricom Contract | EmptyProduct | | | | | | | - | Today | 19 | Sale | 1 | Test Merchant 1 | 123456780 | Test Estate 1 | Safaricom | 100.00 | 123456789 | testcustomer@customer.co.uk | Safaricom Contract | InvalidProduct | | | | | | | - | Today | 20 | Sale | 1 | Test Merchant 4 | 123456783 | Test Estate 1 | Safaricom | 300.00 | 123456789 | testcustomer@customer.co.uk | Safaricom Contract | Variable Topup | | | | | | | + | Today | 12 | Sale | 1 | Test Merchant 1 | 123456780 | Test Estate 1 | AgencyBanking | 0.00 | | | AgencyBanking Contract | Balance Enquiry | | 12345678 | balanceenquiry | 12345678 | | | + | Today | 13 | Sale | 1 | Test Merchant 1 | 123456780 | Test Estate 1 | AgencyBanking | 100.00 | | | AgencyBanking Contract | Deposit | | 12345678 | deposit | 12345678 | | | + | Today | 100 | Sale | 1 | Test Merchant 1 | 123456781 | Test Estate 1 | Safaricom | 100.00 | 123456789 | testcustomer@customer.co.uk | Safaricom Contract | Variable Topup | | | | | | | + | Today | 101 | Sale | 1 | Test Merchant 1 | 123456780 | InvalidEstate | Safaricom | 100.00 | 123456789 | testcustomer@customer.co.uk | Safaricom Contract | Variable Topup | | | | | | | + | Today | 102 | Sale | 1 | InvalidMerchant | 123456780 | Test Estate 1 | Safaricom | 100.00 | 123456789 | testcustomer@customer.co.uk | Safaricom Contract | Variable Topup | | | | | | | + | Today | 103 | Sale | 1 | Test Merchant 1 | 123456780 | Test Estate 1 | Safaricom | 100.00 | 123456789 | testcustomer@customer.co.uk | EmptyContract | Variable Topup | | | | | | | + | Today | 104 | Sale | 1 | Test Merchant 1 | 123456780 | Test Estate 1 | Safaricom | 100.00 | 123456789 | testcustomer@customer.co.uk | InvalidContract | Variable Topup | | | | | | | + | Today | 105 | Sale | 1 | Test Merchant 1 | 123456780 | Test Estate 1 | Safaricom | 100.00 | 123456789 | testcustomer@customer.co.uk | Safaricom Contract | EmptyProduct | | | | | | | + | Today | 106 | Sale | 1 | Test Merchant 1 | 123456780 | Test Estate 1 | Safaricom | 100.00 | 123456789 | testcustomer@customer.co.uk | Safaricom Contract | InvalidProduct | | | | | | | + | Today | 107 | Sale | 1 | Test Merchant 4 | 123456783 | Test Estate 1 | Safaricom | 300.00 | 123456789 | testcustomer@customer.co.uk | Safaricom Contract | Variable Topup | | | | | | | Then transaction response should contain the following information | EstateName | MerchantName | TransactionNumber | ResponseCode | ResponseMessage | @@ -200,28 +202,30 @@ Scenario: Sale Transactions | Test Estate 1 | Test Merchant 1 | 10 | 0000 | SUCCESS | | Test Estate 1 | Test Merchant 1 | 11 | 0000 | SUCCESS | | Test Estate 1 | Test Merchant 1 | 12 | 0000 | SUCCESS | - | Test Estate 1 | Test Merchant 1 | 13 | 1000 | Device Identifier 123456781 not valid for Merchant Test Merchant 1 | - | InvalidEstate | Test Merchant 1 | 14 | 1001 | Estate Id [79902550-64df-4491-b0c1-4e78943928a3] is not a valid estate | - | Test Estate 1 | InvalidMerchant | 15 | 1002 | Merchant Id [d59320fa-4c3e-4900-a999-483f6a10c69a] is not a valid merchant for estate [Test Estate 1] | - | Test Estate 1 | Test Merchant 1 | 16 | 1012 | Contract Id [00000000-0000-0000-0000-000000000000] must be set for a sale transaction | - | Test Estate 1 | Test Merchant 1 | 17 | 1015 | Contract Id [934d8164-f36a-448e-b27b-4d671d41d180] not valid for Merchant [Test Merchant 1] | - | Test Estate 1 | Test Merchant 1 | 18 | 1013 | Product Id [00000000-0000-0000-0000-000000000000] must be set for a sale transaction | - | Test Estate 1 | Test Merchant 1 | 19 | 1016 | Product Id [934d8164-f36a-448e-b27b-4d671d41d180] not valid for Merchant [Test Merchant 1] | - | Test Estate 1 | Test Merchant 4 | 20 | 1009 | Merchant [Test Merchant 4] does not have enough credit available [100.00] to perform transaction amount [300.00] | + | Test Estate 1 | Test Merchant 1 | 13 | 0000 | SUCCESS | + | Test Estate 1 | Test Merchant 1 | 100 | 1000 | Device Identifier 123456781 not valid for Merchant Test Merchant 1 | + | InvalidEstate | Test Merchant 1 | 101 | 1001 | Estate Id [79902550-64df-4491-b0c1-4e78943928a3] is not a valid estate | + | Test Estate 1 | InvalidMerchant | 102 | 1002 | Merchant Id [d59320fa-4c3e-4900-a999-483f6a10c69a] is not a valid merchant for estate [Test Estate 1] | + | Test Estate 1 | Test Merchant 1 | 103 | 1012 | Contract Id [00000000-0000-0000-0000-000000000000] must be set for a sale transaction | + | Test Estate 1 | Test Merchant 1 | 104 | 1015 | Contract Id [934d8164-f36a-448e-b27b-4d671d41d180] not valid for Merchant [Test Merchant 1] | + | Test Estate 1 | Test Merchant 1 | 105 | 1013 | Product Id [00000000-0000-0000-0000-000000000000] must be set for a sale transaction | + | Test Estate 1 | Test Merchant 1 | 106 | 1016 | Product Id [934d8164-f36a-448e-b27b-4d671d41d180] not valid for Merchant [Test Merchant 1] | + | Test Estate 1 | Test Merchant 4 | 107 | 1009 | Merchant [Test Merchant 4] does not have enough credit available [100.00] to perform transaction amount [300.00] | Then the following entries appear in the merchants balance history for estate 'Test Estate 1' and merchant 'Test Merchant 1' | DateTime | Reference | EntryType | In | Out | ChangeAmount | Balance | - | Today | Merchant Deposit | C | 240.00 | 0.00 | 265.00 | 230.00 | - | Today | Transaction Completed | D | 0.00 | 110.00 | 110.00 | 130.00 | - | Today | Transaction Completed | D | 0.00 | 90.00 | 90.00 | 30.00 | - | Today | Transaction Completed | D | 0.00 | 10.00 | 10.00 | 20.00 | - | Today | Transaction Completed | D | 0.00 | 20.00 | 20.00 | 20.00 | - | Today | Transaction Completed | D | 0.00 | 20.00 | 25.00 | 20.00 | - | Today | Transaction Fee Processed | C | 0.00 | 0.55 | 0.55 | 20.00 | - | Today | Transaction Fee Processed | C | 0.00 | 0.45 | 0.45 | 20.00 | - | Today | Transaction Fee Processed | C | 0.00 | 0.01 | 0.10 | 20.00 | - | Today | Transaction Fee Processed | C | 0.00 | 0.01 | 0.10 | 20.00 | - | Today | Opening Balance | C | 0.00 | 0.00 | 0.00 | 20.00 | + | Today | Merchant Deposit | C | 365.00 | 0.00 | 365.00 | 365.00 | + | Today | Transaction Completed | D | 0.00 | 110.00 | 110.00 | 255.00 | + | Today | Transaction Completed | D | 0.00 | 90.00 | 90.00 | 165.00 | + | Today | Transaction Completed | D | 0.00 | 10.00 | 10.00 | 155.00 | + | Today | Transaction Completed | D | 0.00 | 20.00 | 20.00 | 135.00 | + | Today | Transaction Completed | D | 0.00 | 100.00 | 100.00 | 35.00 | + | Today | Transaction Completed | D | 0.00 | 25.00 | 25.00 | 35.00 | + | Today | Transaction Fee Processed | C | 0.00 | 0.55 | 0.55 | 35.55 | + | Today | Transaction Fee Processed | C | 0.00 | 0.45 | 0.45 | 36.00 | + | Today | Transaction Fee Processed | C | 0.00 | 0.01 | 0.10 | 36.10 | + | Today | Transaction Fee Processed | C | 0.00 | 0.01 | 0.10 | 36.10 | + | Today | Opening Balance | C | 0.00 | 0.00 | 0.00 | 36.10 | Then the following entries appear in the merchants balance history for estate 'Test Estate 1' and merchant 'Test Merchant 2' | DateTime | Reference | EntryType | In | Out | ChangeAmount | Balance | diff --git a/TransactionProcessor.IntegrationTests/Features/SaleTransactionFeature.feature.cs b/TransactionProcessor.IntegrationTests/Features/SaleTransactionFeature.feature.cs index 15df35ec..2db44efa 100644 --- a/TransactionProcessor.IntegrationTests/Features/SaleTransactionFeature.feature.cs +++ b/TransactionProcessor.IntegrationTests/Features/SaleTransactionFeature.feature.cs @@ -397,6 +397,14 @@ await testRunner.GivenAsync("I have a token to access the estate management and "Balance Enquiry", "", "MobileTopup"}); + table15.AddRow(new string[] { + "Test Estate 1", + "AgencyBanking", + "AgencyBanking Contract", + "Deposit", + "Deposit", + "", + "MobileTopup"}); #line 84 await testRunner.WhenAsync("I create the following Products", ((string)(null)), table15, "When "); #line hidden @@ -432,7 +440,7 @@ await testRunner.GivenAsync("I have a token to access the estate management and "Percentage", "Merchant Commission", "0.50"}); -#line 92 +#line 93 await testRunner.WhenAsync("I add the following Transaction Fees", ((string)(null)), table16, "When "); #line hidden global::Reqnroll.Table table17 = new global::Reqnroll.Table(new string[] { @@ -490,7 +498,7 @@ await testRunner.GivenAsync("I have a token to access the estate management and "testcontact4@merchant4.co.uk", "Test Estate 1", "true"}); -#line 98 +#line 99 await testRunner.GivenAsync("I create the following merchants", ((string)(null)), table17, "Given "); #line hidden global::Reqnroll.Table table18 = new global::Reqnroll.Table(new string[] { @@ -619,7 +627,7 @@ await testRunner.GivenAsync("I have a token to access the estate management and "00000004", "10000004", "Test Estate 1"}); -#line 105 +#line 106 await testRunner.GivenAsync("I have assigned the following operator to the merchants", ((string)(null)), table18, "Given "); #line hidden global::Reqnroll.Table table19 = new global::Reqnroll.Table(new string[] { @@ -642,7 +650,7 @@ await testRunner.GivenAsync("I have a token to access the estate management and "123456783", "Test Merchant 4", "Test Estate 1"}); -#line 128 +#line 129 await testRunner.GivenAsync("I have assigned the following devices to the merchants", ((string)(null)), table19, "Given "); #line hidden global::Reqnroll.Table table20 = new global::Reqnroll.Table(new string[] { @@ -653,7 +661,7 @@ await testRunner.GivenAsync("I have a token to access the estate management and "EstateName"}); table20.AddRow(new string[] { "Deposit1", - "265.00", + "365.00", "Today", "Test Merchant 1", "Test Estate 1"}); @@ -675,7 +683,7 @@ await testRunner.GivenAsync("I have a token to access the estate management and "Today", "Test Merchant 4", "Test Estate 1"}); -#line 135 +#line 136 await testRunner.GivenAsync("I make the following manual merchant deposits", ((string)(null)), table20, "Given "); #line hidden global::Reqnroll.Table table21 = new global::Reqnroll.Table(new string[] { @@ -750,7 +758,7 @@ await testRunner.GivenAsync("I have a token to access the estate management and "Test Estate 1", "Test Merchant 4", "PataPawa PrePay Contract"}); -#line 142 +#line 143 await testRunner.WhenAsync("I add the following contracts to the following merchants", ((string)(null)), table21, "When "); #line hidden } @@ -774,7 +782,7 @@ await testRunner.GivenAsync("I have a token to access the estate management and global::Reqnroll.ScenarioInfo scenarioInfo = new global::Reqnroll.ScenarioInfo("Sale Transactions", null, tagsOfScenario, argumentsOfScenario, featureTags, pickleIndex); string[] tagsOfRule = ((string[])(null)); global::Reqnroll.RuleInfo ruleInfo = null; -#line 164 +#line 165 this.ScenarioInitialize(scenarioInfo, ruleInfo); #line hidden if ((global::Reqnroll.TagHelper.ContainsIgnoreTag(scenarioInfo.CombinedTags) || global::Reqnroll.TagHelper.ContainsIgnoreTag(featureTags))) @@ -1041,7 +1049,7 @@ await testRunner.GivenAsync("I have a token to access the estate management and "", "AgencyBanking Contract", "Balance Enquiry", - "balanceenquiry", + "", "12345678", "balanceenquiry", "12345678", @@ -1053,6 +1061,26 @@ await testRunner.GivenAsync("I have a token to access the estate management and "Sale", "1", "Test Merchant 1", + "123456780", + "Test Estate 1", + "AgencyBanking", + "100.00", + "", + "", + "AgencyBanking Contract", + "Deposit", + "", + "12345678", + "deposit", + "12345678", + "", + ""}); + table22.AddRow(new string[] { + "Today", + "100", + "Sale", + "1", + "Test Merchant 1", "123456781", "Test Estate 1", "Safaricom", @@ -1069,7 +1097,7 @@ await testRunner.GivenAsync("I have a token to access the estate management and ""}); table22.AddRow(new string[] { "Today", - "14", + "101", "Sale", "1", "Test Merchant 1", @@ -1089,7 +1117,7 @@ await testRunner.GivenAsync("I have a token to access the estate management and ""}); table22.AddRow(new string[] { "Today", - "15", + "102", "Sale", "1", "InvalidMerchant", @@ -1109,7 +1137,7 @@ await testRunner.GivenAsync("I have a token to access the estate management and ""}); table22.AddRow(new string[] { "Today", - "16", + "103", "Sale", "1", "Test Merchant 1", @@ -1129,7 +1157,7 @@ await testRunner.GivenAsync("I have a token to access the estate management and ""}); table22.AddRow(new string[] { "Today", - "17", + "104", "Sale", "1", "Test Merchant 1", @@ -1149,7 +1177,7 @@ await testRunner.GivenAsync("I have a token to access the estate management and ""}); table22.AddRow(new string[] { "Today", - "18", + "105", "Sale", "1", "Test Merchant 1", @@ -1169,7 +1197,7 @@ await testRunner.GivenAsync("I have a token to access the estate management and ""}); table22.AddRow(new string[] { "Today", - "19", + "106", "Sale", "1", "Test Merchant 1", @@ -1189,7 +1217,7 @@ await testRunner.GivenAsync("I have a token to access the estate management and ""}); table22.AddRow(new string[] { "Today", - "20", + "107", "Sale", "1", "Test Merchant 4", @@ -1207,7 +1235,7 @@ await testRunner.GivenAsync("I have a token to access the estate management and "", "", ""}); -#line 166 +#line 167 await testRunner.WhenAsync("I perform the following transactions", ((string)(null)), table22, "When "); #line hidden global::Reqnroll.Table table23 = new global::Reqnroll.Table(new string[] { @@ -1292,57 +1320,63 @@ await testRunner.GivenAsync("I have a token to access the estate management and "Test Estate 1", "Test Merchant 1", "13", + "0000", + "SUCCESS"}); + table23.AddRow(new string[] { + "Test Estate 1", + "Test Merchant 1", + "100", "1000", "Device Identifier 123456781 not valid for Merchant Test Merchant 1"}); table23.AddRow(new string[] { "InvalidEstate", "Test Merchant 1", - "14", + "101", "1001", "Estate Id [79902550-64df-4491-b0c1-4e78943928a3] is not a valid estate"}); table23.AddRow(new string[] { "Test Estate 1", "InvalidMerchant", - "15", + "102", "1002", "Merchant Id [d59320fa-4c3e-4900-a999-483f6a10c69a] is not a valid merchant for es" + "tate [Test Estate 1]"}); table23.AddRow(new string[] { "Test Estate 1", "Test Merchant 1", - "16", + "103", "1012", "Contract Id [00000000-0000-0000-0000-000000000000] must be set for a sale transac" + "tion"}); table23.AddRow(new string[] { "Test Estate 1", "Test Merchant 1", - "17", + "104", "1015", "Contract Id [934d8164-f36a-448e-b27b-4d671d41d180] not valid for Merchant [Test M" + "erchant 1]"}); table23.AddRow(new string[] { "Test Estate 1", "Test Merchant 1", - "18", + "105", "1013", "Product Id [00000000-0000-0000-0000-000000000000] must be set for a sale transact" + "ion"}); table23.AddRow(new string[] { "Test Estate 1", "Test Merchant 1", - "19", + "106", "1016", "Product Id [934d8164-f36a-448e-b27b-4d671d41d180] not valid for Merchant [Test Me" + "rchant 1]"}); table23.AddRow(new string[] { "Test Estate 1", "Test Merchant 4", - "20", + "107", "1009", "Merchant [Test Merchant 4] does not have enough credit available [100.00] to perf" + "orm transaction amount [300.00]"}); -#line 189 +#line 191 await testRunner.ThenAsync("transaction response should contain the following information", ((string)(null)), table23, "Then "); #line hidden global::Reqnroll.Table table24 = new global::Reqnroll.Table(new string[] { @@ -1357,10 +1391,10 @@ await testRunner.GivenAsync("I have a token to access the estate management and "Today", "Merchant Deposit", "C", - "240.00", + "365.00", "0.00", - "265.00", - "230.00"}); + "365.00", + "365.00"}); table24.AddRow(new string[] { "Today", "Transaction Completed", @@ -1368,7 +1402,7 @@ await testRunner.GivenAsync("I have a token to access the estate management and "0.00", "110.00", "110.00", - "130.00"}); + "255.00"}); table24.AddRow(new string[] { "Today", "Transaction Completed", @@ -1376,7 +1410,7 @@ await testRunner.GivenAsync("I have a token to access the estate management and "0.00", "90.00", "90.00", - "30.00"}); + "165.00"}); table24.AddRow(new string[] { "Today", "Transaction Completed", @@ -1384,7 +1418,7 @@ await testRunner.GivenAsync("I have a token to access the estate management and "0.00", "10.00", "10.00", - "20.00"}); + "155.00"}); table24.AddRow(new string[] { "Today", "Transaction Completed", @@ -1392,15 +1426,23 @@ await testRunner.GivenAsync("I have a token to access the estate management and "0.00", "20.00", "20.00", - "20.00"}); + "135.00"}); + table24.AddRow(new string[] { + "Today", + "Transaction Completed", + "D", + "0.00", + "100.00", + "100.00", + "35.00"}); table24.AddRow(new string[] { "Today", "Transaction Completed", "D", "0.00", - "20.00", "25.00", - "20.00"}); + "25.00", + "35.00"}); table24.AddRow(new string[] { "Today", "Transaction Fee Processed", @@ -1408,7 +1450,7 @@ await testRunner.GivenAsync("I have a token to access the estate management and "0.00", "0.55", "0.55", - "20.00"}); + "35.55"}); table24.AddRow(new string[] { "Today", "Transaction Fee Processed", @@ -1416,7 +1458,7 @@ await testRunner.GivenAsync("I have a token to access the estate management and "0.00", "0.45", "0.45", - "20.00"}); + "36.00"}); table24.AddRow(new string[] { "Today", "Transaction Fee Processed", @@ -1424,7 +1466,7 @@ await testRunner.GivenAsync("I have a token to access the estate management and "0.00", "0.01", "0.10", - "20.00"}); + "36.10"}); table24.AddRow(new string[] { "Today", "Transaction Fee Processed", @@ -1432,7 +1474,7 @@ await testRunner.GivenAsync("I have a token to access the estate management and "0.00", "0.01", "0.10", - "20.00"}); + "36.10"}); table24.AddRow(new string[] { "Today", "Opening Balance", @@ -1440,8 +1482,8 @@ await testRunner.GivenAsync("I have a token to access the estate management and "0.00", "0.00", "0.00", - "20.00"}); -#line 212 + "36.10"}); +#line 215 await testRunner.ThenAsync("the following entries appear in the merchants balance history for estate \'Test Es" + "tate 1\' and merchant \'Test Merchant 1\'", ((string)(null)), table24, "Then "); #line hidden @@ -1493,7 +1535,7 @@ await testRunner.GivenAsync("I have a token to access the estate management and "0.00", "0.00", "20.00"}); -#line 226 +#line 230 await testRunner.ThenAsync("the following entries appear in the merchants balance history for estate \'Test Es" + "tate 1\' and merchant \'Test Merchant 2\'", ((string)(null)), table25, "Then "); #line hidden @@ -1545,7 +1587,7 @@ await testRunner.GivenAsync("I have a token to access the estate management and "0.00", "0.00", "20.00"}); -#line 234 +#line 238 await testRunner.ThenAsync("the following entries appear in the merchants balance history for estate \'Test Es" + "tate 1\' and merchant \'Test Merchant 3\'", ((string)(null)), table26, "Then "); #line hidden diff --git a/TransactionProcessor/nlog.config b/TransactionProcessor/nlog.config index 1ec67c78..96828f11 100644 --- a/TransactionProcessor/nlog.config +++ b/TransactionProcessor/nlog.config @@ -33,7 +33,7 @@ s - +