From 3bfad556570495a812e2282e92574663c44ece7b Mon Sep 17 00:00:00 2001 From: James Gunn Date: Tue, 23 Jan 2024 16:46:02 +0000 Subject: [PATCH] Handle MQs that were imported into DQT and immediately deactivated (#1099) --- .../MandatoryQualificationDqtImportedEvent.cs | 1 + .../Services/TrsDataSync/TrsDataSyncHelper.cs | 68 ++++++++++--------- 2 files changed, 38 insertions(+), 31 deletions(-) diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.Core/Events/MandatoryQualificationDqtImportedEvent.cs b/TeachingRecordSystem/src/TeachingRecordSystem.Core/Events/MandatoryQualificationDqtImportedEvent.cs index aa7c7afaf..5bf8b66a8 100644 --- a/TeachingRecordSystem/src/TeachingRecordSystem.Core/Events/MandatoryQualificationDqtImportedEvent.cs +++ b/TeachingRecordSystem/src/TeachingRecordSystem.Core/Events/MandatoryQualificationDqtImportedEvent.cs @@ -7,4 +7,5 @@ public record MandatoryQualificationDqtImportedEvent : EventBase, IEventWithPers public string? Key { get; init; } public required Guid PersonId { get; init; } public required MandatoryQualification MandatoryQualification { get; init; } + public required int DqtState { get; init; } } diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.Core/Services/TrsDataSync/TrsDataSyncHelper.cs b/TeachingRecordSystem/src/TeachingRecordSystem.Core/Services/TrsDataSync/TrsDataSyncHelper.cs index 513621c16..1c5bbb990 100644 --- a/TeachingRecordSystem/src/TeachingRecordSystem.Core/Services/TrsDataSync/TrsDataSyncHelper.cs +++ b/TeachingRecordSystem/src/TeachingRecordSystem.Core/Services/TrsDataSync/TrsDataSyncHelper.cs @@ -1,4 +1,5 @@ using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Reactive.Linq; using System.Reactive.Subjects; using System.ServiceModel; @@ -873,11 +874,13 @@ private static List MapPersons(IEnumerable contacts) => contact } // If the record is deactivated, the final event should be a MandatoryQualificationDeletedEvent or MandatoryQualificationDqtDeactivatedEvent + // or we should have a MandatoryQualificationDqtImportedEvent (with inactive status) if (q.StateCode == dfeta_qualificationState.Inactive) { var lastEvent = events.Last(); - if (lastEvent is MandatoryQualificationDqtDeactivatedEvent or MandatoryQualificationDeletedEvent) + if (lastEvent is MandatoryQualificationDqtDeactivatedEvent or MandatoryQualificationDeletedEvent || + lastEvent is MandatoryQualificationDqtImportedEvent { DqtState: (int)dfeta_qualificationState.Inactive }) { mapped.DeletedOn = lastEvent.CreatedUtc; } @@ -897,20 +900,15 @@ private static List MapPersons(IEnumerable contacts) => contact EventBase MapCreatedEvent(EntityVersionInfo snapshot) { - if (snapshot.Entity.Attributes.ContainsKey(dfeta_qualification.Fields.dfeta_TRSEvent)) + if (TryDeserializeEventAttribute(snapshot.Entity.Attributes, dfeta_qualification.Fields.dfeta_TRSEvent, out var eventFromAttr)) { - var eventFromAttr = EventInfo.Deserialize(snapshot.Entity.dfeta_TRSEvent).Event; - - if (!(eventFromAttr is DummyEvent)) + if (!(eventFromAttr is MandatoryQualificationCreatedEvent)) { - if (!(eventFromAttr is MandatoryQualificationCreatedEvent)) - { - throw new InvalidOperationException( - $"Expected event to be {nameof(MandatoryQualificationCreatedEvent)} but got {eventFromAttr.GetEventName()}."); - } - - return eventFromAttr; + throw new InvalidOperationException( + $"Expected event to be {nameof(MandatoryQualificationCreatedEvent)} but got {eventFromAttr.GetEventName()}."); } + + return eventFromAttr; } return new MandatoryQualificationCreatedEvent() @@ -933,36 +931,27 @@ EventBase MapImportedEvent(EntityVersionInfo snapshot) CreatedUtc = snapshot.Timestamp, RaisedBy = Events.Models.RaisedByUserInfo.FromDqtUser(snapshot.UserId, snapshot.UserName), PersonId = snapshot.Entity.dfeta_PersonId.Id, - MandatoryQualification = GetEventMandatoryQualification(snapshot.Entity) + MandatoryQualification = GetEventMandatoryQualification(snapshot.Entity), + DqtState = (int)snapshot.Entity.StateCode! }; } EventBase? MapUpdatedEvent(EntityVersionInfo snapshot, EntityVersionInfo previous) { - if (snapshot.Entity.Attributes.ContainsKey(dfeta_qualification.Fields.dfeta_TRSEvent)) + if (TryDeserializeEventAttribute(snapshot.Entity.Attributes, dfeta_qualification.Fields.dfeta_TRSEvent, out var eventFromAttr)) { - var eventFromAttr = EventInfo.Deserialize(snapshot.Entity.dfeta_TRSEvent).Event; - - if (!(eventFromAttr is DummyEvent)) + // dfeta_TRSEvent may contain a stale value from a previous version + // (if the record was updated from the CRM UI then dfeta_TRSEvent won't have been updated). + // Check the previous events we've created; if we've seen it before we know we should ignore it this time. + if (!events.Any(e => e.EventId == eventFromAttr.EventId)) { - // dfeta_TRSEvent may contain a stale value from a previous version - // (if the record was updated from the CRM UI then dfeta_TRSEvent won't have been updated). - // Check the previous events we've created; if we've seen it before we know we should ignore it this time. - if (!events.Any(e => e.EventId == eventFromAttr.EventId)) - { - return eventFromAttr; - } + return eventFromAttr; } } - if (snapshot.Entity.Attributes.ContainsKey(dfeta_qualification.Fields.dfeta_TrsDeletedEvent)) + if (TryDeserializeEventAttribute(snapshot.Entity.Attributes, dfeta_qualification.Fields.dfeta_TrsDeletedEvent, out eventFromAttr)) { - var eventFromAttr = EventInfo.Deserialize(snapshot.Entity.dfeta_TrsDeletedEvent).Event; - - if (!(eventFromAttr is DummyEvent)) - { - return eventFromAttr; - } + return eventFromAttr; } if (snapshot.ChangedAttributes.Contains(dfeta_qualification.Fields.StateCode)) @@ -1057,6 +1046,23 @@ Events.Models.MandatoryQualification GetEventMandatoryQualification(dfeta_qualif EndDate = mapped.EndDate, }; } + + bool TryDeserializeEventAttribute(AttributeCollection attributes, string key, [NotNullWhen(true)] out EventBase? @event) + { + if (attributes.TryGetValue(key, out var attrValue) && attrValue is string serializedEvent) + { + var evt = EventInfo.Deserialize(serializedEvent); + + if (!(evt.Event is DummyEvent)) + { + @event = evt.Event; + return true; + } + } + + @event = default; + return false; + } } private async Task SyncEvents(IReadOnlyCollection events, NpgsqlTransaction transaction, CancellationToken cancellationToken)