Skip to content

Commit 5081996

Browse files
authored
Merge branch 'main' into feat/dtoss-5226-production-environment-pipelines-3
2 parents 4964366 + 8137a57 commit 5081996

16 files changed

Lines changed: 226 additions & 305 deletions

File tree

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ appsettings.json
6363
application/CohortManager/SampleData/
6464
*.csv
6565
*.parquet
66+
*.xml
6667
!tests/UnitTests/CaasIntegrationTests/receiveCaasFileTest/*.parquet
6768

6869
# csv to sql statement scripts

application/CohortManager/compose.core.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ services:
5858
- ExceptionFunctionURL=http://create-exception:7070/api/CreateException
5959
- RetrievePdsDemographicURL=http://retrieve-pds-demographic:8082/api/RetrievePDSDemographic
6060
- UnsubscribeNemsSubscriptionUrl=http://manage-nems-subscription:9081/api/Unsubscribe
61-
- ParticipantDemographicDataServiceURL=http://participant-demographic-data-service:7993/api/ParticipantDemographicDataService
61+
- DemographicDataServiceURL=http://participant-demographic-data-service:7993/api/ParticipantDemographicDataService
6262
- ServiceBusConnectionString_client_internal=Endpoint=sb://service-bus;SharedAccessKeyName=RootManageSharedAccessKey;SharedAccessKey=SAS_KEY_VALUE;UseDevelopmentEmulator=true;
6363
- ParticipantManagementTopic=participant-management-topic
6464

application/CohortManager/src/Functions/DemographicServices/ManageNemsSubscription/ManageNemsSubscription.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,13 +49,13 @@ public async Task<HttpResponseData> Subscribe([HttpTrigger(AuthorizationLevel.An
4949

5050
string? nhsNumber = req.Query["nhsNumber"];
5151

52-
if (!ValidationHelper.ValidateNHSNumber(nhsNumber))
52+
if (!ValidationHelper.ValidateNHSNumber(nhsNumber!))
5353
{
5454
_logger.LogError("NHS number is required and must be valid format");
5555
return await _createResponse.CreateHttpResponseWithBodyAsync(HttpStatusCode.BadRequest, req, "NHS number is required and must be valid format.");
5656
}
5757

58-
var result = await _subscriptionManager.CreateAndSendSubscriptionAsync(nhsNumber);
58+
var result = await _subscriptionManager.CreateAndSendSubscriptionAsync(nhsNumber!);
5959

6060
if (!result.Success)
6161
{

application/CohortManager/src/Functions/DemographicServices/RetrievePDSDemographic/RetrievePDSDemographic.cs

Lines changed: 4 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ namespace NHS.CohortManager.DemographicServices;
1212
using Microsoft.Extensions.Options;
1313
using System.Threading.Tasks;
1414
using Model;
15+
using System.Net.Http.Json;
16+
using Hl7.Fhir.Support;
1517

1618
public class RetrievePdsDemographic
1719
{
@@ -71,12 +73,8 @@ public async Task<HttpResponseData> Run([HttpTrigger(AuthorizationLevel.Anonymou
7173

7274
if (response.StatusCode == HttpStatusCode.NotFound)
7375
{
74-
var demographicRecordDeletedFromDatabase = await DeleteDemographicRecord(nhsNumber);
75-
if (!demographicRecordDeletedFromDatabase)
76-
{
77-
return _createResponse.CreateHttpResponse(HttpStatusCode.NotFound, req, "could not delete record from database. See logs for more details.");
78-
}
79-
return _createResponse.CreateHttpResponse(HttpStatusCode.NotFound, req, "Record not found in PDS and successfully removed from cohort manager database.");
76+
var pdsErrorResponse = await response.Content.ReadAsStringAsync();
77+
return _createResponse.CreateHttpResponse(HttpStatusCode.NotFound, req, pdsErrorResponse);
8078
}
8179

8280
response.EnsureSuccessStatusCode();
@@ -129,36 +127,4 @@ private async Task<bool> UpsertDemographicRecordFromPDS(ParticipantDemographic p
129127
_logger.LogError("Failed to update Participant Demographic.");
130128
return false;
131129
}
132-
133-
private async Task<bool> DeleteDemographicRecord(string nhsNumber)
134-
{
135-
var nhsNumberParsed = long.TryParse(nhsNumber, out long parsedNhsNumber);
136-
if (!nhsNumberParsed)
137-
{
138-
_logger.LogError("could not parse nhs number when trying to get record for deletion.");
139-
return false;
140-
}
141-
var oldParticipantDemographic = await _participantDemographicClient.GetSingleByFilter(i => i.NhsNumber == parsedNhsNumber);
142-
143-
if (oldParticipantDemographic == null)
144-
{
145-
146-
_logger.LogWarning("Failed to delete Participant Demographic as record did not exist in database.");
147-
return false;
148-
}
149-
150-
_logger.LogInformation("Participant Demographic record found, attempting to delete Participant Demographic.");
151-
bool updateSuccess = await _participantDemographicClient.Delete(oldParticipantDemographic.ParticipantId.ToString());
152-
153-
if (updateSuccess)
154-
{
155-
_logger.LogInformation("Successfully deleted Participant Demographic.");
156-
return true;
157-
}
158-
159-
_logger.LogError("Failed to delete Participant Demographic.");
160-
return false;
161-
}
162-
163-
164130
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
namespace NHS.Screening.ProcessNemsUpdate;
2+
3+
public class PdsCoding
4+
{
5+
public string? code { get; set; }
6+
public string? display { get; set; }
7+
public string? system { get; set; }
8+
public string? version { get; set; }
9+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
namespace NHS.Screening.ProcessNemsUpdate;
2+
3+
public class PdsErrorResponse
4+
{
5+
public List<PdsIssue>? issue { get; set; }
6+
public string? resourceType { get; set; }
7+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
namespace NHS.Screening.ProcessNemsUpdate;
2+
3+
public class PdsIssue
4+
{
5+
public string? code { get; set; }
6+
public PdsErrorDetails? details { get; set; }
7+
public string? severity { get; set; }
8+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
namespace NHS.Screening.ProcessNemsUpdate;
2+
3+
public class PdsErrorDetails
4+
{
5+
public List<PdsCoding>? coding { get; set; }
6+
}
7+

application/CohortManager/src/Functions/NemsSubscriptionService/ProcessNemsUpdate/ProcessNemsUpdate.cs

Lines changed: 76 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
using System.Collections.Concurrent;
44
using System.Collections.Specialized;
5+
using System.Net.Http.Json;
56
using System.Text;
67
using System.Text.Json;
78
using Common;
@@ -11,6 +12,7 @@
1112
using Microsoft.Extensions.Options;
1213
using Model;
1314
using DataServices.Client;
15+
using FluentValidation.Validators;
1416

1517
public class ProcessNemsUpdate
1618
{
@@ -61,61 +63,35 @@ public async Task Run([BlobTrigger("nems-updates/{name}", Connection = "nemsmesh
6163
{
6264
try
6365
{
64-
string? nhsNumber = await GetNhsNumberFromFile(blobStream, name);
66+
var nhsNumber = await GetNhsNumberFromFile(blobStream, name);
6567

66-
if (nhsNumber == null)
67-
{
68-
_logger.LogInformation("There is no NHS number, unable to continue.");
69-
return;
70-
}
71-
72-
if (!ValidationHelper.ValidateNHSNumber(nhsNumber))
68+
if (!ValidationHelper.ValidateNHSNumber(nhsNumber!))
7369
{
70+
_logger.LogError("There was a problem parsing the NHS number from blob store in the ProcessNemsUpdate function");
7471
throw new InvalidDataException("Invalid NHS Number");
7572
}
76-
nhsNumberLong = long.Parse(nhsNumber);
77-
78-
string? pdsRecord = await RetrievePdsRecord(nhsNumber);
73+
nhsNumberLong = long.Parse(nhsNumber!);
7974

80-
if (pdsRecord == null)
75+
var pdsResponse = await RetrievePdsRecord(nhsNumber!);
76+
if (pdsResponse!.StatusCode == System.Net.HttpStatusCode.NotFound)
8177
{
82-
_logger.LogInformation("There is no PDS record, unable to continue.");
78+
await ProcessPdsResponse(pdsResponse, nhsNumber!);
79+
// we can stop processing here as we know that not found means the participant ether needed an update or they were actually not found
8380
return;
8481
}
8582

86-
var retrievedPdsRecord = JsonSerializer.Deserialize<PdsDemographic>(pdsRecord);
83+
pdsResponse.EnsureSuccessStatusCode();
84+
85+
var retrievedPdsRecord = await pdsResponse.Content.ReadFromJsonAsync<PdsDemographic>();
8786

8887
if (retrievedPdsRecord?.NhsNumber == nhsNumber)
8988
{
9089
_logger.LogInformation("NHS numbers match, processing the retrieved PDS record.");
91-
await ProcessRecord(retrievedPdsRecord);
90+
await ProcessRecord(new Participant(retrievedPdsRecord!));
9291
}
93-
9492
else
9593
{
96-
var supersededRecord = new PdsDemographic()
97-
{
98-
NhsNumber = nhsNumber,
99-
SupersededByNhsNumber = retrievedPdsRecord?.NhsNumber,
100-
PrimaryCareProvider = null,
101-
ReasonForRemoval = "ORR",
102-
RemovalEffectiveFromDate = DateTime.UtcNow.Date.ToString("yyyyMMdd")
103-
};
104-
105-
_logger.LogInformation("NHS numbers do not match, processing the superseded record.");
106-
await ProcessRecord(supersededRecord);
107-
108-
/*information exception raised for RuleId 60 and Rule name 'SupersededNhsNumber'*/
109-
var ruleId = 60; // Rule 60 is for Superseded rule
110-
var ruleName = "SupersededNhsNumber"; //Superseded rule name
111-
await _exceptionHandler.CreateTransformExecutedExceptions(supersededRecord.ToCohortDistributionParticipant(), ruleName, ruleId);
112-
113-
var unsubscribedFromNems = await UnsubscribeNems(nhsNumber);
114-
115-
if (unsubscribedFromNems)
116-
{
117-
_logger.LogInformation("Successfully unsubscribed from NEMS.");
118-
}
94+
await UnsubscribeFromNems(nhsNumber!, retrievedPdsRecord!);
11995
}
12096

