Skip to content

Commit

Permalink
Merge pull request #1856 from SkillsFundingAgency/FAI-2185-FaaJobEmai…
Browse files Browse the repository at this point in the history
…lError

FAI-2185 - Correct standard level to be string instead of int
  • Loading branch information
dashton82 authored Dec 19, 2024
2 parents d581979 + 26fb41e commit 3ecb400
Show file tree
Hide file tree
Showing 7 changed files with 121 additions and 71 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,14 @@ public void Then_The_Request_Url_Is_Correctly_Built(
List<int>? levels,
bool disabilityConfident)
{
var actual = new GetVacanciesRequest(lat, lon, distance, whatSearchTerm, pageNumber, pageSize, categories, levels, sort, disabilityConfident);
var actual = new GetVacanciesRequest(lat, lon, distance, whatSearchTerm, pageNumber, pageSize, categories, levels, sort, disabilityConfident, new List<VacancyDataSource>
{
VacancyDataSource.Nhs
});

actual.GetUrl
.Should()
.Be($"/api/vacancies?lat={lat}&lon={lon}&distanceInMiles={distance}&sort={sort}&pageNumber={pageNumber}&pageSize={pageSize}&categories={string.Join("&categories=", categories)}&levels={string.Join("&levels=", levels)}&searchTerm={whatSearchTerm}&disabilityConfident={disabilityConfident}");
.Be($"/api/vacancies?lat={lat}&lon={lon}&distanceInMiles={distance}&sort={sort}&pageNumber={pageNumber}&pageSize={pageSize}&categories={string.Join("&categories=", categories)}&levels={string.Join("&levels=", levels)}&searchTerm={whatSearchTerm}&disabilityConfident={disabilityConfident}&additionalDataSources=Nhs&postedInLastNumberOfDays=7");
actual.Version.Should().Be("2.0");
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,8 @@ public async Task Then_The_Vacancies_Not_Matches_Saved_Searches_Returns_Empty(
var actual = await sut.Handle(mockQuery, It.IsAny<CancellationToken>());

actual.Should().NotBeNull();
actual.SavedSearchResults.Count.Should().Be(0);
actual.SavedSearchResults.Count.Should().Be(3);
actual.SavedSearchResults.TrueForAll(c => c.Vacancies.Count == 0).Should().BeTrue();
actual.SavedSearchResults.FirstOrDefault()?.User.Should().NotBeNull();
actual.SavedSearchResults.FirstOrDefault()?.User?.Should().BeEquivalentTo(getCandidateApiResponse, options => options.Excluding(ex => ex.Status));
actual.PageIndex.Should().Be(mockGetSavedSearchesApiResponse.PageIndex);
Expand Down Expand Up @@ -251,7 +252,8 @@ public async Task When_SearchParameters_Lat_Long_Route_Categories_Null_Then_Gets
categories.Select(cat => cat.Id.ToString()).ToList(),
savedSearch.SearchParameters.SelectedLevelIds,
mockQuery.ApprenticeshipSearchResultsSortOrder,
savedSearch.SearchParameters.DisabilityConfident);
savedSearch.SearchParameters.DisabilityConfident,
new List<VacancyDataSource> { VacancyDataSource.Nhs });

mockFindApprenticeshipApiClient.Setup(client => client.Get<GetVacanciesResponse>(It.Is<GetVacanciesRequest>(c => c.GetUrl == getVacanciesExpectedUrl.GetUrl))).ReturnsAsync(getVacanciesResponse);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,48 +13,81 @@
using System.Net;
using PatchSavedSearch = SFA.DAS.FindApprenticeshipJobs.Domain.Models.PatchSavedSearch;

namespace SFA.DAS.FindApprenticeshipJobs.UnitTests.SavedSearches
namespace SFA.DAS.FindApprenticeshipJobs.UnitTests.SavedSearches;

