From ea489835fe4c286e2ee4be8f41711b7755831c20 Mon Sep 17 00:00:00 2001 From: Craig Edmunds Date: Thu, 9 Jan 2025 13:48:56 +0000 Subject: [PATCH] CDMS-223 refactoring 'pairing' to be Context.DecisionComparison & only having it on one decision at a time. Few decision tests currently failing --- Btms.Analytics/MovementExceptions.cs | 11 +- Btms.Analytics/MovementsAggregationService.cs | 2 +- .../AlvsDecisionNumber1Missing.cs | 23 +-- .../ChedPDuplicateDecisionTests.cs | 2 +- .../DecisionTests/ChedPSimpleTests.cs | 53 +++--- .../ChedPUpdatedNotificationTests.cs | 7 +- .../NoMatchNoAlvsDecisionTests.cs | 9 +- .../DecisionTests/NoMatchTests.cs | 57 +++--- .../DecisionTests/NonContiguous.cs | 34 ++-- .../OutOfSequenceAlvsDecision.cs | 55 ++---- Btms.Business/Builders/MovementBuilder.cs | 167 +++++++++++------- .../Extensions/MovementExtensions.cs | 55 +++--- Btms.Model/Cds/AlvsDecision.cs | 47 +++-- .../BtmsClient.cs | 1 + .../Fixtures/BackendFixture.cs | 9 +- 15 files changed, 271 insertions(+), 261 deletions(-) diff --git a/Btms.Analytics/MovementExceptions.cs b/Btms.Analytics/MovementExceptions.cs index fdbee4f5..e2e9b015 100644 --- a/Btms.Analytics/MovementExceptions.cs +++ b/Btms.Analytics/MovementExceptions.cs @@ -32,11 +32,12 @@ public class MovementExceptions(IMongoDbContext context, ILogger logger) ItemCount = m.Items.Count, ChedTypes = m.BtmsStatus.ChedTypes, Status = m.BtmsStatus, - DecisionMatched = !m.AlvsDecisionStatus.Decisions - .OrderBy(d => d.Context.AlvsDecisionNumber) - .Reverse() - .First() - .Context.DecisionMatched, + DecisionMatched = m.AlvsDecisionStatus.Context.DecisionComparison!.DecisionMatched, + // DecisionMatched = !m.AlvsDecisionStatus.Decisions + // .OrderBy(d => d.Context.AlvsDecisionNumber) + // .Reverse() + // .First() + // .Context.DecisionMatched, HasNotificationRelationships = m.Relationships.Notifications.Data.Count > 0, ContiguousAlvsClearanceRequestVersionsFrom1 = m.ClearanceRequests.Select(c => c.Header!.EntryVersionNumber) diff --git a/Btms.Analytics/MovementsAggregationService.cs b/Btms.Analytics/MovementsAggregationService.cs index 3abfc8c9..77a1899e 100644 --- a/Btms.Analytics/MovementsAggregationService.cs +++ b/Btms.Analytics/MovementsAggregationService.cs @@ -289,7 +289,7 @@ public Task> .SelectMany(d => d.Decision.Context.Checks.Select(c => new { d.Decision, d.Movement, Check = c})) .GroupBy(d => new { - d.Decision.Context.DecisionStatus, + d.Decision.Context.DecisionComparison!.DecisionStatus, d.Check.CheckCode, d.Check.AlvsDecisionCode, d.Check.BtmsDecisionCode diff --git a/Btms.Backend.IntegrationTests/DecisionTests/AlvsDecisionNumber1Missing.cs b/Btms.Backend.IntegrationTests/DecisionTests/AlvsDecisionNumber1Missing.cs index 2047936f..6949646c 100644 --- a/Btms.Backend.IntegrationTests/DecisionTests/AlvsDecisionNumber1Missing.cs +++ b/Btms.Backend.IntegrationTests/DecisionTests/AlvsDecisionNumber1Missing.cs @@ -19,11 +19,8 @@ public class AlvsDecisionNumber1Missing(ITestOutputHelper output) [Fact] public void ShouldHave1AlvsDecision() { - // Assert - var movement = Client - .GetSingleMovement(); - - movement + Client + .GetSingleMovement() .AlvsDecisionStatus .Decisions .Count @@ -34,11 +31,8 @@ public void ShouldHave1AlvsDecision() [Fact] public void ShouldHaveCorrectDecisionNumbers() { - // Assert - var movement = Client - .GetSingleMovement(); - - movement + Client + .GetSingleMovement() .AlvsDecisionStatus .Decisions .Select(d => d.Context.AlvsDecisionNumber) @@ -49,13 +43,10 @@ public void ShouldHaveCorrectDecisionNumbers() [Fact] public void ShouldHaveVersionNotCompleteDecisionStatus() { - - // Assert - var movement = Client - .GetSingleMovement(); - - movement + Client + .GetSingleMovement() .AlvsDecisionStatus + .Context.DecisionComparison! .DecisionStatus .Should() .Be(DecisionStatusEnum.AlvsDecisionVersion1NotPresent); diff --git a/Btms.Backend.IntegrationTests/DecisionTests/ChedPDuplicateDecisionTests.cs b/Btms.Backend.IntegrationTests/DecisionTests/ChedPDuplicateDecisionTests.cs index 83a25ad3..e732a25e 100644 --- a/Btms.Backend.IntegrationTests/DecisionTests/ChedPDuplicateDecisionTests.cs +++ b/Btms.Backend.IntegrationTests/DecisionTests/ChedPDuplicateDecisionTests.cs @@ -43,7 +43,7 @@ public void SimpleChedPScenario_ShouldBeLinkedAndMatchDecision() movement.AlvsDecisionStatus.Decisions .First() - .Context.DecisionMatched + .Context.DecisionComparison!.DecisionMatched .Should().BeTrue(); var decisionWithLinkAndContext = movement.AuditEntries diff --git a/Btms.Backend.IntegrationTests/DecisionTests/ChedPSimpleTests.cs b/Btms.Backend.IntegrationTests/DecisionTests/ChedPSimpleTests.cs index 5a220552..a3657c18 100644 --- a/Btms.Backend.IntegrationTests/DecisionTests/ChedPSimpleTests.cs +++ b/Btms.Backend.IntegrationTests/DecisionTests/ChedPSimpleTests.cs @@ -20,19 +20,23 @@ public class ChedPSimpleTests(ITestOutputHelper output) { [Fact] - public void ShouldHaveCorrectAlvsDecisionMatchedStatus() + public void ShouldHaveCorrectAlvsDecisionMatchedStatusOnDecison() { - // Assert - var movement = Client - .GetSingleMovement(); - - movement.AlvsDecisionStatus.Decisions + Client + .GetSingleMovement() + .AlvsDecisionStatus.Decisions .Single() - .Context.DecisionMatched + .Context.DecisionComparison!.DecisionMatched .Should().BeTrue(); - - movement.AlvsDecisionStatus - .Context.DecisionMatched + } + + [Fact] + public void ShouldHaveCorrectAlvsDecisionMatchedStatusAtGlobalLevel() + { + Client + .GetSingleMovement() + .AlvsDecisionStatus + .Context.DecisionComparison!.DecisionMatched .Should().BeTrue(); } @@ -107,11 +111,8 @@ public void ShouldHaveDecisionMatched() { var movement = Client .GetSingleMovement() - .AlvsDecisionStatus - .Context! - .DecisionMatched - .Should() - .BeTrue(); + .AlvsDecisionStatus.Context!.DecisionComparison!.DecisionMatched + .Should().BeTrue(); } [Fact] @@ -119,10 +120,8 @@ public void ShouldHaveDecisionStatus() { Client .GetSingleMovement() - .AlvsDecisionStatus - .DecisionStatus - .Should() - .Be(DecisionStatusEnum.BtmsMadeSameDecisionAsAlvs); + .AlvsDecisionStatus.Context.DecisionComparison!.DecisionStatus + .Should().Be(DecisionStatusEnum.BtmsMadeSameDecisionAsAlvs); } [Fact] @@ -130,10 +129,8 @@ public void ShouldHaveChedType() { Client .GetSingleMovement() - .BtmsStatus - .ChedTypes - .Should() - .Equal(ImportNotificationTypeEnum.Cvedp); + .BtmsStatus.ChedTypes + .Should().Equal(ImportNotificationTypeEnum.Cvedp); } [Fact] @@ -142,8 +139,7 @@ public void ShouldBeLinked() Client .GetSingleMovement() .BtmsStatus.LinkStatus - .Should() - .Be("Linked"); + .Should().Be("Linked"); } // [Fact] @@ -180,11 +176,10 @@ public void AlvsDecisionShouldBePaired() { Client .GetSingleMovement() - .AlvsDecisionStatus - .Decisions + .AlvsDecisionStatus.Decisions .Single() .Context - .Should() - .Match(c => c.BtmsDecisionNumber == 2 && c.Paired == true); + .DecisionComparison! + .Should().Match(c => c.BtmsDecisionNumber == 2 && c.Paired == true); } } \ No newline at end of file diff --git a/Btms.Backend.IntegrationTests/DecisionTests/ChedPUpdatedNotificationTests.cs b/Btms.Backend.IntegrationTests/DecisionTests/ChedPUpdatedNotificationTests.cs index a57e6146..2c6221c6 100644 --- a/Btms.Backend.IntegrationTests/DecisionTests/ChedPUpdatedNotificationTests.cs +++ b/Btms.Backend.IntegrationTests/DecisionTests/ChedPUpdatedNotificationTests.cs @@ -79,10 +79,9 @@ public void AlvsDecisionShouldMatch() { Client .GetSingleMovement() - .AlvsDecisionStatus - .Decisions + .AlvsDecisionStatus.Decisions .Single() - .Context.DecisionMatched + .Context.DecisionComparison!.DecisionMatched .Should().BeTrue(); } @@ -105,6 +104,6 @@ public void LastBtmsDecisionShouldHaveCorrectAuditEntry() (ChedPNotification.ReferenceNumber!, 2) ]); - decisionWithLinkAndContext.Context.Paired.Should().BeTrue(); + decisionWithLinkAndContext.Context.DecisionComparison!.Paired.Should().BeTrue(); } } \ No newline at end of file diff --git a/Btms.Backend.IntegrationTests/DecisionTests/NoMatchNoAlvsDecisionTests.cs b/Btms.Backend.IntegrationTests/DecisionTests/NoMatchNoAlvsDecisionTests.cs index a027d534..edc43543 100644 --- a/Btms.Backend.IntegrationTests/DecisionTests/NoMatchNoAlvsDecisionTests.cs +++ b/Btms.Backend.IntegrationTests/DecisionTests/NoMatchNoAlvsDecisionTests.cs @@ -31,10 +31,10 @@ public void ShouldHaveDecisionStatus() { // Assert - var movement = Client - .GetSingleMovement(); - - movement.AlvsDecisionStatus.DecisionStatus.Should().Be(DecisionStatusEnum.NoAlvsDecisions); + Client + .GetSingleMovement() + .AlvsDecisionStatus.Context.DecisionComparison!.DecisionStatus + .Should().Be(DecisionStatusEnum.NoAlvsDecisions); } [Fact] @@ -47,6 +47,7 @@ public void ShouldHaveDecisionMatched() movement .AlvsDecisionStatus .Context! + .DecisionComparison! .DecisionMatched .Should() .BeFalse(); diff --git a/Btms.Backend.IntegrationTests/DecisionTests/NoMatchTests.cs b/Btms.Backend.IntegrationTests/DecisionTests/NoMatchTests.cs index 81b8e848..8717d760 100644 --- a/Btms.Backend.IntegrationTests/DecisionTests/NoMatchTests.cs +++ b/Btms.Backend.IntegrationTests/DecisionTests/NoMatchTests.cs @@ -20,67 +20,56 @@ public class NoMatchTests(ITestOutputHelper output) [Fact] public void ShouldNotHaveLinked() { - // Assert - var movement = Client - .GetSingleMovement(); - - movement.BtmsStatus.LinkStatus.Should().Be("Not Linked"); + Client + .GetSingleMovement() + .BtmsStatus.LinkStatus + .Should().Be("Not Linked"); } [Fact] public void ShouldHaveAlvsDecision() { - // Assert - var movement = Client - .GetSingleMovement(); - - movement.AlvsDecisionStatus.Decisions.Count.Should().Be(1); + Client + .GetSingleMovement() + .AlvsDecisionStatus.Decisions.Count + .Should().Be(1); } [Fact] public void ShouldHaveDecisionStatus() { - - // Assert - var movement = Client - .GetSingleMovement(); - - movement.AlvsDecisionStatus.DecisionStatus.Should().Be(DecisionStatusEnum.InvestigationNeeded); + Client + .GetSingleMovement() + .AlvsDecisionStatus.Context.DecisionComparison!.DecisionStatus + .Should().Be(DecisionStatusEnum.InvestigationNeeded); } [Fact] public void ShouldHaveDecisionAuditChecks() { - var auditEntry = Client + Client .GetSingleMovement() - .SingleBtmsDecisionAuditEntry(); - - auditEntry.Context?.Checks.Should().NotBeNull(); + .SingleBtmsDecisionAuditEntry() + .Context?.Checks + .Should().NotBeNull(); } [Fact] public void ShouldNotHaveDecisionAuditNotifications() { - - var auditEntry = Client + Client .GetSingleMovement() - .SingleBtmsDecisionAuditEntry(); - - auditEntry.Context?.ImportNotifications.Should().BeEmpty(); + .SingleBtmsDecisionAuditEntry() + .Context?.ImportNotifications + .Should().BeEmpty(); } [Fact] public void ShouldHaveDecisionMatchedFalse() { - - // Assert - var movement = Client - .GetSingleMovement(); - - movement - .AlvsDecisionStatus - .Context! - .DecisionMatched + Client + .GetSingleMovement() + .AlvsDecisionStatus.Context!.DecisionComparison!.DecisionMatched .Should() .BeFalse(); } diff --git a/Btms.Backend.IntegrationTests/DecisionTests/NonContiguous.cs b/Btms.Backend.IntegrationTests/DecisionTests/NonContiguous.cs index 70aac347..5243ffdc 100644 --- a/Btms.Backend.IntegrationTests/DecisionTests/NonContiguous.cs +++ b/Btms.Backend.IntegrationTests/DecisionTests/NonContiguous.cs @@ -47,12 +47,9 @@ public void ShouldHaveCorrectDecisionNumbers() [Fact] public void ShouldHaveVersionNotCompleteDecisionStatus() { - var movement = Client - .GetSingleMovement(); - - movement - .AlvsDecisionStatus - .DecisionStatus + Client + .GetSingleMovement() + .AlvsDecisionStatus.Context.DecisionComparison!.DecisionStatus .Should() .Be(DecisionStatusEnum.AlvsDecisionVersionsNotComplete); } @@ -60,27 +57,21 @@ public void ShouldHaveVersionNotCompleteDecisionStatus() [Fact] public void ShouldHavePairedAlvsDecisions() { - var movement = Client - .GetSingleMovement(); - - movement + Client + .GetSingleMovement() .AlvsDecisionStatus .Decisions - .Count(d => d.Context.Paired) + .Count(d => d.Context.DecisionComparison!.Paired) .Should().Be(1); } [Fact] public void ShouldHave1BtmsDecision() { - var movement = Client - .GetSingleMovement(); - - movement - .Decisions - .Count - .Should() - .Be(1); + Client + .GetSingleMovement() + .Decisions.Count + .Should().Be(1); } [Fact] @@ -90,9 +81,8 @@ public void ShouldHavePairedBtmsDecisions() .GetSingleMovement(); movement - .AlvsDecisionStatus - .Decisions - .Select(d => (d.Context.AlvsDecisionNumber, d.Context.BtmsDecisionNumber)) + .AlvsDecisionStatus.Decisions + .Select(d => (d.Context.AlvsDecisionNumber, d.Context.DecisionComparison!.BtmsDecisionNumber)) .Should().Equal((1,null), (3,1)); } } \ No newline at end of file diff --git a/Btms.Backend.IntegrationTests/DecisionTests/OutOfSequenceAlvsDecision.cs b/Btms.Backend.IntegrationTests/DecisionTests/OutOfSequenceAlvsDecision.cs index d77925a7..bba67b9a 100644 --- a/Btms.Backend.IntegrationTests/DecisionTests/OutOfSequenceAlvsDecision.cs +++ b/Btms.Backend.IntegrationTests/DecisionTests/OutOfSequenceAlvsDecision.cs @@ -20,60 +20,39 @@ public class OutOfSequenceAlvsDecision(ITestOutputHelper output) [Fact] public void ShouldHave2AlvsDecisions() { - // Assert - var movement = Client - .GetSingleMovement(); - - movement - .AlvsDecisionStatus - .Decisions - .Count - .Should() - .Be(2); + Client + .GetSingleMovement() + .AlvsDecisionStatus.Decisions.Count + .Should().Be(2); } [Fact] public void ShouldHaveCorrectDecisionNumbers() { // Assert - var movement = Client - .GetSingleMovement(); - - movement - .AlvsDecisionStatus - .Decisions + Client + .GetSingleMovement() + .AlvsDecisionStatus.Decisions .Select(d => d.Context.AlvsDecisionNumber) - .Should() - .Equal(2, 1); + .Should().Equal(2, 1); } [Fact] public void ShouldHaveVersionNotCompleteDecisionStatus() { - - // Assert - var movement = Client - .GetSingleMovement(); - - movement - .AlvsDecisionStatus - .DecisionStatus - .Should() - .Be(DecisionStatusEnum.BtmsMadeSameDecisionAsAlvs); + Client + .GetSingleMovement() + .AlvsDecisionStatus.Context.DecisionComparison!.DecisionStatus + .Should().Be(DecisionStatusEnum.BtmsMadeSameDecisionAsAlvs); } [Fact] public void ShouldHavePairedAlvsDecisions() { - - // Assert - var movement = Client - .GetSingleMovement(); - - movement - .AlvsDecisionStatus - .Decisions - .Count(d => d.Context.Paired) + Client + .GetSingleMovement() + .AlvsDecisionStatus.Decisions + .Count(d => d.Context.DecisionComparison!.Paired) .Should().Be(1); } @@ -84,7 +63,7 @@ public void ShouldHavePairedBtmsDecisions() .GetSingleMovement() .AlvsDecisionStatus .Decisions - .Select(d => (d.Context.AlvsDecisionNumber, d.Context.BtmsDecisionNumber)) + .Select(d => (d.Context.AlvsDecisionNumber, d.Context.DecisionComparison!.BtmsDecisionNumber)) .Should().Equal( (2,2), (1, null)); diff --git a/Btms.Business/Builders/MovementBuilder.cs b/Btms.Business/Builders/MovementBuilder.cs index a8441ece..33958731 100644 --- a/Btms.Business/Builders/MovementBuilder.cs +++ b/Btms.Business/Builders/MovementBuilder.cs @@ -95,24 +95,30 @@ public MovementBuilder MergeDecision(string path, Model.Cds.CdsClearanceRequest var alvsDecision = FindBtmsPairAndUpdate(clearanceRequest); context = alvsDecision.Context; - if (_movement.AlvsDecisionStatus.Decisions.Count == 0 || ((alvsDecision.Context.AlvsDecisionNumber >=_movement. AlvsDecisionStatus.Context?.AlvsDecisionNumber) && - (alvsDecision.Context.BtmsDecisionNumber > _movement.AlvsDecisionStatus.Context?.BtmsDecisionNumber)) || - ((alvsDecision.Context.AlvsDecisionNumber > _movement.AlvsDecisionStatus.Context?.AlvsDecisionNumber) && - (alvsDecision.Context.BtmsDecisionNumber >= _movement.AlvsDecisionStatus.Context?.BtmsDecisionNumber))) + if (alvsDecision.Context.DecisionComparison.HasValue()) { - _movement.AlvsDecisionStatus.DecisionStatus = alvsDecision.Context.DecisionStatus; + //Copy to top level status _movement.AlvsDecisionStatus.Context = alvsDecision.Context; } - else - { - logger.LogWarning("Decision AlvsDecisionNumber {0}, BtmsDecisionNumber {1} received out of sequence, not updating top level status. Top level status currently AlvsDecisionNumber {2}, BtmsDecisionNumber {3}", - alvsDecision.Context.AlvsDecisionNumber, alvsDecision.Context.BtmsDecisionNumber, - _movement.AlvsDecisionStatus.Context?.AlvsDecisionNumber, _movement.AlvsDecisionStatus.Context?.BtmsDecisionNumber); - } + + // if (_movement.AlvsDecisionStatus.Decisions.Count == 0 || ((alvsDecision.Context.AlvsDecisionNumber >=_movement. AlvsDecisionStatus.Context?.AlvsDecisionNumber) && + // (alvsDecision.Context.BtmsDecisionNumber > _movement.AlvsDecisionStatus.Context?.BtmsDecisionNumber)) || + // ((alvsDecision.Context.AlvsDecisionNumber > _movement.AlvsDecisionStatus.Context?.AlvsDecisionNumber) && + // (alvsDecision.Context.BtmsDecisionNumber >= _movement.AlvsDecisionStatus.Context?.BtmsDecisionNumber))) + // { + // _movement.AlvsDecisionStatus.DecisionStatus = alvsDecision.Context.DecisionStatus; + // _movement.AlvsDecisionStatus.Context = alvsDecision.Context; + // } + // else + // { + // logger.LogWarning("Decision AlvsDecisionNumber {0}, BtmsDecisionNumber {1} received out of sequence, not updating top level status. Top level status currently AlvsDecisionNumber {2}, BtmsDecisionNumber {3}", + // alvsDecision.Context.AlvsDecisionNumber, alvsDecision.Context.BtmsDecisionNumber, + // _movement.AlvsDecisionStatus.Context?.AlvsDecisionNumber, _movement.AlvsDecisionStatus.Context?.BtmsDecisionNumber); + // } _movement.AlvsDecisionStatus.Decisions.Add(alvsDecision); - _movement.AnalyseAlvsStatus(); + // _movement.AnalyseAlvsStatus(); _movement.AddLinkStatus(); } else @@ -179,13 +185,11 @@ private static string BuildNormalizedDecisionPath(string fullPath) private DecisionContext FindAlvsPairAndUpdate(CdsClearanceRequest clearanceRequest) { GuardNullMovement(); - - // This is an initial implementation - // we want to be smarter about how we 'pair' things, considering the same version of the import notifications - // can a BTMS decision be 'paired' to multiple ALVS decisions? - - var alvsDecision = _movement.AlvsDecisionStatus?.Decisions.Find( - d => d.Context.EntryVersionNumber == _movement.EntryVersionNumber); + + var alvsDecision = _movement.AlvsDecisionStatus?.Decisions + .SingleOrDefault(d => d.Context.DecisionComparison.HasValue()); + // .Find( + // d => d.Context.EntryVersionNumber == _movement.EntryVersionNumber); if (alvsDecision != null) { @@ -193,12 +197,12 @@ private DecisionContext FindAlvsPairAndUpdate(CdsClearanceRequest clearanceReque .Items! .SelectMany(i => i.Checks!.Select(c => new { Item = i, Check = c })) .ToDictionary(ic => (ic.Item.ItemNumber!.Value, ic.Check.CheckCode!), ic => ic.Check.DecisionCode!); - - //TODO : Is it possible for these BTMS decisions to arrive out of sequence? - // If so, we shouldn't just update the ALVS decision, we should check if it's a newer BTMS decision first. + + var shouldPair = clearanceRequest.Header!.DecisionNumber > alvsDecision.Context.DecisionComparison!.BtmsDecisionNumber; + + // Updates the pair status if we've received a newer BTMS decision than that already paired. + SetDecisionComparison(alvsDecision, shouldPair, clearanceRequest.Header!.DecisionNumber!.Value); - alvsDecision.Context.BtmsDecisionNumber = clearanceRequest.Header!.DecisionNumber!.Value; - alvsDecision.Context.Paired = true; alvsDecision.Context.Checks = alvsDecision .Context .Checks @@ -218,21 +222,19 @@ private DecisionContext FindAlvsPairAndUpdate(CdsClearanceRequest clearanceReque return new DecisionContext() { EntryVersionNumber = clearanceRequest.Header!.EntryVersionNumber!.Value, - BtmsDecisionNumber = clearanceRequest.Header!.DecisionNumber!.Value + // DecisionComparison = + // BtmsDecisionNumber = clearanceRequest.Header!.DecisionNumber!.Value }; } - private AlvsDecision FindBtmsPairAndUpdate(CdsClearanceRequest clearanceRequest) + private AlvsDecision FindBtmsPairAndUpdate(CdsClearanceRequest alvsDecision) { GuardNullMovement(); - // This is an initial implementation - // we want to be smarter about how we 'pair' things, considering the same version of the import notifications - // Q : can a BTMS decision be 'paired' to multiple ALVS decisions? Probably not... var btmsDecisions = _movement.Decisions? .Where(d => d.Header!.EntryVersionNumber == _movement.EntryVersionNumber) - .OrderBy(d => d.ServiceHeader!.ServiceCalled) + .OrderBy(d => d.Header!.EntryVersionNumber) .Reverse(); var mostRecentBtmsDecision = btmsDecisions?.FirstOrDefault(); @@ -241,36 +243,39 @@ private AlvsDecision FindBtmsPairAndUpdate(CdsClearanceRequest clearanceRequest) .AlvsDecisionStatus .Decisions .SingleOrDefault(d => - d.Context.Paired && d.Context.BtmsDecisionNumber == mostRecentBtmsDecision?.Header?.DecisionNumber + d.Context.DecisionComparison.HasValue() //&& d.Context.BtmsDecisionNumber == mostRecentBtmsDecision?.Header?.DecisionNumber ); - // We should only pair to this ALVS decision if we haven't already paired to a higher decision number - var shouldPair = mostRecentBtmsDecision.HasValue() - && (!pairedAlvsDecision.HasValue() || pairedAlvsDecision.Context.BtmsDecisionNumber < clearanceRequest?.Header?.DecisionNumber); + var shouldPair = mostRecentBtmsDecision.HasValue() && (!pairedAlvsDecision.HasValue() || + alvsDecision!.Header!.DecisionNumber + > pairedAlvsDecision!.Context.AlvsDecisionNumber); + + // var shouldPair = mostRecentBtmsDecision.HasValue(); + // && (!pairedAlvsDecision.HasValue() || + // pairedAlvsDecision.Context.BtmsDecisionNumber < clearanceRequest?.Header?.DecisionNumber); if (shouldPair && pairedAlvsDecision.HasValue()) { // A BTMS decision should only be paired with a single ALVS decision // So if its already paired, remove it. - pairedAlvsDecision!.Context.Paired = false; - pairedAlvsDecision!.Context.BtmsDecisionNumber = null; + SetDecisionComparison(pairedAlvsDecision, false, pairedAlvsDecision!.Context.DecisionComparison!.BtmsDecisionNumber!.Value); + // pairedAlvsDecision!.Context.Paired = false; + // pairedAlvsDecision!.Context.BtmsDecisionNumber = null; } var btmsChecks = mostRecentBtmsDecision ? - .Items! + .Items? .SelectMany(i => i.Checks!.Select(c => new { Item = i!, Check = c })) .ToDictionary(ic => (ic.Item.ItemNumber!.Value, ic.Check.CheckCode!), ic => ic.Check.DecisionCode!); - var alvsDecision = new AlvsDecision() + var alvsDecisionWithContext = new AlvsDecision() { - Decision = clearanceRequest!, //TODO : not sure how this can be null... + Decision = alvsDecision!, //TODO : not sure how this can be null... Context = new DecisionContext() { - AlvsDecisionNumber = clearanceRequest!.Header!.DecisionNumber!, - BtmsDecisionNumber = shouldPair ? mostRecentBtmsDecision!.Header!.DecisionNumber : null, - EntryVersionNumber = clearanceRequest!.Header!.EntryVersionNumber!.Value, - Paired = shouldPair, - Checks = clearanceRequest + AlvsDecisionNumber = alvsDecision!.Header!.DecisionNumber!, + EntryVersionNumber = alvsDecision!.Header!.EntryVersionNumber!.Value, + Checks = alvsDecision .Items!.SelectMany(i => i.Checks!.Select(c => new { Item = i, Check = c })) .Select(ic => { @@ -287,12 +292,30 @@ private AlvsDecision FindBtmsPairAndUpdate(CdsClearanceRequest clearanceRequest) } }; - if (mostRecentBtmsDecision != null) + SetDecisionComparison(alvsDecisionWithContext, shouldPair, mostRecentBtmsDecision?.Header?.DecisionNumber); + + if (shouldPair && mostRecentBtmsDecision.HasValue()) { - CompareDecisions(alvsDecision, mostRecentBtmsDecision); + CompareDecisions(alvsDecisionWithContext, mostRecentBtmsDecision); } - return alvsDecision; + return alvsDecisionWithContext; + } + + private void SetDecisionComparison(AlvsDecision decision, bool paired, int? btmsDecisionNumber) + { + logger.LogInformation("SetPairStatus {decision}, {paired} {btmsDecisionNumber}", + decision.Context.AlvsDecisionNumber, paired, btmsDecisionNumber); + + decision.Context.DecisionComparison = !paired ? null : new DecisionComparison() + { + Paired = paired, + BtmsDecisionNumber = btmsDecisionNumber + }; + // TODO: + // decision.Context.BtmsDecisionNumber = paired ? btmsDecisionNumber : null; + // decision.Context.DecisionStatus + // decision.Context.DecisionMatched } [MemberNotNull(nameof(_movement))] @@ -308,6 +331,12 @@ private void GuardNullMovement() private void CompareDecisions(AlvsDecision alvsDecision, CdsClearanceRequest btmsDecision) { GuardNullMovement(); + + if (!alvsDecision.Context.DecisionComparison.HasValue()) + { + throw new InvalidDataException("Should only be comparing when it's been paired"); + } + var alvsChecks = alvsDecision.Context.Checks; var btmsChecks = alvsDecision.Context.Checks; @@ -325,7 +354,6 @@ private void CompareDecisions(AlvsDecision alvsDecision, CdsClearanceRequest btm AnyHold = alvsChecks.Any(c => c.AlvsDecisionCode.StartsWith('H')) }; - alvsDecision.Context.BtmsCheckStatus = new StatusChecker() { AllMatch = btmsChecks.All(c => c.BtmsDecisionCode.HasValue() && c.BtmsDecisionCode.StartsWith('X')), @@ -341,23 +369,44 @@ private void CompareDecisions(AlvsDecision alvsDecision, CdsClearanceRequest btm }; var decisionStatus = DecisionStatusEnum.InvestigationNeeded; + var checksMatch = alvsChecks.All(c => c.AlvsDecisionCode == c.BtmsDecisionCode); - if (alvsDecision.Context.BtmsDecisionNumber == 0) + if (checksMatch) { - decisionStatus = DecisionStatusEnum.BtmsDecisionNotPresent; + alvsDecision.Context.DecisionComparison.DecisionMatched = true; + decisionStatus = DecisionStatusEnum.BtmsMadeSameDecisionAsAlvs; } - else + // if (_movement.AlvsDecisionStatus.Decisions.All(d => d.Context.DecisionMatched)) + // { + // decisionStatus = DecisionStatusEnum.BtmsMadeSameDecisionAsAlvs; + // } + else if (!_movement.ClearanceRequests.Exists(c => c.Header!.EntryVersionNumber == 1)) { - var checksMatch = alvsChecks.All(c => c.AlvsDecisionCode == c.BtmsDecisionCode); - - if (checksMatch) - { - alvsDecision.Context.DecisionMatched = true; - decisionStatus = DecisionStatusEnum.BtmsMadeSameDecisionAsAlvs; - } + decisionStatus = DecisionStatusEnum.AlvsClearanceRequestVersion1NotPresent; } + else if (!_movement.ClearanceRequests.AreNumbersComplete(c => c.Header!.EntryVersionNumber!.Value)) + { + decisionStatus = DecisionStatusEnum.AlvsClearanceRequestVersionsNotComplete; + } + else if (!_movement.AlvsDecisionStatus.Decisions.Exists(d => d.Context.AlvsDecisionNumber == 1)) + { + decisionStatus = DecisionStatusEnum.AlvsDecisionVersion1NotPresent; + } + else if (!_movement.AlvsDecisionStatus.Decisions.AreNumbersComplete(d => d.Context.AlvsDecisionNumber)) + { + decisionStatus = DecisionStatusEnum.AlvsDecisionVersionsNotComplete; + } + + // if (alvsDecision.Context.DecisionComparison.BtmsDecisionNumber == 0) + // { + // decisionStatus = DecisionStatusEnum.BtmsDecisionNotPresent; + // } + // else + // { + + // } - alvsDecision.Context.DecisionStatus = decisionStatus; + alvsDecision.Context.DecisionComparison.DecisionStatus = decisionStatus; } public Movement Build() diff --git a/Btms.Business/Extensions/MovementExtensions.cs b/Btms.Business/Extensions/MovementExtensions.cs index e86dc924..07a4ed70 100644 --- a/Btms.Business/Extensions/MovementExtensions.cs +++ b/Btms.Business/Extensions/MovementExtensions.cs @@ -30,33 +30,34 @@ public static bool AreNumbersComplete(this IEnumerable source, Func d.Context.DecisionMatched)) - { - alvsDecisionStatus = DecisionStatusEnum.BtmsMadeSameDecisionAsAlvs; - } - else if (!movement.ClearanceRequests.Exists(c => c.Header!.EntryVersionNumber == 1)) - { - alvsDecisionStatus = DecisionStatusEnum.AlvsClearanceRequestVersion1NotPresent; - } - else if (!movement.ClearanceRequests.AreNumbersComplete(c => c.Header!.EntryVersionNumber!.Value)) - { - alvsDecisionStatus = DecisionStatusEnum.AlvsClearanceRequestVersionsNotComplete; - } - else if (!movement.AlvsDecisionStatus.Decisions.Exists(d => d.Context.AlvsDecisionNumber == 1)) - { - alvsDecisionStatus = DecisionStatusEnum.AlvsDecisionVersion1NotPresent; - } - else if (!movement.AlvsDecisionStatus.Decisions.AreNumbersComplete(d => d.Context.AlvsDecisionNumber)) - { - alvsDecisionStatus = DecisionStatusEnum.AlvsDecisionVersionsNotComplete; - } - - movement.AlvsDecisionStatus.DecisionStatus = alvsDecisionStatus; - } + // public static void AnalyseAlvsStatus(this Movement movement) + // { + // var alvsDecisionStatus = DecisionStatusEnum.InvestigationNeeded; + // + // if (movement.AlvsDecisionStatus.Decisions.All(d => d.Context.DecisionMatched)) + // { + // alvsDecisionStatus = DecisionStatusEnum.BtmsMadeSameDecisionAsAlvs; + // } + // else if (!movement.ClearanceRequests.Exists(c => c.Header!.EntryVersionNumber == 1)) + // { + // alvsDecisionStatus = DecisionStatusEnum.AlvsClearanceRequestVersion1NotPresent; + // } + // else if (!movement.ClearanceRequests.AreNumbersComplete(c => c.Header!.EntryVersionNumber!.Value)) + // { + // alvsDecisionStatus = DecisionStatusEnum.AlvsClearanceRequestVersionsNotComplete; + // } + // else if (!movement.AlvsDecisionStatus.Decisions.Exists(d => d.Context.AlvsDecisionNumber == 1)) + // { + // alvsDecisionStatus = DecisionStatusEnum.AlvsDecisionVersion1NotPresent; + // } + // else if (!movement.AlvsDecisionStatus.Decisions.AreNumbersComplete(d => d.Context.AlvsDecisionNumber)) + // { + // alvsDecisionStatus = DecisionStatusEnum.AlvsDecisionVersionsNotComplete; + // } + // + // movement.AlvsDecisionStatus.DecisionStatus = alvsDecisionStatus; + // } + public static void AddLinkStatus(this Movement movement) { var linkStatus = MovementStatus.InvestigateStatus; diff --git a/Btms.Model/Cds/AlvsDecision.cs b/Btms.Model/Cds/AlvsDecision.cs index fa193f28..b3d1aac6 100644 --- a/Btms.Model/Cds/AlvsDecision.cs +++ b/Btms.Model/Cds/AlvsDecision.cs @@ -136,8 +136,8 @@ public enum DecisionStatusEnum { [EnumMember(Value = "Investigation Needed")] InvestigationNeeded, - [EnumMember(Value = "Btms Decision Not Present")] - BtmsDecisionNotPresent, + // [EnumMember(Value = "Btms Decision Not Present")] + // BtmsDecisionNotPresent, [EnumMember(Value = "Btms Made Same Decision As Alvs")] BtmsMadeSameDecisionAsAlvs, @@ -155,17 +155,12 @@ public enum DecisionStatusEnum { AlvsDecisionVersionsNotComplete } - public partial class SummarisedDecisionContext // { [Attr] [System.ComponentModel.Description("")] public int? AlvsDecisionNumber { get; set; } = default; - [Attr] - [System.ComponentModel.Description("")] - public int? BtmsDecisionNumber { get; set; } = default; - [Attr] [System.ComponentModel.Description("")] public int EntryVersionNumber { get; set; } = default; @@ -178,6 +173,17 @@ public partial class SummarisedDecisionContext // [System.ComponentModel.Description("")] public List? ImportNotifications { get; set; } + [Attr] + [System.ComponentModel.Description("")] + public DecisionComparison? DecisionComparison { get; set; } +} + +public class DecisionComparison +{ + [Attr] + [System.ComponentModel.Description("")] + public bool Paired { get; set; } = default; + [Attr] [System.ComponentModel.Description("")] [MongoDB.Bson.Serialization.Attributes.BsonRepresentation(MongoDB.Bson.BsonType.String)] @@ -186,14 +192,14 @@ public partial class SummarisedDecisionContext // [Attr] [System.ComponentModel.Description("")] public bool DecisionMatched { get; set; } = default; + + [Attr] + [System.ComponentModel.Description("")] + public int? BtmsDecisionNumber { get; set; } = default; } public partial class DecisionContext : SummarisedDecisionContext, IAuditContext // -{ - [Attr] - [System.ComponentModel.Description("")] - public bool Paired { get; set; } = default; - +{ [Attr] [System.ComponentModel.Description("")] public StatusChecker? AlvsCheckStatus { get; set; } @@ -209,14 +215,21 @@ public partial class AlvsDecisionStatus // [System.ComponentModel.Description("")] public List Decisions { get; set; } = new List(); - [Attr] - [System.ComponentModel.Description("")] - [MongoDB.Bson.Serialization.Attributes.BsonRepresentation(MongoDB.Bson.BsonType.String)] - public DecisionStatusEnum DecisionStatus { get; set; } = DecisionStatusEnum.NoAlvsDecisions; + // [Attr] + // [System.ComponentModel.Description("")] + // [MongoDB.Bson.Serialization.Attributes.BsonRepresentation(MongoDB.Bson.BsonType.String)] + // public DecisionStatusEnum DecisionStatus { get; set; } = DecisionStatusEnum.NoAlvsDecisions; [Attr] [System.ComponentModel.Description("")] - public SummarisedDecisionContext Context { get; set; } = new SummarisedDecisionContext(); + public SummarisedDecisionContext Context { get; set; } = new SummarisedDecisionContext() + { + //Initialise the DecisionComparison at the top level + DecisionComparison = new DecisionComparison() + { + DecisionStatus = DecisionStatusEnum.NoAlvsDecisions + } + }; } public partial class AlvsDecision // diff --git a/TestGenerator.IntegrationTesting.Backend/BtmsClient.cs b/TestGenerator.IntegrationTesting.Backend/BtmsClient.cs index 3def5d2b..f0fc2240 100644 --- a/TestGenerator.IntegrationTesting.Backend/BtmsClient.cs +++ b/TestGenerator.IntegrationTesting.Backend/BtmsClient.cs @@ -10,6 +10,7 @@ using Elastic.CommonSchema; using FluentAssertions; using idunno.Authentication.Basic; +using Microsoft.Extensions.Logging; using Xunit; namespace TestGenerator.IntegrationTesting.Backend.Fixtures; diff --git a/TestGenerator.IntegrationTesting.Backend/Fixtures/BackendFixture.cs b/TestGenerator.IntegrationTesting.Backend/Fixtures/BackendFixture.cs index 09e90433..2a829dc1 100644 --- a/TestGenerator.IntegrationTesting.Backend/Fixtures/BackendFixture.cs +++ b/TestGenerator.IntegrationTesting.Backend/Fixtures/BackendFixture.cs @@ -28,12 +28,14 @@ public class BackendFixture private BackendFactory WebApp { get; set; } private readonly int _consumerPushDelayMs; + private readonly ILogger Logger; public readonly ITestOutputHelper TestOutputHelper; public BackendFixture(ITestOutputHelper testOutputHelper, string databaseName, int consumerPushDelayMs = 1000, Dictionary? backendConfigOverrides = null) { TestOutputHelper = testOutputHelper; + Logger = TestOutputHelper.GetLogger(); _consumerPushDelayMs = consumerPushDelayMs; WebApp = new BackendFactory(databaseName, testOutputHelper, configOverrides: backendConfigOverrides); @@ -45,9 +47,7 @@ public async Task> LoadTestData(List test { await BtmsClient.ClearDb(); - var logger = TestOutputHelper.GetLogger(); - - await WebApp.Services.PushToConsumers(logger, testData.Select(d => d.Message), _consumerPushDelayMs); + await WebApp.Services.PushToConsumers(Logger, testData.Select(d => d.Message), _consumerPushDelayMs); return testData; } @@ -56,7 +56,8 @@ public async Task> LoadTestData(List test public class BackendFactory(string databaseName, ITestOutputHelper testOutputHelper, Dictionary? configOverrides = null) : WebApplicationFactory { private IMongoDbContext? mongoDbContext; - + private ILogger Logger = testOutputHelper.GetLogger(); + protected override void ConfigureWebHost(IWebHostBuilder builder) { // Any integration test overrides could be added here