Skip to content

Commit

Permalink
Add Address fields onto v3 trn request (#1696)
Browse files Browse the repository at this point in the history
  • Loading branch information
MrKevJoy authored Nov 22, 2024
1 parent 8893ef8 commit 2490be9
Show file tree
Hide file tree
Showing 11 changed files with 300 additions and 10 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,13 @@ public record CreateTrnRequestCommand
public required string? NationalInsuranceNumber { get; init; }
public required bool? IdentityVerified { get; init; }
public required string? OneLoginUserSubject { get; init; }
public required Contact_GenderCode? GenderCode { get; set; }
public required string? AddressLine1 { get; set; }
public required string? AddressLine2 { get; set; }
public required string? AddressLine3 { get; set; }
public required string? City { get; set; }
public required string? Postcode { get; set; }
public required string? Country { get; set; }
}

public class CreateTrnRequestHandler(
Expand Down Expand Up @@ -144,14 +151,20 @@ await crmQueryDispatcher.ExecuteQueryAsync(new CreateContactQuery()
StatedMiddleName = command.MiddleName ?? "",
StatedLastName = command.LastName,
DateOfBirth = command.DateOfBirth,
Gender = Contact_GenderCode.Notavailable,
Gender = command.GenderCode ?? Contact_GenderCode.Notavailable,
EmailAddress = emailAddress,
NationalInsuranceNumber = NationalInsuranceNumberHelper.Normalize(command.NationalInsuranceNumber),
PotentialDuplicates = potentialDuplicates.Select(d => (Duplicate: d, HasActiveAlert: resultsWithActiveAlerts.Contains(d.ContactId))).ToArray(),
ApplicationUserName = currentApplicationUserName,
Trn = trn,
TrnRequestId = TrnRequestHelper.GetCrmTrnRequestId(currentApplicationUserId, command.RequestId),
OutboxMessages = outboxMessages
OutboxMessages = outboxMessages,
Address1Line1 = command.AddressLine1,
Address1Line2 = command.AddressLine2,
Address1Line3 = command.AddressLine3,
Address1City = command.City,
Address1PostalCode = command.Postcode,
Address1Country = command.Country
});

var status = trn is not null ? TrnRequestStatus.Completed : TrnRequestStatus.Pending;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
using TeachingRecordSystem.Core.Dqt.Models;

namespace TeachingRecordSystem.Api.V3.Core.SharedModels;

public enum Gender
{
Male = 1,
Female = 2,
Other = 3
}

public static class GenderExtensions
{
public static Contact_GenderCode ConvertToContact_GenderCode(this Gender input) =>
input.ConvertToEnumByValue<Gender, Contact_GenderCode>();

public static bool TryConvertToContact_GenderCode(this Gender input, out Contact_GenderCode result) =>
input.TryConvertToEnumByValue(out result);
}
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,14 @@ public async Task<IActionResult> CreateTrnRequestAsync(
EmailAddresses = request.Person.Email is string emailAddress ? [emailAddress] : [],
NationalInsuranceNumber = request.Person.NationalInsuranceNumber,
IdentityVerified = null,
OneLoginUserSubject = null
OneLoginUserSubject = null,
AddressLine1 = null,
AddressLine2 = null,
AddressLine3 = null,
City = null,
Postcode = null,
GenderCode = null,
Country = null
};
var result = await handler.HandleAsync(command);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,14 @@ public async Task<IActionResult> CreateTrnRequestAsync(
EmailAddresses = request.Person.EmailAddresses ?? [],
NationalInsuranceNumber = request.Person.NationalInsuranceNumber,
IdentityVerified = null,
OneLoginUserSubject = null
OneLoginUserSubject = null,
AddressLine1 = null,
AddressLine2 = null,
AddressLine3 = null,
City = null,
Postcode = null,
GenderCode = null,
Country = null
};
var result = await handler.HandleAsync(command);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,14 @@ public async Task<IActionResult> CreateTrnRequestAsync(
EmailAddresses = request.Person.EmailAddresses ?? [],
NationalInsuranceNumber = request.Person.NationalInsuranceNumber,
IdentityVerified = request.IdentityVerified,
OneLoginUserSubject = request.OneLoginUserSubject
OneLoginUserSubject = request.OneLoginUserSubject,
AddressLine1 = request.Person.Address?.AddressLine1,
AddressLine2 = request.Person.Address?.AddressLine2,
AddressLine3 = request.Person.Address?.AddressLine3,
GenderCode = request.Person.GenderCode.HasValue ? Core.SharedModels.GenderExtensions.ConvertToContact_GenderCode(request.Person.GenderCode!.Value) : null,
City = request.Person.Address?.City,
Postcode = request.Person.Address?.Postcode,
Country = request.Person.Address?.Country,
};
var result = await handler.HandleAsync(command);

Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,30 @@