12197
}
@@ -126,6 +102,56 @@ public async Task Run([BlobTrigger("nems-updates/{name}", Connection = "nemsmesh
126102

127103
}
128104

105+
private async Task ProcessPdsResponse(HttpResponseMessage pdsResponse, string nhsNumber)
106+
{
107+
var errorResponse = await pdsResponse!.Content.ReadFromJsonAsync<PdsErrorResponse>();
108+
// we now create a record as an update record and send to the manage participant function. Reason for removal for date should be today and the reason for remove of ORR
109+
if (errorResponse!.issue!.FirstOrDefault()!.details!.coding!.FirstOrDefault()!.code == "INVALIDATED_RESOURCE")
110+
{
111+
var pdsDemographic = new PdsDemographic()
112+
{
113+
NhsNumber = nhsNumber,
114+
PrimaryCareProvider = null,
115+
ReasonForRemoval = "ORR",
116+
RemovalEffectiveFromDate = DateTime.UtcNow.Date.ToString("yyyyMMdd")
117+
};
118+
var participant = new Participant(pdsDemographic);
119+
participant.RecordType = Actions.Removed;
120+
//sends record for an update
121+
await ProcessRecord(participant);
122+
return;
123+
}
124+
_logger.LogError("the PDS function has returned a 404 error. function now stopping processing");
125+
126+
}
127+
128+
private async Task UnsubscribeFromNems(string nhsNumber, PdsDemographic retrievedPdsRecord)
129+
{
130+
var supersededRecord = new PdsDemographic()
131+
{
132+
NhsNumber = nhsNumber,
133+
SupersededByNhsNumber = retrievedPdsRecord?.NhsNumber,
134+
PrimaryCareProvider = null,
135+
ReasonForRemoval = "ORR",
136+
RemovalEffectiveFromDate = DateTime.UtcNow.Date.ToString("yyyyMMdd")
137+
};
138+
139+
_logger.LogInformation("NHS numbers do not match, processing the superseded record.");
140+
await ProcessRecord(new Participant(supersededRecord));
141+
142+
/*information exception raised for RuleId 60 and Rule name 'SupersededNhsNumber'*/
143+
var ruleId = 60; // Rule 60 is for Superseded rule
144+
var ruleName = "SupersededNhsNumber"; //Superseded rule name
145+
await _exceptionHandler.CreateTransformExecutedExceptions(supersededRecord.ToCohortDistributionParticipant(), ruleName, ruleId);
146+
147+
var unsubscribedFromNems = await UnsubscribeNems(nhsNumber);
148+
149+
if (unsubscribedFromNems)
150+
{
151+
_logger.LogInformation("Successfully unsubscribed from NEMS.");
152+
}
153+
}
154+
129155
private async Task<string?> GetNhsNumberFromFile(Stream blobStream, string name)
130156
{
131157
try
@@ -139,7 +165,7 @@ public async Task Run([BlobTrigger("nems-updates/{name}", Connection = "nemsmesh
139165
}
140166

141167
// Determine format based on file extension and call appropriate parser
142-
if (name.EndsWith(".xml", StringComparison.OrdinalIgnoreCase))
168+
if (name.EndsWith(".xml", System.StringComparison.OrdinalIgnoreCase))
143169
{
144170
return _fhirPatientDemographicMapper.ParseFhirXmlNhsNumber(blobJson);
145171
}
@@ -156,41 +182,32 @@ public async Task Run([BlobTrigger("nems-updates/{name}", Connection = "nemsmesh
156182
}
157183
}
158184

159-
private async Task<string?> RetrievePdsRecord(string nhsNumber)
185+
private async Task<HttpResponseMessage> RetrievePdsRecord(string nhsNumber)
160186
{
161-
try
187+
var queryParams = new Dictionary<string, string>()
162188
{
163-
var queryParams = new Dictionary<string, string>()
164-
{
165-
{"nhsNumber", nhsNumber }
166-
};
189+
{"nhsNumber", nhsNumber }
190+
};
167191

168-
return await _httpClientFunction.SendGet(_config.RetrievePdsDemographicURL, queryParams);
169-
}
170-
catch (Exception ex)
171-
{
172-
_logger.LogError(ex, "There was an error retrieving the PDS record.");
173-
return null;
174-
}
192+
return await _httpClientFunction.SendGetHttpResponse(_config.RetrievePdsDemographicURL, queryParams);
175193
}
176194

177-
private async Task ProcessRecord(PdsDemographic pdsDemographic)
195+
private async Task ProcessRecord(Participant participant)
178196
{
179197
var updateRecord = new ConcurrentQueue<BasicParticipantCsvRecord>();
180198

181-
var participant = new Participant(pdsDemographic);
182-
183199
// TODO validate all dates in record before enqueuing
184-
185200
var existingParticipant = await _participantDemographic.GetSingleByFilter(x => x.NhsNumber == nhsNumberLong);
201+
202+
186203
if (existingParticipant == null)
187204
{
188205
participant.RecordType = Actions.New;
189206
_logger.LogWarning("The participant doesn't exists in Cohort Manager.A new record will be created in Cohort Manager.");
190207
}
191208
else
192209
{
193-
participant.RecordType = Actions.Amended;
210+
participant.RecordType = participant.RecordType != Actions.Removed ? Actions.Amended : participant.RecordType;
194211
_logger.LogWarning("The participant already exists in Cohort Manager. Existing record will get updated.");
195212
}
196213

@@ -204,6 +221,7 @@ private async Task ProcessRecord(PdsDemographic pdsDemographic)
204221
updateRecord.Enqueue(basicParticipantCsvRecord);
205222

206223
_logger.LogInformation("Sending record to the update queue.");
224+
207225
await _addBatchToQueue.ProcessBatch(updateRecord, _config.ParticipantManagementTopic);
208226
}
209227

application/CohortManager/src/Functions/NemsSubscriptionService/ProcessNemsUpdate/ProcessNemsUpdateConfig.cs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,14 @@ public class ProcessNemsUpdateConfig
77
public required string RetrievePdsDemographicURL { get; set; }
88
public required string NemsMessages { get; set; }
99
public required string UnsubscribeNemsSubscriptionUrl { get; set; }
10-
public required string ParticipantDemographicDataServiceURL { get; set; }
10+
11+
[Required]
1112
public required string ServiceBusConnectionString_client_internal { get; set; }
13+
14+
[Required]
1215
public required string ParticipantManagementTopic { get; set; }
16+
17+
[Required]
18+
public required string DemographicDataServiceURL { get; set; }
19+
1320
}

0 commit comments

Comments
 (0)