Skip to content

Commit

Permalink
Add outbox messages for updating induction status
Browse files Browse the repository at this point in the history
  • Loading branch information
gunndabad committed Feb 12, 2025
1 parent d949efd commit 544eb63
Show file tree
Hide file tree
Showing 7 changed files with 167 additions and 4 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
using TeachingRecordSystem.Core.DataStore.Postgres;
using TeachingRecordSystem.Core.Services.DqtOutbox.Messages;

namespace TeachingRecordSystem.Core.Services.DqtOutbox.Handlers;

public class AddInductionExemptionMessageHandler(TrsDbContext dbContext, IClock clock) : IMessageHandler<AddInductionExemptionMessage>
{
public async Task HandleMessageAsync(AddInductionExemptionMessage message)
{
var person = await dbContext.Persons.SingleAsync(p => p.PersonId == message.PersonId);

var updatedBy = message.DqtUserId is not null && message.DqtUserName is not null
? EventModels.RaisedByUserInfo.FromDqtUser(message.DqtUserId.Value, message.DqtUserName)
: EventModels.RaisedByUserInfo.FromUserId(message.TrsUserId!.Value);

person.AddInductionExemptionReason(
message.ExemptionReasonId,
updatedBy: updatedBy,
now: clock.UtcNow,
out var @event);

if (@event is not null)
{
await dbContext.AddEventAndBroadcastAsync(@event);
}

await dbContext.SaveChangesAsync();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
using TeachingRecordSystem.Core.DataStore.Postgres;
using TeachingRecordSystem.Core.Services.DqtOutbox.Messages;

namespace TeachingRecordSystem.Core.Services.DqtOutbox.Handlers;

public class SetInductionRequiredToCompleteMessageHandler(TrsDbContext dbContext, IClock clock) : IMessageHandler<SetInductionRequiredToCompleteMessage>
{
public async Task HandleMessageAsync(SetInductionRequiredToCompleteMessage message)
{
var person = await dbContext.Persons.SingleAsync(p => p.PersonId == message.PersonId);

if (!InductionStatus.RequiredToComplete.IsHigherPriorityThan(person.InductionStatus))
{
return;
}

var updatedBy = message.DqtUserId is not null && message.DqtUserName is not null
? EventModels.RaisedByUserInfo.FromDqtUser(message.DqtUserId.Value, message.DqtUserName)
: EventModels.RaisedByUserInfo.FromUserId(message.TrsUserId!.Value);

person.SetInductionStatus(
InductionStatus.RequiredToComplete,
startDate: null,
completedDate: null,
exemptionReasonIds: [],
changeReason: null,
changeReasonDetail: null,
evidenceFile: null,
updatedBy: updatedBy,
now: clock.UtcNow,
out var @event);

if (@event is not null)
{
await dbContext.AddEventAndBroadcastAsync(@event);
}

await dbContext.SaveChangesAsync();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,6 @@ public object DeserializeMessage(string payload, string messageName)
var messageTypeName = $"{_messagesNamespace}{messageName}";
var messageType = typeof(MessageSerializer).Assembly.GetType(messageTypeName) ??
throw new ArgumentException("Could not find message type.", nameof(messageName));
return JsonSerializer.Deserialize(payload, messageType)!;
return JsonSerializer.Deserialize(payload, messageType, _serializerOptions)!;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
namespace TeachingRecordSystem.Core.Services.DqtOutbox.Messages;

public record AddInductionExemptionMessage
{
public required Guid PersonId { get; init; }
public required Guid ExemptionReasonId { get; init; }
public Guid? TrsUserId { get; init; }
public Guid? DqtUserId { get; init; }
public string? DqtUserName { get; init; }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
namespace TeachingRecordSystem.Core.Services.DqtOutbox.Messages;

public record SetInductionRequiredToCompleteMessage
{
public required Guid PersonId { get; init; }
public Guid? TrsUserId { get; init; }
public Guid? DqtUserId { get; init; }
public string? DqtUserName { get; init; }
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,14 @@ public async Task HandleOutboxMessageAsync(dfeta_TrsOutboxMessage outboxMessage)
{
await HandleMessageAsync<TrnRequestMetadataMessage, TrnRequestMetadataMessageHandler>(trnRequestMetadataMessage);
}
else if (message is AddInductionExemptionMessage addInductionExemptionMessage)
{
await HandleMessageAsync<AddInductionExemptionMessage, AddInductionExemptionMessageHandler>(addInductionExemptionMessage);
}
else if (message is SetInductionRequiredToCompleteMessage setInductionRequiredToCompleteMessage)
{
await HandleMessageAsync<SetInductionRequiredToCompleteMessage, SetInductionRequiredToCompleteMessageHandler>(setInductionRequiredToCompleteMessage);
}
else
{
throw new ArgumentException($"Unknown message type: '{outboxMessage.dfeta_MessageName}'.", nameof(outboxMessage.dfeta_MessageName));
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.PowerPlatform.Dataverse.Client;
using TeachingRecordSystem.Core.DataStore.Postgres;
using TeachingRecordSystem.Core.DataStore.Postgres.Models;
using TeachingRecordSystem.Core.Dqt;
using TeachingRecordSystem.Core.Dqt.Models;
using TeachingRecordSystem.Core.Services.DqtOutbox;
using TeachingRecordSystem.Core.Services.DqtOutbox.Messages;
using TeachingRecordSystem.Core.Services.TrsDataSync;
using TeachingRecordSystem.Core.Services.Webhooks;

namespace TeachingRecordSystem.Core.Tests.Services.DqtOutbox;

Expand Down Expand Up @@ -79,14 +82,74 @@ await DbFixture.WithDbContextAsync(async dbContext =>
Assert.Equal(message.DateOfBirth, trnRequestMetadata.DateOfBirth);
});
}

[Fact]
public async Task HandleOutboxMessage_ForAddInductionExemptionMessage_AddsExemptionReason()
{
// Arrange
var person = await TestData.CreatePersonAsync(p => p.WithTrn());

var message = new AddInductionExemptionMessage()
{
PersonId = person.PersonId,
ExemptionReasonId = InductionExemptionReason.PassedInWalesId,
TrsUserId = Core.DataStore.Postgres.Models.SystemUser.SystemUserId
};

var outboxMessage = new dfeta_TrsOutboxMessage()
{
dfeta_Payload = MessageSerializer.SerializeMessage(message, out var messageName),
dfeta_MessageName = messageName
};

// Act
await Handler.HandleOutboxMessageAsync(outboxMessage);

// Assert
await DbFixture.WithDbContextAsync(async dbContext =>
{
var updatedPerson = await dbContext.Persons.SingleAsync(p => p.PersonId == person.PersonId);
Assert.Equal(InductionStatus.Exempt, updatedPerson.InductionStatus);
Assert.Collection(updatedPerson.InductionExemptionReasonIds, id => Assert.Equal(InductionExemptionReason.PassedInWalesId, id));
});
}

[Fact]
public async Task HandleOutboxMessage_ForSetInductionRequiredToCompleteMessage_UpdatesInductionStatus()
{
// Arrange
var person = await TestData.CreatePersonAsync(p => p.WithTrn());

var message = new SetInductionRequiredToCompleteMessage()
{
PersonId = person.PersonId,
TrsUserId = Core.DataStore.Postgres.Models.SystemUser.SystemUserId
};

var outboxMessage = new dfeta_TrsOutboxMessage()
{
dfeta_Payload = MessageSerializer.SerializeMessage(message, out var messageName),
dfeta_MessageName = messageName
};

// Act
await Handler.HandleOutboxMessageAsync(outboxMessage);

// Assert
await DbFixture.WithDbContextAsync(async dbContext =>
{
var updatedPerson = await dbContext.Persons.SingleAsync(p => p.PersonId == person.PersonId);
Assert.Equal(InductionStatus.RequiredToComplete, updatedPerson.InductionStatus);
});
}
}

public class OutboxMessageHandlerFixture
{
public OutboxMessageHandlerFixture(
DbFixture dbFixture,
IOrganizationServiceAsync2 organizationService,
IDbContextFactory<TrsDbContext> dbContextFactory,
IConfiguration configuration,
ReferenceDataCache referenceDataCache,
FakeTrnGenerator trnGenerator,
ILoggerFactory loggerFactory)
Expand Down Expand Up @@ -116,12 +179,16 @@ public OutboxMessageHandlerFixture(
.AddSingleton(MessageSerializer)
.AddSingleton<TestData>()
.AddSingleton<OutboxMessageHandler>()
.AddSingleton(dbContextFactory)
.AddDatabase(configuration.GetPostgresConnectionString())
.AddTransient<TrsDbContext>(sp => sp.GetRequiredService<IDbContextFactory<TrsDbContext>>().CreateDbContext())
.AddSingleton(TestData)
.AddTransient<TrnRequestHelper>()
.AddCrmQueries()
.AddDefaultServiceClient(ServiceLifetime.Singleton, _ => organizationService);
.AddDefaultServiceClient(ServiceLifetime.Singleton, _ => organizationService)
.AddSingleton<WebhookMessageFactory>()
.AddSingleton<EventMapperRegistry>()
.AddSingleton<PersonInfoCache>()
.AddMemoryCache();

ServiceProvider = services.BuildServiceProvider();
}
Expand Down

0 comments on commit 544eb63

Please sign in to comment.