using TeachingRecordSystem.Api.V3.Core.SharedModels;

namespace TeachingRecordSystem.Api.V3.VNext.Requests;

[GenerateVersionedDto(typeof(V20240606.Requests.CreateTrnRequestRequest))]
[GenerateVersionedDto(typeof(V20240606.Requests.CreateTrnRequestRequest), excludeMembers: "Person")]
public partial record CreateTrnRequestRequest
{
public bool IdentityVerified { get; init; }
public string? OneLoginUserSubject { get; init; }
public required CreateTrnRequestRequestPerson Person { get; init; }
}

[GenerateVersionedDto(typeof(V20240606.Requests.CreateTrnRequestRequestPerson))]
public partial record CreateTrnRequestRequestPerson
{
public CreateTrnRequestAddress? Address { get; init; }
public Gender? GenderCode { get; init; }
}

public class CreateTrnRequestAddress
{
public string? AddressLine1 { get; init; }
public string? AddressLine2 { get; init; }
public string? AddressLine3 { get; init; }
public string? City { get; init; }
public string? Postcode { get; init; }
public string? Country { get; init; }
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
using FluentValidation;
using TeachingRecordSystem.Api.V3.VNext.Requests;
using TeachingRecordSystem.Core.Dqt.Models;

namespace TeachingRecordSystem.Api.V3.VNext.Validators;

public class CreateTrnRequestRequestValidator : AbstractValidator<CreateTrnRequestRequest>
{
public CreateTrnRequestRequestValidator(IClock clock)
{
RuleFor(r => r.Person.Address!.AddressLine1)
.MaximumLength(AttributeConstraints.Contact.Address1_Line1MaxLength)
.When(r => r.Person.Address != null);

RuleFor(r => r.Person.Address!.AddressLine2)
.MaximumLength(AttributeConstraints.Contact.Address1_Line2MaxLength)
.When(r => r.Person.Address != null);

RuleFor(r => r.Person.Address!.AddressLine3)
.MaximumLength(AttributeConstraints.Contact.Address1_Line3MaxLength)
.When(r => r.Person.Address != null);

RuleFor(r => r.Person.Address!.City)
.MaximumLength(AttributeConstraints.Contact.Address1_CityMaxLength)
.When(r => r.Person.Address != null);

RuleFor(r => r.Person.Address!.Country)
.MaximumLength(AttributeConstraints.Contact.Address1_CountryMaxLength)
.When(r => r.Person.Address != null);

RuleFor(r => r.Person.Address!.Postcode)
.MaximumLength(AttributeConstraints.Contact.Address1_PostalCodeLength)
.When(r => r.Person.Address != null);

RuleFor(r => r.Person.GenderCode)
.IsInEnum();
}
}


Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,10 @@ public class CreateContactQuery : ICrmQuery<Guid>
public required string? Trn { get; init; }
public required string? TrnRequestId { get; init; }
public required IEnumerable<dfeta_TrsOutboxMessage> OutboxMessages { get; init; }
public required string? Address1Line1 { get; init; }
public required string? Address1Line2 { get; init; }
public required string? Address1Line3 { get; init; }
public required string? Address1City { get; init; }
public required string? Address1PostalCode { get; init; }
public required string? Address1Country { get; init; }
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,13 @@ public async Task<Guid> ExecuteAsync(CreateContactQuery query, IOrganizationServ
EMailAddress1 = query.EmailAddress,
dfeta_AllowPiiUpdatesFromRegister = false,
dfeta_TrnRequestID = query.TrnRequestId,
dfeta_TRN = query.Trn
dfeta_TRN = query.Trn,
Address1_Line1 = query.Address1Line1,
Address1_Line2 = query.Address1Line2,
Address1_Line3 = query.Address1Line3,
Address1_City = query.Address1City,
Address1_PostalCode = query.Address1PostalCode,
Address1_Country = query.Address1Country
};

if (query.Trn is null)
Expand All @@ -40,6 +46,12 @@ public async Task<Guid> ExecuteAsync(CreateContactQuery query, IOrganizationServ
contact.Attributes.Remove(Contact.Fields.dfeta_TRN);
}

if (query.Address1City is null)
{
// CRM plug-in explodes if AddressCity is specified but is null
contact.Attributes.Remove(Contact.Fields.Address1_City);
}

requestBuilder.AddRequest(new CreateRequest() { Target = contact });

foreach (var (duplicate, hasActiveAlert) in query.PotentialDuplicates)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
using TeachingRecordSystem.Api.V3.Core.SharedModels;
using TeachingRecordSystem.Api.V3.VNext.Requests;
using TeachingRecordSystem.Core.Dqt.Queries;
using TeachingRecordSystem.Core.Services.DqtOutbox;
using TeachingRecordSystem.Core.Services.DqtOutbox.Messages;
Expand Down Expand Up @@ -69,4 +71,133 @@ public async Task Post_CreatesOutboxMessageInCrm()
Assert.Equal(dateOfBirth, message.DateOfBirth);
});
}

