Skip to content

Commit

Permalink
Merge pull request #1496 from DFE-Digital/add-remaining-creation-chan…
Browse files Browse the repository at this point in the history
…nel-endpoints

Add creation channels to remaining endpoints
  • Loading branch information
martyn-w authored Jan 23, 2025
2 parents 8de1d5a + 2ae66ef commit 72789e3
Show file tree
Hide file tree
Showing 15 changed files with 305 additions and 157 deletions.
69 changes: 60 additions & 9 deletions GetIntoTeachingApi/Models/Crm/Candidate.cs
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
using System;
using System.Collections.Generic;
using System.Linq;
using GetIntoTeachingApi.Attributes;
using GetIntoTeachingApi.Attributes;
using GetIntoTeachingApi.Services;
using GetIntoTeachingApi.Utils;
using Microsoft.Xrm.Sdk;
using Swashbuckle.AspNetCore.Annotations;
using System;
using System.Collections.Generic;
using System.Linq;

namespace GetIntoTeachingApi.Models.Crm
{
Expand Down Expand Up @@ -300,14 +300,11 @@ public enum RegistrationStatus
[EntityRelationship("dfe_contact_dfe_contactchannelcreation_ContactId", typeof(ContactChannelCreation))]
public List<ContactChannelCreation> ContactChannelCreations { get; set; } = new List<ContactChannelCreation>();

public Candidate()
: base()
{
public Candidate() : base(){
}

public Candidate(Entity entity, ICrmService crm, IServiceProvider serviceProvider)
: base(entity, crm, serviceProvider)
{
: base(entity, crm, serviceProvider){
}

public bool HasTeacherTrainingAdviser()
Expand Down Expand Up @@ -335,6 +332,60 @@ public bool IsPlanningToRetakeGcseMathsAndEnglish()
return new[] { PlanningToRetakeGcseMathsId, PlanningToRetakeGcseEnglishId }.All(g => g == (int)GcseStatus.HasOrIsPlanningOnRetaking);
}

/// <summary>
/// Allows the configuration of a contact channel for a
/// candidate based on the provided contactChannelCreator.
/// </summary>
public void ConfigureChannel(ICreateContactChannel contactChannelCreator, Guid? candidateId)
{
if (candidateId == null)
{
if (contactChannelCreator.CreationChannelSourceId.HasValue)
{
ChannelId = null;
AddContactChannelCreation(
channelCreation: !ContactChannelCreations.Any(),
contactChannelCreator: contactChannelCreator);
}
else
{
ChannelId = contactChannelCreator.DefaultContactCreationChannel;
}
}
else // Candidate record already exists
{
// NB: we do not update a candidate's ChannelId for an existing record
// NB: CreationChannel should always be false for existing candidates
if (contactChannelCreator.CreationChannelSourceId.HasValue)
{
AddContactChannelCreation(
channelCreation: false,
contactChannelCreator: contactChannelCreator);
}
}
}

/// <summary>
/// Allows automatic creation of an <see cref="ContactChannelCreation"/>
/// and assigns to the underlying collection of contact channel creations.
/// </summary>
/// <param name="channelCreation">
/// Predicates the context of the contact channel creation based on the candidate status.
/// </param>
/// <param name="contactChannelCreator">
/// The source of the contact channel creation request, a type
/// which implements the <see cref="ICreateContactChannel"/> interface.
/// </param>
private void AddContactChannelCreation(bool channelCreation, ICreateContactChannel contactChannelCreator)
{
ContactChannelCreations.Add(
ContactChannelCreation.Create(
creationChannel: channelCreation,
sourceId: contactChannelCreator.CreationChannelSourceId,
serviceId: contactChannelCreator.CreationChannelServiceId,
activityId: contactChannelCreator.CreationChannelActivityId));
}

public bool MagicLinkTokenExpired() => MagicLinkTokenExpiresAt == null || MagicLinkTokenExpiresAt < DateTime.UtcNow;
public bool MagicLinkTokenAlreadyExchanged() => MagicLinkTokenStatusId == (int)MagicLinkTokenStatus.Exchanged;
}
Expand Down
29 changes: 22 additions & 7 deletions GetIntoTeachingApi/Models/Crm/ContactChannelCreation.cs
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
using System;
using System.Text.Json.Serialization;
using FluentValidation;
using GetIntoTeachingApi.Attributes;
using GetIntoTeachingApi.Services;
using Microsoft.Xrm.Sdk;
using System;
using System.Text.Json.Serialization;

namespace GetIntoTeachingApi.Models.Crm
{
Expand Down Expand Up @@ -94,13 +93,29 @@ public enum CreationChannelActivity
[EntityField("dfe_creationchannelactivities", typeof(OptionSetValue))]
public int? CreationChannelActivityId { get; set; }

public ContactChannelCreation() : base()
{
public ContactChannelCreation() : base(){
}

public ContactChannelCreation(Entity entity, ICrmService crm, IServiceProvider serviceProvider)
: base(entity, crm, serviceProvider)
{
: base(entity, crm, serviceProvider){
}

/// <summary>
/// Factory method for creating a ContactChannelCreation instance.
/// </summary>
/// <returns>
/// A configured <see cref="ContactChannelCreation"/> instance.
/// </returns>
public static ContactChannelCreation Create(
bool creationChannel,
int? sourceId,
int? serviceId,
int? activityId) => new()
{
CreationChannel = creationChannel,
CreationChannelSourceId = sourceId,
CreationChannelServiceId = serviceId,
CreationChannelActivityId = activityId,
};
}
}
29 changes: 29 additions & 0 deletions GetIntoTeachingApi/Models/Crm/ICreateContactChannel.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
namespace GetIntoTeachingApi.Models.Crm
{
/// <summary>
/// Interface that defines the contract on which objects
/// that wish to invoke contact channel creation behaviour must adhere.
/// </summary>
public interface ICreateContactChannel
{
/// <summary>
/// Provides the default read-only contact creation channel integer value.
/// </summary>
int? DefaultContactCreationChannel { get; }

/// <summary>
/// Provides the ability to assign and retrieve the channel source creation identifier.
/// </summary>
int? CreationChannelSourceId { get; set; }

/// <summary>
/// Provides the ability to assign and retrieve the channel service creation identifier.
/// </summary>
int? CreationChannelServiceId { get; set; }

/// <summary>
/// Provides the ability to assign and retrieve the channel activity creation identifier.
/// </summary>
int? CreationChannelActivityId { get; set; }
}
}
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
using System;
using System.Text.Json.Serialization;
using GetIntoTeachingApi.Models.Crm;
using GetIntoTeachingApi.Models.Crm;
using GetIntoTeachingApi.Services;
using GetIntoTeachingApi.Utils;
using Swashbuckle.AspNetCore.Annotations;
using System;
using System.Text.Json.Serialization;

namespace GetIntoTeachingApi.Models.GetIntoTeaching
{
public class GetIntoTeachingCallback
public class GetIntoTeachingCallback : ICreateContactChannel
{
public Guid? CandidateId { get; set; }
[SwaggerSchema(WriteOnly = true)]
Expand All @@ -20,14 +20,22 @@ public class GetIntoTeachingCallback
[SwaggerSchema(WriteOnly = true)]
public DateTime? PhoneCallScheduledAt { get; set; }
public string TalkingPoints { get; set; }

[SwaggerSchema(WriteOnly = true)]
public int? CreationChannelSourceId { get; set; }
[SwaggerSchema(WriteOnly = true)]
public int? CreationChannelServiceId { get; set; }
[SwaggerSchema(WriteOnly = true)]
public int? CreationChannelActivityId { get; set; }

[JsonIgnore]
public Candidate Candidate => CreateCandidate();
[JsonIgnore]
public IDateTimeProvider DateTimeProvider { get; set; } = new DateTimeProvider();

public GetIntoTeachingCallback()
{
public int? DefaultContactCreationChannel => (int?)Candidate.Channel.GetIntoTeachingCallback;

public GetIntoTeachingCallback(){
}

public GetIntoTeachingCallback(Candidate candidate)
Expand Down Expand Up @@ -55,8 +63,7 @@ private Candidate CreateCandidate()
LastName = LastName,
AddressTelephone = AddressTelephone,
};

ConfigureChannel(candidate);
candidate.ConfigureChannel(contactChannelCreator: this, candidateId: CandidateId);
SchedulePhoneCall(candidate);
AcceptPrivacyPolicy(candidate);

Expand All @@ -79,14 +86,6 @@ private void SchedulePhoneCall(Candidate candidate)
}
}

private void ConfigureChannel(Candidate candidate)
{
if (CandidateId == null)
{
candidate.ChannelId = (int?)Candidate.Channel.GetIntoTeachingCallback;
}
}

private void AcceptPrivacyPolicy(Candidate candidate)
{
if (AcceptedPolicyId != null)
Expand Down
48 changes: 6 additions & 42 deletions GetIntoTeachingApi/Models/GetIntoTeaching/MailingListAddMember.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

namespace GetIntoTeachingApi.Models.GetIntoTeaching
{
public class MailingListAddMember
public class MailingListAddMember : ICreateContactChannel
{
public Guid? CandidateId { get; set; }
public Guid? QualificationId { get; set; }
Expand Down Expand Up @@ -45,8 +45,10 @@ public class MailingListAddMember
[JsonIgnore]
public IDateTimeProvider DateTimeProvider { get; set; } = new DateTimeProvider();

public MailingListAddMember()
{
public int? DefaultContactCreationChannel =>
ChannelId ?? (int?)Candidate.Channel.MailingList; // Use the assigned channel ID if available, else assign default.

public MailingListAddMember(){
}

public MailingListAddMember(Candidate candidate)
Expand Down Expand Up @@ -98,52 +100,14 @@ private Candidate CreateCandidate()
GdprConsentId = (int)Candidate.GdprConsent.Consent,
OptOutOfGdpr = false,
};

ConfigureChannel(candidate);
candidate.ConfigureChannel(contactChannelCreator: this, candidateId: CandidateId);
ConfigureSubscriptions(candidate);
AddQualification(candidate);
AcceptPrivacyPolicy(candidate);

return candidate;
}

private void ConfigureChannel(Candidate candidate)
{
if (CandidateId == null)
{
if (CreationChannelSourceId.HasValue)
{
candidate.ChannelId = null;
// NB: CreationChannel should be true only if it is the first ContactChannelCreation record
AddCandidateCreationChannel(candidate, !candidate.ContactChannelCreations.Any());
}
else
{
candidate.ChannelId = ChannelId ?? (int?)Candidate.Channel.MailingList;
}
}
else // Candidate record already exists
{
// NB: we do not update a candidate's ChannelId for an existing record
// NB: CreationChannel should always be false for existing candidates
if (CreationChannelSourceId.HasValue)
{
AddCandidateCreationChannel(candidate, false);
}
}
}

private void AddCandidateCreationChannel(Candidate candidate, bool creationChannel)
{
candidate.ContactChannelCreations.Add(new ContactChannelCreation()
{
CreationChannel = creationChannel,
CreationChannelSourceId = CreationChannelSourceId,
CreationChannelServiceId = CreationChannelServiceId,
CreationChannelActivityId = CreationChannelActivityId,
});
}

private void AddQualification(Candidate candidate)
{
candidate.Qualifications.Add(new CandidateQualification()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
using System;
using System.Linq;
using System.Text.Json.Serialization;
using GetIntoTeachingApi.Models.Crm;
using GetIntoTeachingApi.Models.Crm;
using GetIntoTeachingApi.Services;
using GetIntoTeachingApi.Utils;
using Swashbuckle.AspNetCore.Annotations;
using System;
using System.Linq;
using System.Text.Json.Serialization;

namespace GetIntoTeachingApi.Models.GetIntoTeaching
{
public class TeachingEventAddAttendee
public class TeachingEventAddAttendee : ICreateContactChannel
{
public Guid? CandidateId { get; set; }
public Guid? QualificationId { get; set; }
Expand All @@ -18,6 +18,13 @@ public class TeachingEventAddAttendee

[SwaggerSchema(WriteOnly = true)]
public int? ChannelId { get; set; }

[SwaggerSchema(WriteOnly = true)]
public int? CreationChannelSourceId { get; set; }
[SwaggerSchema(WriteOnly = true)]
public int? CreationChannelServiceId { get; set; }
[SwaggerSchema(WriteOnly = true)]
public int? CreationChannelActivityId { get; set; }

[SwaggerSchema(WriteOnly = true)]
public Guid? AcceptedPolicyId { get; set; }
Expand Down Expand Up @@ -48,8 +55,10 @@ public class TeachingEventAddAttendee
[JsonIgnore]
public IDateTimeProvider DateTimeProvider { get; set; } = new DateTimeProvider();

public TeachingEventAddAttendee()
{
public int? DefaultContactCreationChannel =>
ChannelId ?? (int?)Candidate.Channel.Event; // Use the assigned channel ID if available, else assign default.

public TeachingEventAddAttendee(){
}

public TeachingEventAddAttendee(Candidate candidate)
Expand Down Expand Up @@ -126,8 +135,7 @@ private Candidate CreateCandidate()
{
candidate.PreferredTeachingSubjectId = PreferredTeachingSubjectId;
}

ConfigureChannel(candidate);
candidate.ConfigureChannel(contactChannelCreator: this, candidateId: CandidateId);
AddTeachingEventRegistration(candidate);
AddQualification(candidate);
AcceptPrivacyPolicy(candidate);
Expand All @@ -136,14 +144,6 @@ private Candidate CreateCandidate()
return candidate;
}

private void ConfigureChannel(Candidate candidate)
{
if (CandidateId == null)
{
candidate.ChannelId = ChannelId ?? (int?)Candidate.Channel.Event;
}
}

private void AddQualification(Candidate candidate)
{
if (DegreeStatusId != null)
Expand Down
Loading

0 comments on commit 72789e3

Please sign in to comment.