diff --git a/.github/workflows/pullrequest.yml b/.github/workflows/pullrequest.yml index dfec0962..a78e1479 100644 --- a/.github/workflows/pullrequest.yml +++ b/.github/workflows/pullrequest.yml @@ -34,3 +34,9 @@ jobs: - name: Run Integration Tests run: dotnet test "TransactionProcessor.IntegrationTests\TransactionProcessor.IntegrationTests.csproj" --filter Category=PRTest + + - uses: actions/upload-artifact@v2 + if: ${{ failure() }} + with: + name: tracelogs + path: /home/txnproc/trace/ \ No newline at end of file diff --git a/TransactionProcessor.BusinessLogic/EventHandling/TransactionDomainEventHandler.cs b/TransactionProcessor.BusinessLogic/EventHandling/TransactionDomainEventHandler.cs index 19f91de6..390dd03f 100644 --- a/TransactionProcessor.BusinessLogic/EventHandling/TransactionDomainEventHandler.cs +++ b/TransactionProcessor.BusinessLogic/EventHandling/TransactionDomainEventHandler.cs @@ -238,14 +238,18 @@ private async Task HandleSpecificDomainEvent(TransactionHasBeenCompletedEvent do foreach (CalculatedFee calculatedFee in merchantFees) { // Determine when the fee should be applied - Guid aggregateId = merchant.NextSettlementDueDate.ToGuid(); + Logger.LogInformation($"Completed Date {domainEvent.CompletedDateTime}"); + Logger.LogInformation($"SettlementSchedule {merchant.SettlementSchedule}"); + DateTime settlementDate = CalculateSettlementDate(merchant.SettlementSchedule, domainEvent.CompletedDateTime); + Logger.LogInformation($"Settlement Date {settlementDate}"); + Guid aggregateId = settlementDate.ToGuid(); // We need to add the fees to a pending settlement stream (for today) SettlementAggregate aggregate = await this.SettlementAggregateRepository.GetLatestVersion(aggregateId, cancellationToken); if (aggregate.IsCreated == false) { - aggregate.Create(transactionAggregate.EstateId, merchant.NextSettlementDueDate); + aggregate.Create(transactionAggregate.EstateId, settlementDate); } aggregate.AddFee(transactionAggregate.MerchantId, transactionAggregate.AggregateId, calculatedFee); @@ -255,6 +259,19 @@ private async Task HandleSpecificDomainEvent(TransactionHasBeenCompletedEvent do } } + private DateTime CalculateSettlementDate(SettlementSchedule merchantSettlementSchedule, DateTime completeDateTime) + { + switch(merchantSettlementSchedule) + { + case SettlementSchedule.Weekly: + return completeDateTime.Date.AddDays(7).Date; + case SettlementSchedule.Monthly: + return completeDateTime.Date.AddMonths(1).Date; + default: + throw new Exception("Invalid merchant settlement schedule"); + } + } + /// /// Handles the specific domain event. /// diff --git a/TransactionProcessor.IntegrationTests/Settlement/Settlement.feature b/TransactionProcessor.IntegrationTests/Settlement/Settlement.feature index d268dfcd..76a95357 100644 --- a/TransactionProcessor.IntegrationTests/Settlement/Settlement.feature +++ b/TransactionProcessor.IntegrationTests/Settlement/Settlement.feature @@ -97,9 +97,9 @@ Scenario: Get Pending Settlement | Test Estate 1 | Test Merchant 3 | 8 | 0000 | SUCCESS | When I get the pending settlements the following information should be returned - | NextSettlementDate | EstateName | NumberOfFees | - | NextWeek | Test Estate 1 | 1 | - | NextMonth | Test Estate 1 | 1 | + | SettlementDate | EstateName | NumberOfFees | + | NextWeek | Test Estate 1 | 1 | + | NextMonth | Test Estate 1 | 1 | @PRTest Scenario: Process Settlement @@ -142,9 +142,9 @@ Scenario: Process Settlement | Test Estate 1 | Test Merchant 2 | 6 | 0000 | SUCCESS | When I get the pending settlements the following information should be returned - | NextSettlementDate | EstateName | NumberOfFees | - | NextWeek | Test Estate 1 | 1 | + | SettlementDate | EstateName | NumberOfFees | + | Yesterday | Test Estate 1 | 1 | - When I process the settlement for 'NextWeek' on Estate 'Test Estate 1' then 1 fees are marked as settled and the settlement is completed + When I process the settlement for 'Yesterday' on Estate 'Test Estate 1' then 1 fees are marked as settled and the settlement is completed diff --git a/TransactionProcessor.IntegrationTests/Settlement/Settlement.feature.cs b/TransactionProcessor.IntegrationTests/Settlement/Settlement.feature.cs index fc3e5cbc..c8e5ea31 100644 --- a/TransactionProcessor.IntegrationTests/Settlement/Settlement.feature.cs +++ b/TransactionProcessor.IntegrationTests/Settlement/Settlement.feature.cs @@ -247,14 +247,12 @@ void System.IDisposable.Dispose() [Xunit.SkippableFactAttribute(DisplayName="Get Pending Settlement")] [Xunit.TraitAttribute("FeatureTitle", "Settlement")] [Xunit.TraitAttribute("Description", "Get Pending Settlement")] - [Xunit.TraitAttribute("Category", "PRTest")] public virtual void GetPendingSettlement() { - string[] tagsOfScenario = new string[] { - "PRTest"}; + string[] tagsOfScenario = ((string[])(null)); System.Collections.Specialized.OrderedDictionary argumentsOfScenario = new System.Collections.Specialized.OrderedDictionary(); TechTalk.SpecFlow.ScenarioInfo scenarioInfo = new TechTalk.SpecFlow.ScenarioInfo("Get Pending Settlement", null, tagsOfScenario, argumentsOfScenario); -#line 50 +#line 49 this.ScenarioInitialize(scenarioInfo); #line hidden bool isScenarioIgnored = default(bool); @@ -317,7 +315,7 @@ public virtual void GetPendingSettlement() "testcontact3@merchant2.co.uk", "Test Estate 1", "Monthly"}); -#line 51 +#line 50 testRunner.Given("I create the following merchants", ((string)(null)), table71, "Given "); #line hidden TechTalk.SpecFlow.Table table72 = new TechTalk.SpecFlow.Table(new string[] { @@ -362,7 +360,7 @@ public virtual void GetPendingSettlement() "00000003", "10000003", "Test Estate 1"}); -#line 57 +#line 56 testRunner.Given("I have assigned the following operator to the merchants", ((string)(null)), table72, "Given "); #line hidden TechTalk.SpecFlow.Table table73 = new TechTalk.SpecFlow.Table(new string[] { @@ -381,7 +379,7 @@ public virtual void GetPendingSettlement() "123456782", "Test Merchant 3", "Test Estate 1"}); -#line 66 +#line 65 testRunner.Given("I have assigned the following devices to the merchants", ((string)(null)), table73, "Given "); #line hidden TechTalk.SpecFlow.Table table74 = new TechTalk.SpecFlow.Table(new string[] { @@ -408,7 +406,7 @@ public virtual void GetPendingSettlement() "Today", "Test Merchant 3", "Test Estate 1"}); -#line 72 +#line 71 testRunner.Given("I make the following manual merchant deposits", ((string)(null)), table74, "Given "); #line hidden TechTalk.SpecFlow.Table table75 = new TechTalk.SpecFlow.Table(new string[] { @@ -546,7 +544,7 @@ public virtual void GetPendingSettlement() "10 KES", "test@recipient.co.uk", ""}); -#line 78 +#line 77 testRunner.When("I perform the following transactions", ((string)(null)), table75, "When "); #line hidden TechTalk.SpecFlow.Table table76 = new TechTalk.SpecFlow.Table(new string[] { @@ -603,11 +601,11 @@ public virtual void GetPendingSettlement() "8", "0000", "SUCCESS"}); -#line 89 +#line 88 testRunner.Then("transaction response should contain the following information", ((string)(null)), table76, "Then "); #line hidden TechTalk.SpecFlow.Table table77 = new TechTalk.SpecFlow.Table(new string[] { - "NextSettlementDate", + "SettlementDate", "EstateName", "NumberOfFees"}); table77.AddRow(new string[] { @@ -618,7 +616,7 @@ public virtual void GetPendingSettlement() "NextMonth", "Test Estate 1", "1"}); -#line 101 +#line 99 testRunner.When("I get the pending settlements the following information should be returned", ((string)(null)), table77, "When "); #line hidden } @@ -635,7 +633,7 @@ public virtual void ProcessSettlement() "PRTest"}; System.Collections.Specialized.OrderedDictionary argumentsOfScenario = new System.Collections.Specialized.OrderedDictionary(); TechTalk.SpecFlow.ScenarioInfo scenarioInfo = new TechTalk.SpecFlow.ScenarioInfo("Process Settlement", null, tagsOfScenario, argumentsOfScenario); -#line 107 +#line 105 this.ScenarioInitialize(scenarioInfo); #line hidden bool isScenarioIgnored = default(bool); @@ -688,7 +686,7 @@ public virtual void ProcessSettlement() "testcontact2@merchant2.co.uk", "Test Estate 1", "Weekly"}); -#line 108 +#line 106 testRunner.Given("I create the following merchants", ((string)(null)), table78, "Given "); #line hidden TechTalk.SpecFlow.Table table79 = new TechTalk.SpecFlow.Table(new string[] { @@ -721,7 +719,7 @@ public virtual void ProcessSettlement() "00000002", "10000002", "Test Estate 1"}); -#line 113 +#line 111 testRunner.Given("I have assigned the following operator to the merchants", ((string)(null)), table79, "Given "); #line hidden TechTalk.SpecFlow.Table table80 = new TechTalk.SpecFlow.Table(new string[] { @@ -736,7 +734,7 @@ public virtual void ProcessSettlement() "123456781", "Test Merchant 2", "Test Estate 1"}); -#line 120 +#line 118 testRunner.Given("I have assigned the following devices to the merchants", ((string)(null)), table80, "Given "); #line hidden TechTalk.SpecFlow.Table table81 = new TechTalk.SpecFlow.Table(new string[] { @@ -757,7 +755,7 @@ public virtual void ProcessSettlement() "Today", "Test Merchant 2", "Test Estate 1"}); -#line 125 +#line 123 testRunner.Given("I make the following manual merchant deposits", ((string)(null)), table81, "Given "); #line hidden TechTalk.SpecFlow.Table table82 = new TechTalk.SpecFlow.Table(new string[] { @@ -850,7 +848,7 @@ public virtual void ProcessSettlement() "10 KES", "", "123456789"}); -#line 130 +#line 128 testRunner.When("I perform the following transactions", ((string)(null)), table82, "When "); #line hidden TechTalk.SpecFlow.Table table83 = new TechTalk.SpecFlow.Table(new string[] { @@ -889,23 +887,23 @@ public virtual void ProcessSettlement() "6", "0000", "SUCCESS"}); -#line 138 +#line 136 testRunner.Then("transaction response should contain the following information", ((string)(null)), table83, "Then "); #line hidden TechTalk.SpecFlow.Table table84 = new TechTalk.SpecFlow.Table(new string[] { - "NextSettlementDate", + "SettlementDate", "EstateName", "NumberOfFees"}); table84.AddRow(new string[] { - "NextWeek", + "Yesterday", "Test Estate 1", "1"}); -#line 146 +#line 144 testRunner.When("I get the pending settlements the following information should be returned", ((string)(null)), table84, "When "); #line hidden -#line 150 - testRunner.When("I process the settlement for \'NextWeek\' on Estate \'Test Estate 1\' then 1 fees are" + - " marked as settled and the settlement is completed", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "When "); +#line 148 + testRunner.When("I process the settlement for \'Yesterday\' on Estate \'Test Estate 1\' then 1 fees ar" + + "e marked as settled and the settlement is completed", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "When "); #line hidden } this.ScenarioCleanup(); diff --git a/TransactionProcessor.IntegrationTests/Shared/SharedSteps.cs b/TransactionProcessor.IntegrationTests/Shared/SharedSteps.cs index 22b82b62..47d230b4 100644 --- a/TransactionProcessor.IntegrationTests/Shared/SharedSteps.cs +++ b/TransactionProcessor.IntegrationTests/Shared/SharedSteps.cs @@ -9,6 +9,7 @@ namespace TransactionProcessor.IntegrationTests.Shared using System.Runtime.InteropServices; using System.Threading; using System.Threading.Tasks; + using BusinessLogic.Common; using Common; using DataTransferObjects; using EstateManagement.DataTransferObjects; @@ -877,19 +878,24 @@ public async Task WhenIGetThePendingSettlementsTheFollowingInformationShouldBeRe { // Get the merchant name EstateDetails estateDetails = this.TestingContext.GetEstateDetails(tableRow); - String nextSettlementDateString = SpecflowTableHelper.GetStringRowValue(tableRow, "NextSettlementDate"); + String settlementDateString = SpecflowTableHelper.GetStringRowValue(tableRow, "SettlementDate"); Int32 numberOfFees = SpecflowTableHelper.GetIntValue(tableRow, "NumberOfFees"); - DateTime nextSettlementDate = this.GetNextSettlementDate(DateTime.Now, nextSettlementDateString); - + DateTime settlementDate = this.GetSettlementDate(DateTime.Today, settlementDateString); + if (Environment.GetEnvironmentVariable("CI") == Boolean.TrueString.ToLower()) + { + settlementDate = settlementDate.AddDays(1); + } + + var aggregateid = settlementDate.ToGuid(); await Retry.For(async () => { SettlementResponse settlements = await this.TestingContext.DockerHelper.TransactionProcessorClient.GetSettlementByDate(this.TestingContext.AccessToken, - nextSettlementDate, + settlementDate, estateDetails.EstateId, CancellationToken.None); - settlements.NumberOfFeesPendingSettlement.ShouldBe(numberOfFees); + settlements.NumberOfFeesPendingSettlement.ShouldBe(numberOfFees, $"Settlment date {settlementDate}"); }, TimeSpan.FromMinutes(3)); } } @@ -897,7 +903,12 @@ await this.TestingContext.DockerHelper.TransactionProcessorClient.GetSettlementB [When(@"I process the settlement for '([^']*)' on Estate '([^']*)' then (.*) fees are marked as settled and the settlement is completed")] public async Task WhenIProcessTheSettlementForOnEstateThenFeesAreMarkedAsSettledAndTheSettlementIsCompleted(String dateString, String estateName, Int32 numberOfFeesSettled) { - var settlementDate = SpecflowTableHelper.GetDateForDateString(dateString, DateTime.Now); + DateTime settlementDate = this.GetSettlementDate(DateTime.Today, dateString); + if (Environment.GetEnvironmentVariable("CI") == Boolean.TrueString.ToLower()) + { + settlementDate = settlementDate.AddDays(1); + } + EstateDetails estateDetails = this.TestingContext.GetEstateDetails(estateName); await this.TestingContext.DockerHelper.TransactionProcessorClient.ProcessSettlement(this.TestingContext.AccessToken, settlementDate, @@ -915,23 +926,28 @@ await this.TestingContext.DockerHelper.TransactionProcessorClient.GetSettlementB settlement.NumberOfFeesPendingSettlement.ShouldBe(0); settlement.NumberOfFeesSettled.ShouldBe(numberOfFeesSettled); settlement.SettlementCompleted.ShouldBeTrue(); - }); + }, TimeSpan.FromMinutes(2)); } - private DateTime GetNextSettlementDate(DateTime now, + private DateTime GetSettlementDate(DateTime now, String nextSettlementDate) { + if (nextSettlementDate == "Yesterday") + { + return now.AddDays(-1).Date; + } + if (nextSettlementDate == "NextWeek") { - return now.AddDays(7); + return now.AddDays(7).Date; } if (nextSettlementDate == "NextMonth") { - return now.AddMonths(1); + return now.AddMonths(1).Date; } - return now; + return now.Date; } } } diff --git a/TransactionProcessor.IntegrationTests/TransactionProcessor.IntegrationTests.csproj b/TransactionProcessor.IntegrationTests/TransactionProcessor.IntegrationTests.csproj index e2aafeb1..1071db15 100644 --- a/TransactionProcessor.IntegrationTests/TransactionProcessor.IntegrationTests.csproj +++ b/TransactionProcessor.IntegrationTests/TransactionProcessor.IntegrationTests.csproj @@ -34,6 +34,7 @@ + diff --git a/TransactionProcessor/Controllers/SettlementController.cs b/TransactionProcessor/Controllers/SettlementController.cs index c44ee5e4..8dda2e69 100644 --- a/TransactionProcessor/Controllers/SettlementController.cs +++ b/TransactionProcessor/Controllers/SettlementController.cs @@ -16,6 +16,7 @@ namespace TransactionProcessor.Controllers using SettlementAggregates; using Shared.DomainDrivenDesign.EventSourcing; using Shared.EventStore.Aggregate; + using Shared.Logger; [ExcludeFromCodeCoverage] [Route(SettlementController.ControllerRoute)] @@ -60,6 +61,8 @@ public async Task GetPendingSettlement([FromRoute] DateTime settl // Convert the date passed in to a guid var aggregateId = settlementDate.Date.ToGuid(); + Logger.LogInformation($"Settlement Aggregate Id {aggregateId}"); + var settlementAggregate = await this.SettlmentAggregateRepository.GetLatestVersion(aggregateId, cancellationToken); var settlementResponse = new SettlementResponse