[Fact]
public async Task Post_ValidAddressFields_PopulatesContactAddressFields()
{
// Arrange
var requestId = Guid.NewGuid().ToString();
var firstName = TestData.GenerateFirstName();
var middleName = TestData.GenerateMiddleName();
var lastName = TestData.GenerateLastName();
var dateOfBirth = TestData.GenerateDateOfBirth();
var email = TestData.GenerateUniqueEmail();
var identityVerified = true;
var oneLoginUserSubject = TestData.CreateOneLoginUserSubject();
var addressLine1 = Faker.Address.StreetName();
var addressLine2 = Faker.Address.StreetName();
var addressLine3 = Faker.Address.StreetName();
var postcode = Faker.Address.UkPostCode();
var country = Faker.Address.Country();
var gender = Gender.Female;
var city = Faker.Address.City();

var request = new HttpRequestMessage(HttpMethod.Post, "v3/trn-requests")
{
Content = CreateJsonContent(new
{
requestId = requestId,
person = new
{
firstName = firstName,
middleName = middleName,
lastName = lastName,
dateOfBirth = dateOfBirth,
emailAddresses = new[] { email },
address = new
{
addressLine1 = addressLine1,
addressLine2 = addressLine2,
addressLine3 = addressLine3,
city = city,
postcode = postcode,
country = country,
},
genderCode = gender
},
identityVerified = identityVerified,
oneLoginUserSubject = oneLoginUserSubject
})
};

// Act
var response = await GetHttpClientWithApiKey().SendAsync(request);

// Assert
await AssertEx.JsonResponseAsync(response, expectedStatusCode: StatusCodes.Status200OK);

var (crmQuery, _) = CrmQueryDispatcherSpy.GetSingleQuery<CreateContactQuery, Guid>();
Assert.Equal(addressLine1, crmQuery.Address1Line1);
Assert.Equal(addressLine2, crmQuery.Address1Line2);
Assert.Equal(addressLine3, crmQuery.Address1Line3);
Assert.Equal(city, crmQuery.Address1City);
Assert.Equal(postcode, crmQuery.Address1PostalCode);
Assert.Equal(country, crmQuery.Address1Country);
Assert.Equal(Contact_GenderCode.Female, crmQuery.Gender);
}

