diff --git a/application/CohortManager/compose.wiremock.yaml b/application/CohortManager/compose.wiremock.yaml index b9ed7ba76f..f3badf16d9 100644 --- a/application/CohortManager/compose.wiremock.yaml +++ b/application/CohortManager/compose.wiremock.yaml @@ -7,6 +7,7 @@ services: build: context: ./src/Functions/ dockerfile: Shared/Wiremock/Dockerfile + user: "0" ports: - "8080:8080" volumes: diff --git a/application/CohortManager/src/Functions/CohortDistributionServices/DistributeParticipant/ValidateParticipant.cs b/application/CohortManager/src/Functions/CohortDistributionServices/DistributeParticipant/ValidateParticipant.cs index 499be80380..f552e4c6e1 100644 --- a/application/CohortManager/src/Functions/CohortDistributionServices/DistributeParticipant/ValidateParticipant.cs +++ b/application/CohortManager/src/Functions/CohortDistributionServices/DistributeParticipant/ValidateParticipant.cs @@ -65,7 +65,7 @@ public ValidateParticipant(IDataServiceClient cohortDistribu await removeValidationRecordTask; validationRecord.PreviousParticipantRecord = previousRecord; - + // Lookup & Static Validation var lookupTaskOptions = TaskOptions.FromRetryPolicy(new RetryPolicy( maxNumberOfAttempts: _config.MaxLookupValidationRetries, @@ -215,6 +215,7 @@ public async Task> LookupValidation([ActivityTrigger] var transformDataRequestBody = new TransformDataRequestBody() { Participant = validationRecord.Participant, + FileName = validationRecord.FileName, // TODO: is this used? ServiceProvider = validationRecord.ServiceProvider, ExistingParticipant = validationRecord.PreviousParticipantRecord.ToCohortDistribution() @@ -258,4 +259,4 @@ public async Task HandleValidationExceptions([ActivityTrigger] ValidationExcepti } _logger.LogInformation("Created validation exception and set exception flag to 1 for participant {ParticipantId}", participantRecord.Participant.ParticipantId); } -} \ No newline at end of file +} diff --git a/application/CohortManager/src/Functions/CohortDistributionServices/TransformDataService/Program.cs b/application/CohortManager/src/Functions/CohortDistributionServices/TransformDataService/Program.cs index 7e1c4c631f..86498642fc 100644 --- a/application/CohortManager/src/Functions/CohortDistributionServices/TransformDataService/Program.cs +++ b/application/CohortManager/src/Functions/CohortDistributionServices/TransformDataService/Program.cs @@ -24,6 +24,7 @@ services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); + services.AddSingleton(); services.AddMemoryCache(); // Register health checks diff --git a/application/CohortManager/src/Functions/CohortDistributionServices/TransformDataService/TransformDataService.cs b/application/CohortManager/src/Functions/CohortDistributionServices/TransformDataService/TransformDataService.cs index 9ce78e99b4..db5d0039c6 100644 --- a/application/CohortManager/src/Functions/CohortDistributionServices/TransformDataService/TransformDataService.cs +++ b/application/CohortManager/src/Functions/CohortDistributionServices/TransformDataService/TransformDataService.cs @@ -28,13 +28,15 @@ public class TransformDataService private readonly IExceptionHandler _exceptionHandler; private readonly ITransformReasonForRemoval _transformReasonForRemoval; private readonly ITransformDataLookupFacade _dataLookup; + private readonly IReasonForRemovalLookup _reasonForRemovalLookup; public TransformDataService( ICreateResponse createResponse, IExceptionHandler exceptionHandler, ILogger logger, ITransformReasonForRemoval transformReasonForRemoval, - ITransformDataLookupFacade dataLookup + ITransformDataLookupFacade dataLookup, + IReasonForRemovalLookup reasonForRemovalLookup ) { _createResponse = createResponse; @@ -42,6 +44,7 @@ ITransformDataLookupFacade dataLookup _logger = logger; _transformReasonForRemoval = transformReasonForRemoval; _dataLookup = dataLookup; + _reasonForRemovalLookup = reasonForRemovalLookup; } [Function("TransformDataService")] @@ -77,7 +80,7 @@ public async Task RunAsync([HttpTrigger(AuthorizationLevel.Ano participant = await transformString.TransformStringFields(participant); // Other transformation rules - participant = await TransformParticipantAsync(participant, requestBody.ExistingParticipant); + participant = await TransformParticipantAsync(participant, requestBody.ExistingParticipant,ValidationHelper.CheckManualAddFileName(requestBody.FileName)); // Name prefix transformation if (participant.NamePrefix != null) @@ -85,17 +88,21 @@ public async Task RunAsync([HttpTrigger(AuthorizationLevel.Ano participant = await _transformReasonForRemoval.ReasonForRemovalTransformations(participant, requestBody.ExistingParticipant); - if (participant.NhsNumber != null) + + if (participant.NhsNumber == null) { - var response = JsonSerializer.Serialize(participant); - return _createResponse.CreateHttpResponse(HttpStatusCode.OK, req, response); + return _createResponse.CreateHttpResponse(HttpStatusCode.Accepted, req, ""); + } - return _createResponse.CreateHttpResponse(HttpStatusCode.Accepted, req, ""); + + var response = JsonSerializer.Serialize(participant); + return _createResponse.CreateHttpResponse(HttpStatusCode.OK, req, response); + } catch (ArgumentException ex) { _logger.LogWarning(ex, "An error occurred during transformation"); - await _exceptionHandler.CreateSystemExceptionLogFromNhsNumber(ex, participant.NhsNumber, "", participant.ScreeningName, JsonSerializer.Serialize(participant)); + await _exceptionHandler.CreateSystemExceptionLogFromNhsNumber(ex, participant.NhsNumber, requestBody.FileName!, participant.ScreeningName!, JsonSerializer.Serialize(participant)); return _createResponse.CreateHttpResponse(HttpStatusCode.Accepted, req); } catch (TransformationException ex) @@ -105,14 +112,14 @@ public async Task RunAsync([HttpTrigger(AuthorizationLevel.Ano } catch (Exception ex) { - await _exceptionHandler.CreateSystemExceptionLogFromNhsNumber(ex, participant.NhsNumber, "", participant.ScreeningName, JsonSerializer.Serialize(participant)); + await _exceptionHandler.CreateSystemExceptionLogFromNhsNumber(ex, participant.NhsNumber, requestBody.FileName!, participant.ScreeningName!, JsonSerializer.Serialize(participant)); _logger.LogWarning(ex, "exception occurred while running transform data service"); return _createResponse.CreateHttpResponse(HttpStatusCode.InternalServerError, req); } } public async Task TransformParticipantAsync(CohortDistributionParticipant participant, - CohortDistribution databaseParticipant) + CohortDistribution databaseParticipant, bool isManualAdd = false) { var excludedSMUList = await _dataLookup.GetCachedExcludedSMUValues(); @@ -133,7 +140,8 @@ public async Task TransformParticipantAsync(Cohor new RuleParameter("participant", participant), new RuleParameter("dbLookup", _dataLookup), new RuleParameter("excludedSMUList", excludedSMUList), - new RuleParameter("existingParticipant", existingParticipant) + new RuleParameter("existingParticipant", existingParticipant), + new RuleParameter("reasonForRemovalLkp",_reasonForRemovalLookup) }; var resultList = await re.ExecuteAllRulesAsync("Common", ruleParameters); @@ -142,6 +150,10 @@ public async Task TransformParticipantAsync(Cohor { resultList.AddRange(await re.ExecuteAllRulesAsync("Referred", ruleParameters)); } + if (isManualAdd) + { + resultList.AddRange(await re.ExecuteAllRulesAsync("ManualAdd", ruleParameters)); + } await HandleExceptions(resultList, participant); await CreateTransformExecutedExceptions(resultList, participant); @@ -216,5 +228,4 @@ private async Task CreateTransformExecutedExceptions(List except await _exceptionHandler.CreateTransformExecutedExceptions(participant, ruleName, ruleId); } } - } diff --git a/application/CohortManager/src/Functions/CohortDistributionServices/TransformDataService/transformRules.json b/application/CohortManager/src/Functions/CohortDistributionServices/TransformDataService/transformRules.json index 05b6a328f4..a4aea48dbb 100644 --- a/application/CohortManager/src/Functions/CohortDistributionServices/TransformDataService/transformRules.json +++ b/application/CohortManager/src/Functions/CohortDistributionServices/TransformDataService/transformRules.json @@ -751,5 +751,43 @@ } } ] + }, + { + "WorkflowName": "ManualAdd", + "Rules": [ + { + "RuleName": "96.UpdateRFR.ManualAdd", + "LocalParams": [ + { + "Name": "CanTransformRfr", + "Expression": "reasonForRemovalLkp.CanRemovalReasonBeOverridden(participant.ReasonForRemoval)" + }, + { + "Name": "HasPrimaryCareProvider", + "Expression": "!string.IsNullOrEmpty(participant.PrimaryCareProvider)" + } + ], + "Expression": "!string.IsNullOrEmpty(participant.ReasonForRemoval) && CanTransformRfr && HasPrimaryCareProvider", + "Actions": { + "OnSuccess": { + "Name": "TransformAction", + "Context": { + "transformFields": [ + { + "field": "ReasonForRemoval", + "value": null, + "isExpression": false + }, + { + "field": "ReasonForRemovalEffectiveFromDate", + "value": null, + "isExpression": false + } + ] + } + } + } + } + ] } ] diff --git a/application/CohortManager/src/Functions/DemographicServices/RetrievePDSDemographic/MockedPDSData/complete-patient-9990360855.json b/application/CohortManager/src/Functions/DemographicServices/RetrievePDSDemographic/MockedPDSData/complete-patient-9990360855.json new file mode 100644 index 0000000000..c06c9c239d --- /dev/null +++ b/application/CohortManager/src/Functions/DemographicServices/RetrievePDSDemographic/MockedPDSData/complete-patient-9990360855.json @@ -0,0 +1,367 @@ +{ + "resourceType": "Patient", + "id": "9990360855", + "identifier": [ + { + "system": "https://fhir.nhs.uk/Id/nhs-number", + "value": "9990360855", + "extension": [ + { + "url": "https://fhir.hl7.org.uk/StructureDefinition/Extension-UKCore-NHSNumberVerificationStatus", + "valueCodeableConcept": { + "coding": [ + { + "system": "https://fhir.hl7.org.uk/CodeSystem/UKCore-NHSNumberVerificationStatus", + "version": "1.0.0", + "code": "01", + "display": "Number present and verified" + } + ] + } + } + ] + } + ], + "meta": { + "versionId": "2", + "security": [ + { + "system": "http://terminology.hl7.org/CodeSystem/v3-Confidentiality", + "code": "U", + "display": "unrestricted" + } + ] + }, + "name": [ + { + "id": "123", + "use": "usual", + "period": { + "start": "2020-01-01", + "end": "2021-12-31" + }, + "given": [ + "Jane" + ], + "family": "Smith", + "prefix": [ + "Mrs" + ] + } + ], + "gender": "female", + "birthDate": "1980-10-22", + "multipleBirthInteger": 1, + "generalPractitioner": [ + { + "id": "254406A3", + "type": "Organization", + "identifier": { + "system": "https://fhir.nhs.uk/Id/ods-organization-code", + "value": "", + "period": { + "start": "2020-01-01", + "end": "2021-12-31" + } + } + } + ], + "managingOrganization": { + "type": "Organization", + "identifier": { + "system": "https://fhir.nhs.uk/Id/ods-organization-code", + "value": "Y12345", + "period": { + "start": "2020-01-01", + "end": "2021-12-31" + } + } + }, + "extension": [ + { + "url": "https://fhir.hl7.org.uk/StructureDefinition/Extension-UKCore-NominatedPharmacy", + "valueReference": { + "identifier": { + "system": "https://fhir.nhs.uk/Id/ods-organization-code", + "value": "Y12345" + } + } + }, + { + "url": "https://fhir.hl7.org.uk/StructureDefinition/Extension-UKCore-PreferredDispenserOrganization", + "valueReference": { + "identifier": { + "system": "https://fhir.nhs.uk/Id/ods-organization-code", + "value": "Y23456" + } + } + }, + { + "url": "https://fhir.hl7.org.uk/StructureDefinition/Extension-UKCore-MedicalApplianceSupplier", + "valueReference": { + "identifier": { + "system": "https://fhir.nhs.uk/Id/ods-organization-code", + "value": "Y34567" + } + } + }, + { + "url": "https://fhir.hl7.org.uk/StructureDefinition/Extension-UKCore-NHSCommunication", + "extension": [ + { + "url": "language", + "valueCodeableConcept": { + "coding": [ + { + "system": "https://fhir.hl7.org.uk/CodeSystem/UKCore-HumanLanguage", + "version": "1.0.0", + "code": "fr", + "display": "French" + } + ] + } + }, + { + "url": "interpreterRequired", + "valueBoolean": true + } + ] + }, + { + "url": "https://fhir.hl7.org.uk/StructureDefinition/Extension-UKCore-ContactPreference", + "extension": [ + { + "url": "PreferredWrittenCommunicationFormat", + "valueCodeableConcept": { + "coding": [ + { + "system": "https://fhir.hl7.org.uk/CodeSystem/UKCore-PreferredWrittenCommunicationFormat", + "code": "12", + "display": "Braille" + } + ] + } + }, + { + "url": "PreferredContactMethod", + "valueCodeableConcept": { + "coding": [ + { + "system": "https://fhir.hl7.org.uk/CodeSystem/UKCore-PreferredContactMethod", + "code": "1", + "display": "Letter" + } + ] + } + }, + { + "url": "PreferredContactTimes", + "valueString": "Not after 7pm" + } + ] + }, + { + "url": "http://hl7.org/fhir/StructureDefinition/patient-birthPlace", + "valueAddress": { + "city": "Manchester", + "district": "Greater Manchester", + "country": "GBR" + } + }, + { + "url": "https://fhir.nhs.uk/StructureDefinition/Extension-PDS-RemovalFromRegistration", + "extension": [ + { + "url": "removalFromRegistrationCode", + "valueCodeableConcept": { + "coding": [ + { + "system": "https://fhir.nhs.uk/CodeSystem/PDS-RemovalReasonExitCode", + "code": "AFL", + "display": "armed forces enlistment - notified locally)" + } + ] + } + }, + { + "url": "effectiveTime", + "valuePeriod": { + "start": "2020-01-01T00:00:00+00:00", + "end": "2021-12-31T00:00:00+00:00" + } + } + ] + } + ], + "telecom": [ + { + "id": "789", + "period": { + "start": "2020-01-01", + "end": "2021-12-31" + }, + "system": "phone", + "value": "01632960587", + "use": "home" + }, + { + "id": "790", + "period": { + "start": "2019-01-01", + "end": "2022-12-31" + }, + "system": "email", + "value": "jane.smith@example.com", + "use": "home" + }, + { + "id": "OC789", + "period": { + "start": "2020-01-01", + "end": "2021-12-31" + }, + "system": "other", + "value": "01632960587", + "use": "home", + "extension": [ + { + "url": "https://fhir.hl7.org.uk/StructureDefinition/Extension-UKCore-OtherContactSystem", + "valueCoding": { + "system": "https://fhir.hl7.org.uk/CodeSystem/UKCore-OtherContactSystem", + "code": "textphone", + "display": "Minicom (Textphone)" + } + } + ] + } + ], + "contact": [ + { + "id": "C123", + "period": { + "start": "2020-01-01", + "end": "2021-12-31" + }, + "relationship": [ + { + "coding": [ + { + "system": "http://terminology.hl7.org/CodeSystem/v2-0131", + "code": "C", + "display": "Emergency Contact" + } + ] + } + ], + "telecom": [ + { + "system": "phone", + "value": "01632960587" + } + ] + } + ], + "address": [ + { + "id": "456", + "period": { + "start": "2020-01-01", + "end": "2021-12-31" + }, + "use": "home", + "line": [ + "1 Trevelyan Square", + "Boar Lane", + "City Centre", + "Leeds", + "West Yorkshire" + ], + "postalCode": "LS1 6AE", + "extension": [ + { + "url": "https://fhir.hl7.org.uk/StructureDefinition/Extension-UKCore-AddressKey", + "extension": [ + { + "url": "type", + "valueCoding": { + "system": "https://fhir.hl7.org.uk/CodeSystem/UKCore-AddressKeyType", + "code": "PAF" + } + }, + { + "url": "value", + "valueString": "12345678" + } + ] + }, + { + "url": "https://fhir.hl7.org.uk/StructureDefinition/Extension-UKCore-AddressKey", + "extension": [ + { + "url": "type", + "valueCoding": { + "system": "https://fhir.hl7.org.uk/CodeSystem/UKCore-AddressKeyType", + "code": "UPRN" + } + }, + { + "url": "value", + "valueString": "123456789012" + } + ] + } + ] + }, + { + "id": "T456", + "period": { + "start": "2020-01-01", + "end": "2021-12-31" + }, + "use": "temp", + "text": "Student Accommodation", + "line": [ + "1 Trevelyan Square", + "Boar Lane", + "City Centre", + "Leeds", + "West Yorkshire" + ], + "postalCode": "LS1 6AE", + "extension": [ + { + "url": "https://fhir.hl7.org.uk/StructureDefinition/Extension-UKCore-AddressKey", + "extension": [ + { + "url": "type", + "valueCoding": { + "system": "https://fhir.hl7.org.uk/CodeSystem/UKCore-AddressKeyType", + "code": "PAF" + } + }, + { + "url": "value", + "valueString": "12345678" + } + ] + }, + { + "url": "https://fhir.hl7.org.uk/StructureDefinition/Extension-UKCore-AddressKey", + "extension": [ + { + "url": "type", + "valueCoding": { + "system": "https://fhir.hl7.org.uk/CodeSystem/UKCore-AddressKeyType", + "code": "UPRN" + } + }, + { + "url": "value", + "valueString": "123456789012" + } + ] + } + ] + } + ] +} diff --git a/application/CohortManager/src/Functions/DemographicServices/RetrievePDSDemographic/MockedPDSData/complete-patient-9991970592.json b/application/CohortManager/src/Functions/DemographicServices/RetrievePDSDemographic/MockedPDSData/complete-patient-9991970592.json new file mode 100644 index 0000000000..7ff0daf00a --- /dev/null +++ b/application/CohortManager/src/Functions/DemographicServices/RetrievePDSDemographic/MockedPDSData/complete-patient-9991970592.json @@ -0,0 +1,367 @@ +{ + "resourceType": "Patient", + "id": "9991970592", + "identifier": [ + { + "system": "https://fhir.nhs.uk/Id/nhs-number", + "value": "9991970592", + "extension": [ + { + "url": "https://fhir.hl7.org.uk/StructureDefinition/Extension-UKCore-NHSNumberVerificationStatus", + "valueCodeableConcept": { + "coding": [ + { + "system": "https://fhir.hl7.org.uk/CodeSystem/UKCore-NHSNumberVerificationStatus", + "version": "1.0.0", + "code": "01", + "display": "Number present and verified" + } + ] + } + } + ] + } + ], + "meta": { + "versionId": "2", + "security": [ + { + "system": "http://terminology.hl7.org/CodeSystem/v3-Confidentiality", + "code": "U", + "display": "unrestricted" + } + ] + }, + "name": [ + { + "id": "123", + "use": "usual", + "period": { + "start": "2020-01-01", + "end": "2021-12-31" + }, + "given": [ + "Jane" + ], + "family": "Smith", + "prefix": [ + "Mrs" + ] + } + ], + "gender": "female", + "birthDate": "1980-10-22", + "multipleBirthInteger": 1, + "generalPractitioner": [ + { + "id": "254406A3", + "type": "Organization", + "identifier": { + "system": "https://fhir.nhs.uk/Id/ods-organization-code", + "value": "", + "period": { + "start": "2020-01-01", + "end": "2021-12-31" + } + } + } + ], + "managingOrganization": { + "type": "Organization", + "identifier": { + "system": "https://fhir.nhs.uk/Id/ods-organization-code", + "value": "Y12345", + "period": { + "start": "2020-01-01", + "end": "2021-12-31" + } + } + }, + "extension": [ + { + "url": "https://fhir.hl7.org.uk/StructureDefinition/Extension-UKCore-NominatedPharmacy", + "valueReference": { + "identifier": { + "system": "https://fhir.nhs.uk/Id/ods-organization-code", + "value": "Y12345" + } + } + }, + { + "url": "https://fhir.hl7.org.uk/StructureDefinition/Extension-UKCore-PreferredDispenserOrganization", + "valueReference": { + "identifier": { + "system": "https://fhir.nhs.uk/Id/ods-organization-code", + "value": "Y23456" + } + } + }, + { + "url": "https://fhir.hl7.org.uk/StructureDefinition/Extension-UKCore-MedicalApplianceSupplier", + "valueReference": { + "identifier": { + "system": "https://fhir.nhs.uk/Id/ods-organization-code", + "value": "Y34567" + } + } + }, + { + "url": "https://fhir.hl7.org.uk/StructureDefinition/Extension-UKCore-NHSCommunication", + "extension": [ + { + "url": "language", + "valueCodeableConcept": { + "coding": [ + { + "system": "https://fhir.hl7.org.uk/CodeSystem/UKCore-HumanLanguage", + "version": "1.0.0", + "code": "fr", + "display": "French" + } + ] + } + }, + { + "url": "interpreterRequired", + "valueBoolean": true + } + ] + }, + { + "url": "https://fhir.hl7.org.uk/StructureDefinition/Extension-UKCore-ContactPreference", + "extension": [ + { + "url": "PreferredWrittenCommunicationFormat", + "valueCodeableConcept": { + "coding": [ + { + "system": "https://fhir.hl7.org.uk/CodeSystem/UKCore-PreferredWrittenCommunicationFormat", + "code": "12", + "display": "Braille" + } + ] + } + }, + { + "url": "PreferredContactMethod", + "valueCodeableConcept": { + "coding": [ + { + "system": "https://fhir.hl7.org.uk/CodeSystem/UKCore-PreferredContactMethod", + "code": "1", + "display": "Letter" + } + ] + } + }, + { + "url": "PreferredContactTimes", + "valueString": "Not after 7pm" + } + ] + }, + { + "url": "http://hl7.org/fhir/StructureDefinition/patient-birthPlace", + "valueAddress": { + "city": "Manchester", + "district": "Greater Manchester", + "country": "GBR" + } + }, + { + "url": "https://fhir.nhs.uk/StructureDefinition/Extension-PDS-RemovalFromRegistration", + "extension": [ + { + "url": "removalFromRegistrationCode", + "valueCodeableConcept": { + "coding": [ + { + "system": "https://fhir.nhs.uk/CodeSystem/PDS-RemovalReasonExitCode", + "code": "NIT", + "display": "Transferred to Northern Ireland" + } + ] + } + }, + { + "url": "effectiveTime", + "valuePeriod": { + "start": "2020-01-01T00:00:00+00:00", + "end": "2021-12-31T00:00:00+00:00" + } + } + ] + } + ], + "telecom": [ + { + "id": "789", + "period": { + "start": "2020-01-01", + "end": "2021-12-31" + }, + "system": "phone", + "value": "01632960587", + "use": "home" + }, + { + "id": "790", + "period": { + "start": "2019-01-01", + "end": "2022-12-31" + }, + "system": "email", + "value": "jane.smith@example.com", + "use": "home" + }, + { + "id": "OC789", + "period": { + "start": "2020-01-01", + "end": "2021-12-31" + }, + "system": "other", + "value": "01632960587", + "use": "home", + "extension": [ + { + "url": "https://fhir.hl7.org.uk/StructureDefinition/Extension-UKCore-OtherContactSystem", + "valueCoding": { + "system": "https://fhir.hl7.org.uk/CodeSystem/UKCore-OtherContactSystem", + "code": "textphone", + "display": "Minicom (Textphone)" + } + } + ] + } + ], + "contact": [ + { + "id": "C123", + "period": { + "start": "2020-01-01", + "end": "2021-12-31" + }, + "relationship": [ + { + "coding": [ + { + "system": "http://terminology.hl7.org/CodeSystem/v2-0131", + "code": "C", + "display": "Emergency Contact" + } + ] + } + ], + "telecom": [ + { + "system": "phone", + "value": "01632960587" + } + ] + } + ], + "address": [ + { + "id": "456", + "period": { + "start": "2020-01-01", + "end": "2021-12-31" + }, + "use": "home", + "line": [ + "1 Trevelyan Square", + "Boar Lane", + "City Centre", + "Leeds", + "West Yorkshire" + ], + "postalCode": "LS1 6AE", + "extension": [ + { + "url": "https://fhir.hl7.org.uk/StructureDefinition/Extension-UKCore-AddressKey", + "extension": [ + { + "url": "type", + "valueCoding": { + "system": "https://fhir.hl7.org.uk/CodeSystem/UKCore-AddressKeyType", + "code": "PAF" + } + }, + { + "url": "value", + "valueString": "12345678" + } + ] + }, + { + "url": "https://fhir.hl7.org.uk/StructureDefinition/Extension-UKCore-AddressKey", + "extension": [ + { + "url": "type", + "valueCoding": { + "system": "https://fhir.hl7.org.uk/CodeSystem/UKCore-AddressKeyType", + "code": "UPRN" + } + }, + { + "url": "value", + "valueString": "123456789012" + } + ] + } + ] + }, + { + "id": "T456", + "period": { + "start": "2020-01-01", + "end": "2021-12-31" + }, + "use": "temp", + "text": "Student Accommodation", + "line": [ + "1 Trevelyan Square", + "Boar Lane", + "City Centre", + "Leeds", + "West Yorkshire" + ], + "postalCode": "LS1 6AE", + "extension": [ + { + "url": "https://fhir.hl7.org.uk/StructureDefinition/Extension-UKCore-AddressKey", + "extension": [ + { + "url": "type", + "valueCoding": { + "system": "https://fhir.hl7.org.uk/CodeSystem/UKCore-AddressKeyType", + "code": "PAF" + } + }, + { + "url": "value", + "valueString": "12345678" + } + ] + }, + { + "url": "https://fhir.hl7.org.uk/StructureDefinition/Extension-UKCore-AddressKey", + "extension": [ + { + "url": "type", + "valueCoding": { + "system": "https://fhir.hl7.org.uk/CodeSystem/UKCore-AddressKeyType", + "code": "UPRN" + } + }, + { + "url": "value", + "valueString": "123456789012" + } + ] + } + ] + } + ] +} diff --git a/application/CohortManager/src/Functions/DemographicServices/RetrievePDSDemographic/MockedPDSData/complete-patient-9994170503.json b/application/CohortManager/src/Functions/DemographicServices/RetrievePDSDemographic/MockedPDSData/complete-patient-9994170503.json new file mode 100644 index 0000000000..18b3c5c7ba --- /dev/null +++ b/application/CohortManager/src/Functions/DemographicServices/RetrievePDSDemographic/MockedPDSData/complete-patient-9994170503.json @@ -0,0 +1,367 @@ +{ + "resourceType": "Patient", + "id": "9994170503", + "identifier": [ + { + "system": "https://fhir.nhs.uk/Id/nhs-number", + "value": "9994170503", + "extension": [ + { + "url": "https://fhir.hl7.org.uk/StructureDefinition/Extension-UKCore-NHSNumberVerificationStatus", + "valueCodeableConcept": { + "coding": [ + { + "system": "https://fhir.hl7.org.uk/CodeSystem/UKCore-NHSNumberVerificationStatus", + "version": "1.0.0", + "code": "01", + "display": "Number present and verified" + } + ] + } + } + ] + } + ], + "meta": { + "versionId": "2", + "security": [ + { + "system": "http://terminology.hl7.org/CodeSystem/v3-Confidentiality", + "code": "U", + "display": "unrestricted" + } + ] + }, + "name": [ + { + "id": "123", + "use": "usual", + "period": { + "start": "2020-01-01", + "end": "2021-12-31" + }, + "given": [ + "Jane" + ], + "family": "Smith", + "prefix": [ + "Mrs" + ] + } + ], + "gender": "female", + "birthDate": "1980-10-22", + "multipleBirthInteger": 1, + "generalPractitioner": [ + { + "id": "254406A3", + "type": "Organization", + "identifier": { + "system": "https://fhir.nhs.uk/Id/ods-organization-code", + "value": "", + "period": { + "start": "2020-01-01", + "end": "2021-12-31" + } + } + } + ], + "managingOrganization": { + "type": "Organization", + "identifier": { + "system": "https://fhir.nhs.uk/Id/ods-organization-code", + "value": "Y12345", + "period": { + "start": "2020-01-01", + "end": "2021-12-31" + } + } + }, + "extension": [ + { + "url": "https://fhir.hl7.org.uk/StructureDefinition/Extension-UKCore-NominatedPharmacy", + "valueReference": { + "identifier": { + "system": "https://fhir.nhs.uk/Id/ods-organization-code", + "value": "Y12345" + } + } + }, + { + "url": "https://fhir.hl7.org.uk/StructureDefinition/Extension-UKCore-PreferredDispenserOrganization", + "valueReference": { + "identifier": { + "system": "https://fhir.nhs.uk/Id/ods-organization-code", + "value": "Y23456" + } + } + }, + { + "url": "https://fhir.hl7.org.uk/StructureDefinition/Extension-UKCore-MedicalApplianceSupplier", + "valueReference": { + "identifier": { + "system": "https://fhir.nhs.uk/Id/ods-organization-code", + "value": "Y34567" + } + } + }, + { + "url": "https://fhir.hl7.org.uk/StructureDefinition/Extension-UKCore-NHSCommunication", + "extension": [ + { + "url": "language", + "valueCodeableConcept": { + "coding": [ + { + "system": "https://fhir.hl7.org.uk/CodeSystem/UKCore-HumanLanguage", + "version": "1.0.0", + "code": "fr", + "display": "French" + } + ] + } + }, + { + "url": "interpreterRequired", + "valueBoolean": true + } + ] + }, + { + "url": "https://fhir.hl7.org.uk/StructureDefinition/Extension-UKCore-ContactPreference", + "extension": [ + { + "url": "PreferredWrittenCommunicationFormat", + "valueCodeableConcept": { + "coding": [ + { + "system": "https://fhir.hl7.org.uk/CodeSystem/UKCore-PreferredWrittenCommunicationFormat", + "code": "12", + "display": "Braille" + } + ] + } + }, + { + "url": "PreferredContactMethod", + "valueCodeableConcept": { + "coding": [ + { + "system": "https://fhir.hl7.org.uk/CodeSystem/UKCore-PreferredContactMethod", + "code": "1", + "display": "Letter" + } + ] + } + }, + { + "url": "PreferredContactTimes", + "valueString": "Not after 7pm" + } + ] + }, + { + "url": "http://hl7.org/fhir/StructureDefinition/patient-birthPlace", + "valueAddress": { + "city": "Manchester", + "district": "Greater Manchester", + "country": "GBR" + } + }, + { + "url": "https://fhir.nhs.uk/StructureDefinition/Extension-PDS-RemovalFromRegistration", + "extension": [ + { + "url": "removalFromRegistrationCode", + "valueCodeableConcept": { + "coding": [ + { + "system": "https://fhir.nhs.uk/CodeSystem/PDS-RemovalReasonExitCode", + "code": "RDI", + "display": "Practice request immediate removal" + } + ] + } + }, + { + "url": "effectiveTime", + "valuePeriod": { + "start": "2020-01-01T00:00:00+00:00", + "end": "2021-12-31T00:00:00+00:00" + } + } + ] + } + ], + "telecom": [ + { + "id": "789", + "period": { + "start": "2020-01-01", + "end": "2021-12-31" + }, + "system": "phone", + "value": "01632960587", + "use": "home" + }, + { + "id": "790", + "period": { + "start": "2019-01-01", + "end": "2022-12-31" + }, + "system": "email", + "value": "jane.smith@example.com", + "use": "home" + }, + { + "id": "OC789", + "period": { + "start": "2020-01-01", + "end": "2021-12-31" + }, + "system": "other", + "value": "01632960587", + "use": "home", + "extension": [ + { + "url": "https://fhir.hl7.org.uk/StructureDefinition/Extension-UKCore-OtherContactSystem", + "valueCoding": { + "system": "https://fhir.hl7.org.uk/CodeSystem/UKCore-OtherContactSystem", + "code": "textphone", + "display": "Minicom (Textphone)" + } + } + ] + } + ], + "contact": [ + { + "id": "C123", + "period": { + "start": "2020-01-01", + "end": "2021-12-31" + }, + "relationship": [ + { + "coding": [ + { + "system": "http://terminology.hl7.org/CodeSystem/v2-0131", + "code": "C", + "display": "Emergency Contact" + } + ] + } + ], + "telecom": [ + { + "system": "phone", + "value": "01632960587" + } + ] + } + ], + "address": [ + { + "id": "456", + "period": { + "start": "2020-01-01", + "end": "2021-12-31" + }, + "use": "home", + "line": [ + "1 Trevelyan Square", + "Boar Lane", + "City Centre", + "Leeds", + "West Yorkshire" + ], + "postalCode": "LS1 6AE", + "extension": [ + { + "url": "https://fhir.hl7.org.uk/StructureDefinition/Extension-UKCore-AddressKey", + "extension": [ + { + "url": "type", + "valueCoding": { + "system": "https://fhir.hl7.org.uk/CodeSystem/UKCore-AddressKeyType", + "code": "PAF" + } + }, + { + "url": "value", + "valueString": "12345678" + } + ] + }, + { + "url": "https://fhir.hl7.org.uk/StructureDefinition/Extension-UKCore-AddressKey", + "extension": [ + { + "url": "type", + "valueCoding": { + "system": "https://fhir.hl7.org.uk/CodeSystem/UKCore-AddressKeyType", + "code": "UPRN" + } + }, + { + "url": "value", + "valueString": "123456789012" + } + ] + } + ] + }, + { + "id": "T456", + "period": { + "start": "2020-01-01", + "end": "2021-12-31" + }, + "use": "temp", + "text": "Student Accommodation", + "line": [ + "1 Trevelyan Square", + "Boar Lane", + "City Centre", + "Leeds", + "West Yorkshire" + ], + "postalCode": "LS1 6AE", + "extension": [ + { + "url": "https://fhir.hl7.org.uk/StructureDefinition/Extension-UKCore-AddressKey", + "extension": [ + { + "url": "type", + "valueCoding": { + "system": "https://fhir.hl7.org.uk/CodeSystem/UKCore-AddressKeyType", + "code": "PAF" + } + }, + { + "url": "value", + "valueString": "12345678" + } + ] + }, + { + "url": "https://fhir.hl7.org.uk/StructureDefinition/Extension-UKCore-AddressKey", + "extension": [ + { + "url": "type", + "valueCoding": { + "system": "https://fhir.hl7.org.uk/CodeSystem/UKCore-AddressKeyType", + "code": "UPRN" + } + }, + { + "url": "value", + "valueString": "123456789012" + } + ] + } + ] + } + ] +} diff --git a/application/CohortManager/src/Functions/DemographicServices/RetrievePDSDemographic/MockedPDSData/complete-patient-9996666921.json b/application/CohortManager/src/Functions/DemographicServices/RetrievePDSDemographic/MockedPDSData/complete-patient-9996666921.json new file mode 100644 index 0000000000..f6cce54177 --- /dev/null +++ b/application/CohortManager/src/Functions/DemographicServices/RetrievePDSDemographic/MockedPDSData/complete-patient-9996666921.json @@ -0,0 +1,367 @@ +{ + "resourceType": "Patient", + "id": "9996666921", + "identifier": [ + { + "system": "https://fhir.nhs.uk/Id/nhs-number", + "value": "9996666921", + "extension": [ + { + "url": "https://fhir.hl7.org.uk/StructureDefinition/Extension-UKCore-NHSNumberVerificationStatus", + "valueCodeableConcept": { + "coding": [ + { + "system": "https://fhir.hl7.org.uk/CodeSystem/UKCore-NHSNumberVerificationStatus", + "version": "1.0.0", + "code": "01", + "display": "Number present and verified" + } + ] + } + } + ] + } + ], + "meta": { + "versionId": "2", + "security": [ + { + "system": "http://terminology.hl7.org/CodeSystem/v3-Confidentiality", + "code": "U", + "display": "unrestricted" + } + ] + }, + "name": [ + { + "id": "123", + "use": "usual", + "period": { + "start": "2020-01-01", + "end": "2021-12-31" + }, + "given": [ + "Jane" + ], + "family": "Smith", + "prefix": [ + "Mrs" + ] + } + ], + "gender": "female", + "birthDate": "1980-10-22", + "multipleBirthInteger": 1, + "generalPractitioner": [ + { + "id": "254406A3", + "type": "Organization", + "identifier": { + "system": "https://fhir.nhs.uk/Id/ods-organization-code", + "value": "", + "period": { + "start": "2020-01-01", + "end": "2021-12-31" + } + } + } + ], + "managingOrganization": { + "type": "Organization", + "identifier": { + "system": "https://fhir.nhs.uk/Id/ods-organization-code", + "value": "Y12345", + "period": { + "start": "2020-01-01", + "end": "2021-12-31" + } + } + }, + "extension": [ + { + "url": "https://fhir.hl7.org.uk/StructureDefinition/Extension-UKCore-NominatedPharmacy", + "valueReference": { + "identifier": { + "system": "https://fhir.nhs.uk/Id/ods-organization-code", + "value": "Y12345" + } + } + }, + { + "url": "https://fhir.hl7.org.uk/StructureDefinition/Extension-UKCore-PreferredDispenserOrganization", + "valueReference": { + "identifier": { + "system": "https://fhir.nhs.uk/Id/ods-organization-code", + "value": "Y23456" + } + } + }, + { + "url": "https://fhir.hl7.org.uk/StructureDefinition/Extension-UKCore-MedicalApplianceSupplier", + "valueReference": { + "identifier": { + "system": "https://fhir.nhs.uk/Id/ods-organization-code", + "value": "Y34567" + } + } + }, + { + "url": "https://fhir.hl7.org.uk/StructureDefinition/Extension-UKCore-NHSCommunication", + "extension": [ + { + "url": "language", + "valueCodeableConcept": { + "coding": [ + { + "system": "https://fhir.hl7.org.uk/CodeSystem/UKCore-HumanLanguage", + "version": "1.0.0", + "code": "fr", + "display": "French" + } + ] + } + }, + { + "url": "interpreterRequired", + "valueBoolean": true + } + ] + }, + { + "url": "https://fhir.hl7.org.uk/StructureDefinition/Extension-UKCore-ContactPreference", + "extension": [ + { + "url": "PreferredWrittenCommunicationFormat", + "valueCodeableConcept": { + "coding": [ + { + "system": "https://fhir.hl7.org.uk/CodeSystem/UKCore-PreferredWrittenCommunicationFormat", + "code": "12", + "display": "Braille" + } + ] + } + }, + { + "url": "PreferredContactMethod", + "valueCodeableConcept": { + "coding": [ + { + "system": "https://fhir.hl7.org.uk/CodeSystem/UKCore-PreferredContactMethod", + "code": "1", + "display": "Letter" + } + ] + } + }, + { + "url": "PreferredContactTimes", + "valueString": "Not after 7pm" + } + ] + }, + { + "url": "http://hl7.org/fhir/StructureDefinition/patient-birthPlace", + "valueAddress": { + "city": "Manchester", + "district": "Greater Manchester", + "country": "GBR" + } + }, + { + "url": "https://fhir.nhs.uk/StructureDefinition/Extension-PDS-RemovalFromRegistration", + "extension": [ + { + "url": "removalFromRegistrationCode", + "valueCodeableConcept": { + "coding": [ + { + "system": "https://fhir.nhs.uk/CodeSystem/PDS-RemovalReasonExitCode", + "code": "CGA", + "display": "Gone away – address not known/FP69" + } + ] + } + }, + { + "url": "effectiveTime", + "valuePeriod": { + "start": "2020-01-01T00:00:00+00:00", + "end": "2021-12-31T00:00:00+00:00" + } + } + ] + } + ], + "telecom": [ + { + "id": "789", + "period": { + "start": "2020-01-01", + "end": "2021-12-31" + }, + "system": "phone", + "value": "01632960587", + "use": "home" + }, + { + "id": "790", + "period": { + "start": "2019-01-01", + "end": "2022-12-31" + }, + "system": "email", + "value": "jane.smith@example.com", + "use": "home" + }, + { + "id": "OC789", + "period": { + "start": "2020-01-01", + "end": "2021-12-31" + }, + "system": "other", + "value": "01632960587", + "use": "home", + "extension": [ + { + "url": "https://fhir.hl7.org.uk/StructureDefinition/Extension-UKCore-OtherContactSystem", + "valueCoding": { + "system": "https://fhir.hl7.org.uk/CodeSystem/UKCore-OtherContactSystem", + "code": "textphone", + "display": "Minicom (Textphone)" + } + } + ] + } + ], + "contact": [ + { + "id": "C123", + "period": { + "start": "2020-01-01", + "end": "2021-12-31" + }, + "relationship": [ + { + "coding": [ + { + "system": "http://terminology.hl7.org/CodeSystem/v2-0131", + "code": "C", + "display": "Emergency Contact" + } + ] + } + ], + "telecom": [ + { + "system": "phone", + "value": "01632960587" + } + ] + } + ], + "address": [ + { + "id": "456", + "period": { + "start": "2020-01-01", + "end": "2021-12-31" + }, + "use": "home", + "line": [ + "1 Trevelyan Square", + "Boar Lane", + "City Centre", + "Leeds", + "West Yorkshire" + ], + "postalCode": "LS1 6AE", + "extension": [ + { + "url": "https://fhir.hl7.org.uk/StructureDefinition/Extension-UKCore-AddressKey", + "extension": [ + { + "url": "type", + "valueCoding": { + "system": "https://fhir.hl7.org.uk/CodeSystem/UKCore-AddressKeyType", + "code": "PAF" + } + }, + { + "url": "value", + "valueString": "12345678" + } + ] + }, + { + "url": "https://fhir.hl7.org.uk/StructureDefinition/Extension-UKCore-AddressKey", + "extension": [ + { + "url": "type", + "valueCoding": { + "system": "https://fhir.hl7.org.uk/CodeSystem/UKCore-AddressKeyType", + "code": "UPRN" + } + }, + { + "url": "value", + "valueString": "123456789012" + } + ] + } + ] + }, + { + "id": "T456", + "period": { + "start": "2020-01-01", + "end": "2021-12-31" + }, + "use": "temp", + "text": "Student Accommodation", + "line": [ + "1 Trevelyan Square", + "Boar Lane", + "City Centre", + "Leeds", + "West Yorkshire" + ], + "postalCode": "LS1 6AE", + "extension": [ + { + "url": "https://fhir.hl7.org.uk/StructureDefinition/Extension-UKCore-AddressKey", + "extension": [ + { + "url": "type", + "valueCoding": { + "system": "https://fhir.hl7.org.uk/CodeSystem/UKCore-AddressKeyType", + "code": "PAF" + } + }, + { + "url": "value", + "valueString": "12345678" + } + ] + }, + { + "url": "https://fhir.hl7.org.uk/StructureDefinition/Extension-UKCore-AddressKey", + "extension": [ + { + "url": "type", + "valueCoding": { + "system": "https://fhir.hl7.org.uk/CodeSystem/UKCore-AddressKeyType", + "code": "UPRN" + } + }, + { + "url": "value", + "valueString": "123456789012" + } + ] + } + ] + } + ] +} diff --git a/application/CohortManager/src/Functions/DemographicServices/RetrievePDSDemographic/MockedPDSData/complete-patient-9998582997.json b/application/CohortManager/src/Functions/DemographicServices/RetrievePDSDemographic/MockedPDSData/complete-patient-9998582997.json new file mode 100644 index 0000000000..2d2cdf6396 --- /dev/null +++ b/application/CohortManager/src/Functions/DemographicServices/RetrievePDSDemographic/MockedPDSData/complete-patient-9998582997.json @@ -0,0 +1,343 @@ +{ + "resourceType": "Patient", + "id": "9998582997", + "identifier": [ + { + "system": "https://fhir.nhs.uk/Id/nhs-number", + "value": "9998582997", + "extension": [ + { + "url": "https://fhir.hl7.org.uk/StructureDefinition/Extension-UKCore-NHSNumberVerificationStatus", + "valueCodeableConcept": { + "coding": [ + { + "system": "https://fhir.hl7.org.uk/CodeSystem/UKCore-NHSNumberVerificationStatus", + "version": "1.0.0", + "code": "01", + "display": "Number present and verified" + } + ] + } + } + ] + } + ], + "meta": { + "versionId": "2", + "security": [ + { + "system": "http://terminology.hl7.org/CodeSystem/v3-Confidentiality", + "code": "U", + "display": "unrestricted" + } + ] + }, + "name": [ + { + "id": "123", + "use": "usual", + "period": { + "start": "2020-01-01", + "end": "2021-12-31" + }, + "given": [ + "Jane" + ], + "family": "Smith", + "prefix": [ + "Mrs" + ] + } + ], + "gender": "female", + "birthDate": "1980-10-22", + "multipleBirthInteger": 1, + "generalPractitioner": [ + { + "id": "254406A3", + "type": "Organization", + "identifier": { + "system": "https://fhir.nhs.uk/Id/ods-organization-code", + "value": "", + "period": { + "start": "2020-01-01", + "end": "2021-12-31" + } + } + } + ], + "managingOrganization": { + "type": "Organization", + "identifier": { + "system": "https://fhir.nhs.uk/Id/ods-organization-code", + "value": "Y12345", + "period": { + "start": "2020-01-01", + "end": "2021-12-31" + } + } + }, + "extension": [ + { + "url": "https://fhir.hl7.org.uk/StructureDefinition/Extension-UKCore-NominatedPharmacy", + "valueReference": { + "identifier": { + "system": "https://fhir.nhs.uk/Id/ods-organization-code", + "value": "Y12345" + } + } + }, + { + "url": "https://fhir.hl7.org.uk/StructureDefinition/Extension-UKCore-PreferredDispenserOrganization", + "valueReference": { + "identifier": { + "system": "https://fhir.nhs.uk/Id/ods-organization-code", + "value": "Y23456" + } + } + }, + { + "url": "https://fhir.hl7.org.uk/StructureDefinition/Extension-UKCore-MedicalApplianceSupplier", + "valueReference": { + "identifier": { + "system": "https://fhir.nhs.uk/Id/ods-organization-code", + "value": "Y34567" + } + } + }, + { + "url": "https://fhir.hl7.org.uk/StructureDefinition/Extension-UKCore-NHSCommunication", + "extension": [ + { + "url": "language", + "valueCodeableConcept": { + "coding": [ + { + "system": "https://fhir.hl7.org.uk/CodeSystem/UKCore-HumanLanguage", + "version": "1.0.0", + "code": "fr", + "display": "French" + } + ] + } + }, + { + "url": "interpreterRequired", + "valueBoolean": true + } + ] + }, + { + "url": "https://fhir.hl7.org.uk/StructureDefinition/Extension-UKCore-ContactPreference", + "extension": [ + { + "url": "PreferredWrittenCommunicationFormat", + "valueCodeableConcept": { + "coding": [ + { + "system": "https://fhir.hl7.org.uk/CodeSystem/UKCore-PreferredWrittenCommunicationFormat", + "code": "12", + "display": "Braille" + } + ] + } + }, + { + "url": "PreferredContactMethod", + "valueCodeableConcept": { + "coding": [ + { + "system": "https://fhir.hl7.org.uk/CodeSystem/UKCore-PreferredContactMethod", + "code": "1", + "display": "Letter" + } + ] + } + }, + { + "url": "PreferredContactTimes", + "valueString": "Not after 7pm" + } + ] + }, + { + "url": "http://hl7.org/fhir/StructureDefinition/patient-birthPlace", + "valueAddress": { + "city": "Manchester", + "district": "Greater Manchester", + "country": "GBR" + } + } + ], + "telecom": [ + { + "id": "789", + "period": { + "start": "2020-01-01", + "end": "2021-12-31" + }, + "system": "phone", + "value": "01632960587", + "use": "home" + }, + { + "id": "790", + "period": { + "start": "2019-01-01", + "end": "2022-12-31" + }, + "system": "email", + "value": "jane.smith@example.com", + "use": "home" + }, + { + "id": "OC789", + "period": { + "start": "2020-01-01", + "end": "2021-12-31" + }, + "system": "other", + "value": "01632960587", + "use": "home", + "extension": [ + { + "url": "https://fhir.hl7.org.uk/StructureDefinition/Extension-UKCore-OtherContactSystem", + "valueCoding": { + "system": "https://fhir.hl7.org.uk/CodeSystem/UKCore-OtherContactSystem", + "code": "textphone", + "display": "Minicom (Textphone)" + } + } + ] + } + ], + "contact": [ + { + "id": "C123", + "period": { + "start": "2020-01-01", + "end": "2021-12-31" + }, + "relationship": [ + { + "coding": [ + { + "system": "http://terminology.hl7.org/CodeSystem/v2-0131", + "code": "C", + "display": "Emergency Contact" + } + ] + } + ], + "telecom": [ + { + "system": "phone", + "value": "01632960587" + } + ] + } + ], + "address": [ + { + "id": "456", + "period": { + "start": "2020-01-01", + "end": "2021-12-31" + }, + "use": "home", + "line": [ + "1 Trevelyan Square", + "Boar Lane", + "City Centre", + "Leeds", + "West Yorkshire" + ], + "postalCode": "LS1 6AE", + "extension": [ + { + "url": "https://fhir.hl7.org.uk/StructureDefinition/Extension-UKCore-AddressKey", + "extension": [ + { + "url": "type", + "valueCoding": { + "system": "https://fhir.hl7.org.uk/CodeSystem/UKCore-AddressKeyType", + "code": "PAF" + } + }, + { + "url": "value", + "valueString": "12345678" + } + ] + }, + { + "url": "https://fhir.hl7.org.uk/StructureDefinition/Extension-UKCore-AddressKey", + "extension": [ + { + "url": "type", + "valueCoding": { + "system": "https://fhir.hl7.org.uk/CodeSystem/UKCore-AddressKeyType", + "code": "UPRN" + } + }, + { + "url": "value", + "valueString": "123456789012" + } + ] + } + ] + }, + { + "id": "T456", + "period": { + "start": "2020-01-01", + "end": "2021-12-31" + }, + "use": "temp", + "text": "Student Accommodation", + "line": [ + "1 Trevelyan Square", + "Boar Lane", + "City Centre", + "Leeds", + "West Yorkshire" + ], + "postalCode": "LS1 6AE", + "extension": [ + { + "url": "https://fhir.hl7.org.uk/StructureDefinition/Extension-UKCore-AddressKey", + "extension": [ + { + "url": "type", + "valueCoding": { + "system": "https://fhir.hl7.org.uk/CodeSystem/UKCore-AddressKeyType", + "code": "PAF" + } + }, + { + "url": "value", + "valueString": "12345678" + } + ] + }, + { + "url": "https://fhir.hl7.org.uk/StructureDefinition/Extension-UKCore-AddressKey", + "extension": [ + { + "url": "type", + "valueCoding": { + "system": "https://fhir.hl7.org.uk/CodeSystem/UKCore-AddressKeyType", + "code": "UPRN" + } + }, + { + "url": "value", + "valueString": "123456789012" + } + ] + } + ] + } + ] +} diff --git a/application/CohortManager/src/Functions/ScreeningValidationService/StaticValidation/Breast_Screening_staticRules.json b/application/CohortManager/src/Functions/ScreeningValidationService/StaticValidation/Breast_Screening_staticRules.json index 9d09d462fb..94752cc707 100644 --- a/application/CohortManager/src/Functions/ScreeningValidationService/StaticValidation/Breast_Screening_staticRules.json +++ b/application/CohortManager/src/Functions/ScreeningValidationService/StaticValidation/Breast_Screening_staticRules.json @@ -93,7 +93,7 @@ }, { "RuleName": "3.PrimaryCareProviderAndReasonForRemoval.NBO.NonFatal", - "Expression": "(string.IsNullOrEmpty(participant.PrimaryCareProvider) AND !string.IsNullOrEmpty(participant.ReasonForRemoval)) OR (!string.IsNullOrEmpty(participant.PrimaryCareProvider) AND string.IsNullOrEmpty(participant.ReasonForRemoval))", + "Expression": "manualAdd OR ((string.IsNullOrEmpty(participant.PrimaryCareProvider) AND !string.IsNullOrEmpty(participant.ReasonForRemoval)) OR (!string.IsNullOrEmpty(participant.PrimaryCareProvider) AND string.IsNullOrEmpty(participant.ReasonForRemoval)))", "Actions": { "OnFailure": { "Name": "OutputExpression", @@ -174,5 +174,40 @@ } } ] + }, + { + "WorkflowName": "Manual_Add", + "Rules": [ + { + "RuleName": "97.NoDummyGPorPCP.NBO.NonFatal", + "LocalParams" : [ + { + "Name": "ValidReasonForRemoval", + "Expression": "participant.ReasonForRemoval == \"RDR\" || participant.ReasonForRemoval == \"RPR\" || participant.ReasonForRemoval == \"RDI\" " + } + ], + "Expression": "!string.IsNullOrEmpty(participant.PrimaryCareProvider) || (string.IsNullOrEmpty(participant.PrimaryCareProvider) && ValidReasonForRemoval)", + "Actions": { + "OnFailure": { + "Name": "OutputExpression", + "Context": { + "Expression": "\"Missing GP details\"" + } + } + } + }, + { + "RuleName": "98.ManualAddWithBlockingRFR.NBO.NonFatal", + "Expression": "reasonForRemovalLkp.CanRemovalReasonBeOverridden(participant.ReasonForRemoval)", + "Actions": { + "OnFailure": { + "Name": "OutputExpression", + "Context": { + "Expression": "\"Participant cannot be sent to BS Select due to reason for removal (RfR)\"" + } + } + } + } + ] } ] diff --git a/application/CohortManager/src/Functions/ScreeningValidationService/StaticValidation/Program.cs b/application/CohortManager/src/Functions/ScreeningValidationService/StaticValidation/Program.cs index cf9cd8bffb..370b0a9a92 100644 --- a/application/CohortManager/src/Functions/ScreeningValidationService/StaticValidation/Program.cs +++ b/application/CohortManager/src/Functions/ScreeningValidationService/StaticValidation/Program.cs @@ -10,6 +10,7 @@ { services.AddSingleton(); services.AddSingleton(); + services.AddSingleton(); // Register health checks services.AddBasicHealthCheck("StaticValidation"); }) diff --git a/application/CohortManager/src/Functions/ScreeningValidationService/StaticValidation/StaticValidation.cs b/application/CohortManager/src/Functions/ScreeningValidationService/StaticValidation/StaticValidation.cs index 65a5a2c690..03ce19b294 100644 --- a/application/CohortManager/src/Functions/ScreeningValidationService/StaticValidation/StaticValidation.cs +++ b/application/CohortManager/src/Functions/ScreeningValidationService/StaticValidation/StaticValidation.cs @@ -1,6 +1,7 @@ namespace NHS.CohortManager.ScreeningValidationService; using System.Net; +using System.Runtime.CompilerServices; using System.Text; using System.Text.Json; using System.Text.RegularExpressions; @@ -20,15 +21,18 @@ public class StaticValidation private readonly ILogger _logger; private readonly ICreateResponse _createResponse; private readonly IReadRules _readRules; + private readonly IReasonForRemovalLookup _reasonForRemovalLookup; public StaticValidation( ILogger logger, ICreateResponse createResponse, - IReadRules readRules) + IReadRules readRules, + IReasonForRemovalLookup reasonForRemovalLookup) { _logger = logger; _createResponse = createResponse; _readRules = readRules; + _reasonForRemovalLookup = reasonForRemovalLookup; } // TODO: refactor to accept a cohort distribution participant @@ -49,6 +53,7 @@ public async Task RunAsync([HttpTrigger(AuthorizationLevel.Ano _logger.LogInformation("ruleFileName: {RuleFileName}", ruleFileName); bool routineParticipant = (participantCsvRecord.Participant.ReferralFlag ?? "").ToLower() == "false"; + bool isManualAdd = ValidationHelper.CheckManualAddFileName(participantCsvRecord.FileName); var json = await _readRules.GetRulesFromDirectory(ruleFileName); var rules = JsonSerializer.Deserialize(json); @@ -62,7 +67,9 @@ public async Task RunAsync([HttpTrigger(AuthorizationLevel.Ano var re = new RulesEngine.RulesEngine(rules, reSettings); var ruleParameters = new[] { - new RuleParameter("participant", participantCsvRecord.Participant) + new RuleParameter("participant", participantCsvRecord.Participant), + new RuleParameter("reasonForRemovalLkp", _reasonForRemovalLookup), + new RuleParameter("manualAdd",isManualAdd) }; var resultList = new List(); @@ -77,6 +84,12 @@ public async Task RunAsync([HttpTrigger(AuthorizationLevel.Ano } } + if (isManualAdd) + { + var manualAddResults = await re.ExecuteAllRulesAsync("Manual_Add", ruleParameters); + resultList.AddRange(manualAddResults); + } + if (re.GetAllRegisteredWorkflowNames().Contains(participantCsvRecord.Participant.RecordType)) { _logger.LogInformation("Executing workflow {RecordType}", participantCsvRecord.Participant.RecordType); diff --git a/application/CohortManager/src/Functions/Shared/Common/ReasonForRemovalLookup/IReasonForRemovalLookup.cs b/application/CohortManager/src/Functions/Shared/Common/ReasonForRemovalLookup/IReasonForRemovalLookup.cs new file mode 100644 index 0000000000..edd8374cb1 --- /dev/null +++ b/application/CohortManager/src/Functions/Shared/Common/ReasonForRemovalLookup/IReasonForRemovalLookup.cs @@ -0,0 +1,6 @@ +namespace Common; + +public interface IReasonForRemovalLookup +{ + bool CanRemovalReasonBeOverridden(string? reasonForRemoval); +} diff --git a/application/CohortManager/src/Functions/Shared/Common/ReasonForRemovalLookup/ReasonForRemovalLookup.cs b/application/CohortManager/src/Functions/Shared/Common/ReasonForRemovalLookup/ReasonForRemovalLookup.cs new file mode 100644 index 0000000000..9911e35dce --- /dev/null +++ b/application/CohortManager/src/Functions/Shared/Common/ReasonForRemovalLookup/ReasonForRemovalLookup.cs @@ -0,0 +1,34 @@ +namespace Common; + +public class ReasonForRemovalLookup : IReasonForRemovalLookup +{ + + private readonly List NonOverridableRFRs; + public ReasonForRemovalLookup() + { + NonOverridableRFRs = new List + { + "AFL", + "AFN", + "DEA", + "LDN", + "SDL", + "SDN", + "TRA" + }; + } + public bool CanRemovalReasonBeOverridden(string? reasonForRemoval) + { + if(reasonForRemoval is null) + { + return true; + } + + if (NonOverridableRFRs.Contains(reasonForRemoval.ToUpper())) + { + return false; + } + return true; + } + +} diff --git a/application/CohortManager/src/Functions/Shared/Common/TransformDataRequestBody.cs b/application/CohortManager/src/Functions/Shared/Common/TransformDataRequestBody.cs index 929e646f81..0df72ccb28 100644 --- a/application/CohortManager/src/Functions/Shared/Common/TransformDataRequestBody.cs +++ b/application/CohortManager/src/Functions/Shared/Common/TransformDataRequestBody.cs @@ -7,4 +7,5 @@ public class TransformDataRequestBody public CohortDistributionParticipant Participant { get; set; } public CohortDistribution ExistingParticipant { get; set; } public string? ServiceProvider { get; set; } + public string? FileName {get;set;} } diff --git a/application/CohortManager/src/Functions/Shared/Common/ValidationHelper.cs b/application/CohortManager/src/Functions/Shared/Common/ValidationHelper.cs index 6c2818ba64..2ddb5168eb 100644 --- a/application/CohortManager/src/Functions/Shared/Common/ValidationHelper.cs +++ b/application/CohortManager/src/Functions/Shared/Common/ValidationHelper.cs @@ -125,6 +125,23 @@ public static bool ValidatePostcode(string postcode) string outcode = match.Groups[1].Value; return outcode.ToUpper(); } + /// + /// Checks that a file name is a parquet file to see if a Routine or a manual add + /// + /// + /// true is its a manualAdd + public static bool CheckManualAddFileName(string? FileName) + { + if(string.IsNullOrEmpty(FileName)) + { + return false; + } + if (FileName.ToLower().EndsWith(".parquet")) + { + return false; + } + return true; + } private static bool ParseInt32(char value, out int integerValue) { diff --git a/tests/UnitTests/ScreeningValidationServiceTests/StaticValidation/StaticValidationTests.cs b/tests/UnitTests/ScreeningValidationServiceTests/StaticValidation/StaticValidationTests.cs index 4c32dda7b5..b0a974a82b 100644 --- a/tests/UnitTests/ScreeningValidationServiceTests/StaticValidation/StaticValidationTests.cs +++ b/tests/UnitTests/ScreeningValidationServiceTests/StaticValidation/StaticValidationTests.cs @@ -27,6 +27,7 @@ public class StaticValidationTests private readonly CreateResponse _createResponse = new(); private readonly ServiceCollection _serviceCollection = new(); private readonly ParticipantCsvRecord _participantCsvRecord; + private readonly IReasonForRemovalLookup _reasonForRemovalLookup; private readonly StaticValidation _function; public StaticValidationTests() @@ -37,10 +38,13 @@ public StaticValidationTests() _context.SetupProperty(c => c.InstanceServices, serviceProvider); + _reasonForRemovalLookup = new ReasonForRemovalLookup(); + _function = new StaticValidation( _logger.Object, _createResponse, - new ReadRules(new NullLogger()) + new ReadRules(new NullLogger()), + _reasonForRemovalLookup ); _request.Setup(r => r.CreateResponse()).Returns(() => @@ -54,7 +58,7 @@ public StaticValidationTests() _participantCsvRecord = new ParticipantCsvRecord() { - FileName = "test", + FileName = "test.parquet", Participant = new Participant() { ScreeningName = "Breast Screening", @@ -637,7 +641,120 @@ public async Task Run_CompatibleCurrentPostingAndPrimaryCareProvider_ReturnNoCon Assert.AreEqual(HttpStatusCode.NoContent, response.StatusCode); } #endregion + #region Manual add rule 97 Missing GP details (and no accepted reason for removal) + [TestMethod] + [DataRow("A12345",null)] + [DataRow("ZZZZYZ","RPR")] + [DataRow("ZZZZYZ","RDI")] + [DataRow("ZZZZYZ","RDR")] + [DataRow(null,"RDR")] + [DataRow(null,"RDI")] + [DataRow(null,"RPR")] + public async Task Run_ManualAddWithGPCode_ReturnsNoContent(string? primaryCareProvider,string? reasonForRemoval) + { + // Arrange + _participantCsvRecord.Participant.CurrentPosting = "BAA"; + _participantCsvRecord.Participant.PrimaryCareProvider = primaryCareProvider; + _participantCsvRecord.Participant.ReasonForRemoval = reasonForRemoval; + + _participantCsvRecord.Participant.RecordType = Actions.New; + _participantCsvRecord.FileName = "CS0573848"; + var json = JsonSerializer.Serialize(_participantCsvRecord); + SetUpRequestBody(json); + + // Act + var response = await _function.RunAsync(_request.Object); + string body = await AssertionHelper.ReadResponseBodyAsync(response); + // Assert + Assert.AreEqual(HttpStatusCode.NoContent, response.StatusCode); + + } + [TestMethod] + [DataRow("AFL")] + [DataRow("RDI")] + [DataRow("NIT")] + [DataRow(null)] + public async Task Run_ManualAddWithoutGPCode_ReturnValidationException(string? reasonForRemoval) + { + // Arrange + _participantCsvRecord.Participant.CurrentPosting = "BAA"; + _participantCsvRecord.Participant.PrimaryCareProvider = null; + + _participantCsvRecord.Participant.RecordType = Actions.New; + _participantCsvRecord.FileName = "CS0573848"; + var json = JsonSerializer.Serialize(_participantCsvRecord); + SetUpRequestBody(json); + + // Act + var response = await _function.RunAsync(_request.Object); + + // Assert + string body = await AssertionHelper.ReadResponseBodyAsync(response); + Assert.AreEqual(HttpStatusCode.OK,response.StatusCode); + StringAssert.Contains(body, "97.NoDummyGPorPCP.NBO.NonFatal"); + + } + + #endregion + #region Rule 98 Participant cannot be sent to BS Select due to reason for removal (RfR) + [TestMethod] + [DataRow(null)] + [DataRow("CGA")] + [DataRow("NIT")] + [DataRow("EMB")] + [DataRow("SCT")] + [DataRow("OPA")] + [DataRow("RDR")] + [DataRow("RPR")] + [DataRow("RPI")] + public async Task Run_ManualAddWithOverridableReasonForRemoval_ReturnsNoContent(string? reasonForRemoval) + { + // Arrange + _participantCsvRecord.Participant.CurrentPosting = "BAA"; + _participantCsvRecord.Participant.RecordType = Actions.New; + _participantCsvRecord.FileName = "CS0573848"; + _participantCsvRecord.Participant.PrimaryCareProvider = "ZZZXYZ"; + _participantCsvRecord.Participant.ReasonForRemoval = reasonForRemoval; + var json = JsonSerializer.Serialize(_participantCsvRecord); + SetUpRequestBody(json); + + // Act + var response = await _function.RunAsync(_request.Object); + string body = await AssertionHelper.ReadResponseBodyAsync(response); + // Assert + Assert.AreEqual(HttpStatusCode.NoContent, response.StatusCode); + } + [TestMethod] + [DataRow("AFL")] + [DataRow("AFN")] + [DataRow("DEA")] + [DataRow("LDN")] + [DataRow("SDL")] + [DataRow("SDN")] + [DataRow("TRA")] + public async Task Run_ManualAddWithoutOverridableReasonForRemoval_ReturnsValidationException(string? reasonForRemoval) + { + // Arrange + _participantCsvRecord.Participant.CurrentPosting = "BAA"; + _participantCsvRecord.Participant.RecordType = Actions.New; + _participantCsvRecord.FileName = "CS0573848"; + _participantCsvRecord.Participant.ReasonForRemoval = reasonForRemoval; + var json = JsonSerializer.Serialize(_participantCsvRecord); + SetUpRequestBody(json); + + // Act + var response = await _function.RunAsync(_request.Object); + + // Assert + string body = await AssertionHelper.ReadResponseBodyAsync(response); + Assert.AreEqual(HttpStatusCode.OK,response.StatusCode); + StringAssert.Contains(body, "98.ManualAddWithBlockingRFR.NBO.NonFatal"); + + } + + + #endregion [TestMethod] public async Task Run_ValidParticipantFile_ReturnNoContent() { diff --git a/tests/UnitTests/TransformDataServiceTests/TransformDataServiceTests/TransformDataServiceTests.cs b/tests/UnitTests/TransformDataServiceTests/TransformDataServiceTests/TransformDataServiceTests.cs index f43afaed4f..ecea1d9a44 100644 --- a/tests/UnitTests/TransformDataServiceTests/TransformDataServiceTests/TransformDataServiceTests.cs +++ b/tests/UnitTests/TransformDataServiceTests/TransformDataServiceTests/TransformDataServiceTests.cs @@ -27,6 +27,7 @@ public class TransformDataServiceTests private readonly Mock _handleException = new(); private readonly Mock _transformLookups = new(); private readonly ITransformReasonForRemoval _transformReasonForRemoval; + private readonly IReasonForRemovalLookup _reasonForRemovalLookup; public TransformDataServiceTests() { @@ -55,16 +56,19 @@ public TransformDataServiceTests() { Participant = requestParticipant, ExistingParticipant = databaseParticipant, - ServiceProvider = "1" + ServiceProvider = "1", + FileName = "test.parquet" }; + _reasonForRemovalLookup = new ReasonForRemovalLookup(); + _transformLookups.Setup(x => x.ValidateOutcode(It.IsAny())).Returns(true); _transformLookups.Setup(x => x.GetBsoCode(It.IsAny())).Returns("ELD"); _transformLookups.Setup(x => x.GetBsoCodeUsingPCP(It.IsAny())).Returns("ELD"); _transformLookups.Setup(x => x.ValidateLanguageCode(It.IsAny())).Returns(true); _transformReasonForRemoval = new TransformReasonForRemoval(_handleException.Object, _transformLookups.Object); - _function = new TransformDataService(_createResponse.Object, _handleException.Object, _logger.Object, _transformReasonForRemoval, _transformLookups.Object); + _function = new TransformDataService(_createResponse.Object, _handleException.Object, _logger.Object, _transformReasonForRemoval, _transformLookups.Object, _reasonForRemovalLookup); _request.Setup(r => r.CreateResponse()).Returns(() => { @@ -943,6 +947,73 @@ public async Task Run_ZZZSECURPostcode_TransformPostcode() Assert.AreEqual("ZZ99 3VZ", actualResponse?.Postcode); } + [TestMethod] + [DataRow("CGA")] + [DataRow("DIS")] + [DataRow("EMB")] + [DataRow("NIT")] + [DataRow("OPA")] + [DataRow("ORR")] + [DataRow("RDI")] + [DataRow("RDR")] + [DataRow("RPR")] + [DataRow("RFI")] + [DataRow("SCT")] + public async Task Run_ManualAddRemovableRfR_RemovesRFR(string ReasonForRemoval) + { + // Arrange + _requestBody.FileName = "CS0848402"; + _requestBody.Participant.PrimaryCareProvider = "ZZZXYZ"; + _requestBody.Participant.ReasonForRemoval = ReasonForRemoval; + _requestBody.Participant.ReasonForRemovalEffectiveFromDate = DateTime.UtcNow.ToString(); + + var json = JsonSerializer.Serialize(_requestBody); + SetUpRequestBody(json); + + // Act + var result = await _function.RunAsync(_request.Object); + + // Assert + Assert.AreEqual(HttpStatusCode.OK, result.StatusCode); + + string responseBody = await AssertionHelper.ReadResponseBodyAsync(result); + var actualResponse = JsonSerializer.Deserialize(responseBody); + + Assert.IsNull(actualResponse!.ReasonForRemoval); + Assert.IsNull(actualResponse!.ReasonForRemovalEffectiveFromDate); + } + [TestMethod] + [DataRow("AFL")] + [DataRow("AFN")] + [DataRow("DEA")] + [DataRow("LDN")] + [DataRow("SDL")] + [DataRow("SDN")] + [DataRow("TRA")] + public async Task Run_ManualAddNonRemovableRfR_HasRFR(string ReasonForRemoval) + { + // Arrange + _requestBody.FileName = "CS0848402"; + _requestBody.Participant.PrimaryCareProvider = "ZZZXYZ"; + _requestBody.Participant.ReasonForRemoval = ReasonForRemoval; + var timestamp = DateTime.UtcNow.ToString(); + _requestBody.Participant.ReasonForRemovalEffectiveFromDate = timestamp; + + var json = JsonSerializer.Serialize(_requestBody); + SetUpRequestBody(json); + + // Act + var result = await _function.RunAsync(_request.Object); + + // Assert + Assert.AreEqual(HttpStatusCode.OK, result.StatusCode); + + string responseBody = await AssertionHelper.ReadResponseBodyAsync(result); + var actualResponse = JsonSerializer.Deserialize(responseBody); + + Assert.AreEqual(ReasonForRemoval,actualResponse!.ReasonForRemoval); + Assert.IsNotNull(actualResponse!.ReasonForRemovalEffectiveFromDate); + } private void SetUpRequestBody(string json) {