[TestFixture]
public class WhenHandlingPostSendSavedSearchNotificationCommand
{
[TestFixture]
public class WhenHandlingPostSendSavedSearchNotificationCommand
[Test]
[MoqAutoData]
public async Task Then_The_SavedSearch_Is_Patched_LastEmailSent_Updated_And_Email_Sent(
PostSendSavedSearchNotificationCommand command,
EmailEnvironmentHelper emailEnvironmentHelper,
[Frozen] Mock<IFindApprenticeshipApiClient<FindApprenticeshipApiConfiguration>> findApprenticeshipApiClient,
[Frozen] Mock<INotificationService> notificationService,
PostSendSavedSearchNotificationCommandHandler handler)
{
[Test]
[MoqAutoData]
public async Task Then_The_SavedSearch_Is_Patched_LastEmailSent_Updated_And_Email_Sent(
var expectedPatchSavedSearchApiRequest =
new PatchSavedSearchApiRequest(command.Id, new JsonPatchDocument<PatchSavedSearch>());

findApprenticeshipApiClient
.Setup(x => x.PatchWithResponseCode(
It.Is<PatchSavedSearchApiRequest>(c =>
c.PatchUrl == expectedPatchSavedSearchApiRequest.PatchUrl
)))
.ReturnsAsync(new ApiResponse<string>(null!, HttpStatusCode.OK, string.Empty));


await handler.Handle(command, CancellationToken.None);

findApprenticeshipApiClient.Verify(x => x.PatchWithResponseCode(It.Is<PatchSavedSearchApiRequest>(c =>
c.PatchUrl.Contains(command.Id.ToString(), StringComparison.CurrentCultureIgnoreCase)
&& c.Data.Operations[1].path == "/LastRunDate"
&& DateTime.Parse(c.Data.Operations[1].value.ToString()).Date.Equals(DateTime.UtcNow.Date)
&& c.Data.Operations[0].path == "/EmailLastSendDate"
&& DateTime.Parse(c.Data.Operations[0].value.ToString()).Date.Equals(DateTime.UtcNow.Date))), Times.Once);

notificationService.Verify(x => x.Send(
It.Is<SendEmailCommand>(c =>
c.RecipientsAddress == command.User.Email
&& c.TemplateId == emailEnvironmentHelper.SavedSearchEmailNotificationTemplateId
&& c.Tokens["firstName"] == command.User.FirstName
&& c.Tokens["newApprenticeships"] == $"{command.Vacancies.Count.ToString()} new {(command.Vacancies.Count == 1 ? "apprenticeship" : "apprenticeships")}"
&& c.Tokens["searchAlertDescriptor"] == $"{command.SearchTerm} in {command.Location}"
&& !string.IsNullOrEmpty(c.Tokens["unsubscribeLink"])
&& !string.IsNullOrEmpty(c.Tokens["searchUrl"])
&& !string.IsNullOrEmpty(c.Tokens["searchParams"])
)
), Times.Once);
}

[Test]
[MoqAutoData]
public async Task Then_When_No_Vacancies_LastRun_Updated_And_No_Email_Sent(
PostSendSavedSearchNotificationCommand command,
EmailEnvironmentHelper emailEnvironmentHelper,
[Frozen] Mock<IFindApprenticeshipApiClient<FindApprenticeshipApiConfiguration>> findApprenticeshipApiClient,
[Frozen] Mock<INotificationService> notificationService,
PostSendSavedSearchNotificationCommandHandler handler)
{
var expectedPatchSavedSearchApiRequest =
new PatchSavedSearchApiRequest(command.Id, new JsonPatchDocument<PatchSavedSearch>());

findApprenticeshipApiClient
.Setup(x => x.PatchWithResponseCode(
It.Is<PatchSavedSearchApiRequest>(c =>
c.PatchUrl == expectedPatchSavedSearchApiRequest.PatchUrl
)))
.ReturnsAsync(new ApiResponse<string>(null!, HttpStatusCode.OK, string.Empty));


await handler.Handle(command, CancellationToken.None);

findApprenticeshipApiClient.Verify(x => x.PatchWithResponseCode(It.Is<PatchSavedSearchApiRequest>(c =>
c.PatchUrl.Contains(command.Id.ToString(), StringComparison.CurrentCultureIgnoreCase))), Times.Once);

notificationService.Verify(x => x.Send(
It.Is<SendEmailCommand>(c =>
c.RecipientsAddress == command.User.Email
&& c.TemplateId == emailEnvironmentHelper.SavedSearchEmailNotificationTemplateId
&& c.Tokens["firstName"] == command.User.FirstName
&& c.Tokens["newApprenticeships"] == $"{command.Vacancies.Count.ToString()} new {(command.Vacancies.Count == 1 ? "apprenticeship" : "apprenticeships")}"
&& c.Tokens["searchAlertDescriptor"] == $"{command.SearchTerm} in {command.Location}"
&& !string.IsNullOrEmpty(c.Tokens["unsubscribeLink"])
&& !string.IsNullOrEmpty(c.Tokens["searchUrl"])
&& !string.IsNullOrEmpty(c.Tokens["searchParams"])
)
), Times.Once);
}
{
command.Vacancies = [];
var expectedPatchSavedSearchApiRequest =
new PatchSavedSearchApiRequest(command.Id, new JsonPatchDocument<PatchSavedSearch>());

findApprenticeshipApiClient
.Setup(x => x.PatchWithResponseCode(
It.Is<PatchSavedSearchApiRequest>(c =>
c.PatchUrl == expectedPatchSavedSearchApiRequest.PatchUrl
)))
.ReturnsAsync(new ApiResponse<string>(null!, HttpStatusCode.OK, string.Empty));

await handler.Handle(command, CancellationToken.None);

findApprenticeshipApiClient.Verify(x => x.PatchWithResponseCode(It.Is<PatchSavedSearchApiRequest>(c =>
c.PatchUrl.Contains(command.Id.ToString(), StringComparison.CurrentCultureIgnoreCase)
&& c.Data.Operations[0].path == "/LastRunDate"
&& DateTime.Parse(c.Data.Operations[0].value.ToString()).Date.Equals(DateTime.UtcNow.Date))), Times.Once);

notificationService.Verify(x => x.Send(It.IsAny<SendEmailCommand>()), Times.Never);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
using SFA.DAS.FindApprenticeshipJobs.InnerApi.Requests;
using SFA.DAS.Notifications.Messages.Commands;
using SFA.DAS.SharedOuterApi.Configuration;
using SFA.DAS.SharedOuterApi.InnerApi.Responses;
using SFA.DAS.SharedOuterApi.Interfaces;

namespace SFA.DAS.FindApprenticeshipJobs.Application.Commands.SavedSearch.SendNotification
Expand All @@ -18,11 +17,22 @@ public record PostSendSavedSearchNotificationCommandHandler(
public async Task<Unit> Handle(PostSendSavedSearchNotificationCommand command, CancellationToken cancellationToken)
{
var jsonPatchDocument = new JsonPatchDocument<PatchSavedSearch>();
jsonPatchDocument.Replace(x => x.EmailLastSendDate, DateTime.UtcNow);
if (command.Vacancies.Count != 0)
{
jsonPatchDocument.Replace(x => x.EmailLastSendDate, DateTime.UtcNow);
}

jsonPatchDocument.Replace(x => x.LastRunDate, DateTime.UtcNow);

var patchRequest = new PatchSavedSearchApiRequest(command.Id, jsonPatchDocument);

if (command.Vacancies.Count == 0)
{
await FindApprenticeshipApiClient.PatchWithResponseCode(patchRequest);
return Unit.Value;
}


var vacanciesEmailSnippet = EmailTemplateBuilder.GetSavedSearchVacanciesSnippet(EmailEnvironmentHelper,
command.Vacancies, command.Location != null);

Expand Down Expand Up @@ -58,7 +68,5 @@ await Task.WhenAll(

return Unit.Value;
}


}
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,14 @@ public async Task<GetSavedSearchesQueryResult> Handle(GetSavedSearchesQuery requ
TotalCount = savedSearchResponse.TotalCount,
SavedSearchResults = []
};

var routesTask = CourseService.GetRoutes();
var levelsTask = CourseService.GetLevels();

await Task.WhenAll(routesTask, levelsTask);
var routesList = routesTask.Result;
var levelsList = levelsTask.Result;

foreach (var savedSearch in savedSearchResponse.SavedSearches)
{
var candidate =
Expand All @@ -40,14 +47,6 @@ await CandidateApiClient.Get<GetCandidateApiResponse>(

if (candidate == null || candidate.Status == UserStatus.Deleted) continue;

var routesTask = CourseService.GetRoutes();
var levelsTask = CourseService.GetLevels();

await Task.WhenAll(routesTask, levelsTask);

var routesList = routesTask.Result;
var levelsList = levelsTask.Result;

var categories = routesList.Routes
.Where(route =>
savedSearch.SearchParameters.SelectedRouteIds != null
Expand Down Expand Up @@ -79,9 +78,14 @@ await CandidateApiClient.Get<GetCandidateApiResponse>(
categories.Select(cat => cat.Id.ToString()).ToList(),
savedSearch.SearchParameters.SelectedLevelIds,
request.ApprenticeshipSearchResultsSortOrder,
savedSearch.SearchParameters.DisabilityConfident));
savedSearch.SearchParameters.DisabilityConfident,
new List<VacancyDataSource>
{
VacancyDataSource.Nhs
}));

if (vacanciesResponse != null && vacanciesResponse.ApprenticeshipVacancies.Any())
if (vacanciesResponse != null)
{
searchResultList.Add(new GetSavedSearchesQueryResult.SearchResult
{
Id = savedSearch.Id,
Expand All @@ -97,6 +101,7 @@ await CandidateApiClient.Get<GetCandidateApiResponse>(
(GetSavedSearchesQueryResult.SearchResult.ApprenticeshipVacancy) x)
.ToList()
});
}
}

return new GetSavedSearchesQueryResult
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using SFA.DAS.SharedOuterApi.Interfaces;
using System.Web;
using SFA.DAS.SharedOuterApi.Interfaces;
using SFA.DAS.FindApprenticeshipJobs.Domain.Models;

namespace SFA.DAS.FindApprenticeshipJobs.InnerApi.Requests
Expand All @@ -15,6 +16,7 @@ public class GetVacanciesRequest : IGetApiRequest
private readonly string _searchTerm;
private readonly VacancySort _sort;
private readonly bool _disabilityConfident;
private readonly string _additionalDataSources;

public GetVacanciesRequest(
double? lat,
Expand All @@ -26,7 +28,8 @@ public GetVacanciesRequest(
IReadOnlyCollection<string> categories,
IReadOnlyCollection<int>? levels,
VacancySort sort,
bool disabilityConfident)
bool disabilityConfident,
IReadOnlyCollection<VacancyDataSource> additionalDataSources)
{
_lat = lat;
_lon = lon;
Expand All @@ -38,10 +41,15 @@ public GetVacanciesRequest(
_levels = levels is { Count: > 0 } ? string.Join("&levels=", levels) : string.Empty;
_searchTerm = searchTerm;
_disabilityConfident = disabilityConfident;

_additionalDataSources = additionalDataSources is { Count: > 0 } ? string.Join("&additionalDataSources=", additionalDataSources) : string.Empty;
}

public string Version => "2.0";
public string GetUrl => $"/api/vacancies?lat={_lat}&lon={_lon}&distanceInMiles={_distance}&sort={_sort}&pageNumber={_pageNumber}&pageSize={_pageSize}&categories={_categories}&levels={_levels}&searchTerm={_searchTerm}&disabilityConfident={_disabilityConfident}";
public string GetUrl => $"/api/vacancies?lat={_lat}&lon={_lon}&distanceInMiles={_distance}&sort={_sort}&pageNumber={_pageNumber}&pageSize={_pageSize}&categories={_categories}&levels={_levels}&searchTerm={_searchTerm}&disabilityConfident={_disabilityConfident}&additionalDataSources={_additionalDataSources}&postedInLastNumberOfDays=7";
}
}
public enum VacancyDataSource
{
Raa,
Nhs,
}
Original file line number Diff line number Diff line change
@@ -1,15 +1,9 @@
using System.Text.Json.Serialization;
using System.Text.Json.Serialization;

namespace SFA.DAS.FindApprenticeshipJobs.InnerApi.Responses
{
public class GetVacanciesResponse
{
[JsonPropertyName("total")]
public long Total { get; set; }

[JsonPropertyName("totalFound")]
public long TotalFound { get; set; }

[JsonPropertyName("apprenticeshipVacancies")]
public IEnumerable<GetVacanciesListItem> ApprenticeshipVacancies { get; set; } = [];
}
Expand Down Expand Up @@ -49,15 +43,12 @@ public class GetVacanciesListItem
[JsonPropertyName("distance")]
public decimal? Distance { get; set; }

[JsonPropertyName("score")]
public double Score { get; set; }

[JsonPropertyName("standardTitle")]
public string CourseTitle { get; set; }

[JsonPropertyName("standardLevel")]
public int CourseLevel { get; set; }

public string CourseLevel { get; set; }
[JsonPropertyName("vacancySource")]
public string VacancySource { get; set; }
}
Expand Down

0 comments on commit 3ecb400

Please sign in to comment.