[Fact]
public async Task Post_AddressFieldsExceedingMaxLengths_ReturnsBadRequest()
{
// Arrange
var requestId = Guid.NewGuid().ToString();
var firstName = TestData.GenerateFirstName();
var middleName = TestData.GenerateMiddleName();
var lastName = TestData.GenerateLastName();
var dateOfBirth = TestData.GenerateDateOfBirth();
var email = TestData.GenerateUniqueEmail();
var identityVerified = true;
var oneLoginUserSubject = TestData.CreateOneLoginUserSubject();
var addressLine1 = new string('x', 255);
var addressLine2 = new string('x', 255);
var addressLine3 = new string('x', 255);
var postcode = new string('x', 255);
var country = new string('x', 255);
var gender = Gender.Female;
var city = new string('x', 255);

var request = new HttpRequestMessage(HttpMethod.Post, "v3/trn-requests")
{
Content = CreateJsonContent(new
{
requestId = requestId,
person = new
{
firstName = firstName,
middleName = middleName,
lastName = lastName,
dateOfBirth = dateOfBirth,
emailAddresses = new[] { email },
address = new
{
addressLine1 = addressLine1,
addressLine2 = addressLine2,
addressLine3 = addressLine3,
city = city,
postcode = postcode,
country = country,
},
genderCode = gender
},
identityVerified = identityVerified,
oneLoginUserSubject = oneLoginUserSubject
})
};

// Act
var response = await GetHttpClientWithApiKey().SendAsync(request);

// Assert
await AssertEx.JsonResponseHasValidationErrorsForPropertiesAsync(
response,
new Dictionary<string, string>()
{
{ $"{nameof(CreateTrnRequestRequest.Person)}.{nameof(CreateTrnRequestRequestPerson.Address)}.{nameof(CreateTrnRequestAddress.AddressLine1)}", $"The length of 'Person Address Address Line1' must be {AttributeConstraints.Contact.Address1_Line1MaxLength} characters or fewer. You entered 255 characters."},
{ $"{nameof(CreateTrnRequestRequest.Person)}.{nameof(CreateTrnRequestRequestPerson.Address)}.{nameof(CreateTrnRequestAddress.AddressLine2)}", $"The length of 'Person Address Address Line2' must be {AttributeConstraints.Contact.Address1_Line2MaxLength} characters or fewer. You entered 255 characters."},
{ $"{nameof(CreateTrnRequestRequest.Person)}.{nameof(CreateTrnRequestRequestPerson.Address)}.{nameof(CreateTrnRequestAddress.AddressLine3)}", $"The length of 'Person Address Address Line3' must be {AttributeConstraints.Contact.Address1_Line3MaxLength} characters or fewer. You entered 255 characters."},
{ $"{nameof(CreateTrnRequestRequest.Person)}.{nameof(CreateTrnRequestRequestPerson.Address)}.{nameof(CreateTrnRequestAddress.Postcode)}", $"The length of 'Person Address Postcode' must be {AttributeConstraints.Contact.Address1_PostalCodeLength} characters or fewer. You entered 255 characters."},
{ $"{nameof(CreateTrnRequestRequest.Person)}.{nameof(CreateTrnRequestRequestPerson.Address)}.{nameof(CreateTrnRequestAddress.City)}", $"The length of 'Person Address City' must be {AttributeConstraints.Contact.Address1_CityMaxLength} characters or fewer. You entered 255 characters."},
{ $"{nameof(CreateTrnRequestRequest.Person)}.{nameof(CreateTrnRequestRequestPerson.Address)}.{nameof(CreateTrnRequestAddress.Country)}", $"The length of 'Person Address Country' must be {AttributeConstraints.Contact.Address1_CountryMaxLength} characters or fewer. You entered 255 characters."},
});
}
}
Loading

0 comments on commit 2490be9

Please sign in to comment.