-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Create endpoint for resending an EhrExtract (#990)
--------- Co-authored-by: hospel <[email protected]>
- Loading branch information
1 parent
bf88ffd
commit bde8dcc
Showing
4 changed files
with
443 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
130 changes: 130 additions & 0 deletions
130
service/src/main/java/uk/nhs/adaptors/gp2gp/ehr/EhrResendController.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,130 @@ | ||
package uk.nhs.adaptors.gp2gp.ehr; | ||
|
||
import lombok.AllArgsConstructor; | ||
import lombok.extern.slf4j.Slf4j; | ||
import org.hl7.fhir.dstu3.model.CodeableConcept; | ||
import org.hl7.fhir.dstu3.model.Coding; | ||
import org.hl7.fhir.dstu3.model.Meta; | ||
import org.hl7.fhir.dstu3.model.OperationOutcome; | ||
import org.hl7.fhir.dstu3.model.UriType; | ||
import org.springframework.beans.factory.annotation.Autowired; | ||
import org.springframework.http.HttpStatus; | ||
import org.springframework.http.ResponseEntity; | ||
import org.springframework.web.bind.annotation.PathVariable; | ||
import org.springframework.web.bind.annotation.PostMapping; | ||
import org.springframework.web.bind.annotation.RequestMapping; | ||
import org.springframework.web.bind.annotation.RestController; | ||
import uk.nhs.adaptors.gp2gp.common.service.FhirParseService; | ||
import uk.nhs.adaptors.gp2gp.common.service.RandomIdGeneratorService; | ||
import uk.nhs.adaptors.gp2gp.common.service.TimestampService; | ||
import uk.nhs.adaptors.gp2gp.common.task.TaskDispatcher; | ||
import uk.nhs.adaptors.gp2gp.ehr.model.EhrExtractStatus; | ||
import uk.nhs.adaptors.gp2gp.gpc.GetGpcStructuredTaskDefinition; | ||
|
||
import java.util.Collections; | ||
|
||
@Slf4j | ||
@RestController | ||
@AllArgsConstructor(onConstructor = @__(@Autowired)) | ||
@RequestMapping(path = "/ehr-resend") | ||
public class EhrResendController { | ||
|
||
private static final String OPERATION_OUTCOME_URL = "https://fhir.nhs.uk/STU3/StructureDefinition/GPConnect-OperationOutcome-1"; | ||
private static final String PRECONDITION_FAILED = "PRECONDITION_FAILED"; | ||
private static final String INVALID_IDENTIFIER_VALUE = "INVALID_IDENTIFIER_VALUE"; | ||
|
||
private EhrExtractStatusRepository ehrExtractStatusRepository; | ||
private TaskDispatcher taskDispatcher; | ||
private RandomIdGeneratorService randomIdGeneratorService; | ||
private final TimestampService timestampService; | ||
private final FhirParseService fhirParseService; | ||
|
||
@PostMapping("/{conversationId}") | ||
public ResponseEntity<String> scheduleEhrExtractResend(@PathVariable String conversationId) { | ||
EhrExtractStatus ehrExtractStatus = ehrExtractStatusRepository.findByConversationId(conversationId).orElseGet(() -> null); | ||
|
||
if (ehrExtractStatus == null) { | ||
var details = getCodeableConcept(INVALID_IDENTIFIER_VALUE); | ||
var diagnostics = "Provide a conversationId that exists and retry the operation"; | ||
|
||
var operationOutcome = createOperationOutcome(OperationOutcome.IssueType.VALUE, | ||
OperationOutcome.IssueSeverity.ERROR, | ||
details, | ||
diagnostics); | ||
var errorBody = fhirParseService.encodeToJson(operationOutcome); | ||
|
||
return new ResponseEntity<>(errorBody, HttpStatus.NOT_FOUND); | ||
} | ||
|
||
if (hasNoErrorsInEhrReceivedAcknowledgement(ehrExtractStatus) && ehrExtractStatus.getError() == null) { | ||
|
||
var details = getCodeableConcept(PRECONDITION_FAILED); | ||
var diagnostics = "The current resend operation is still in progress. Please wait for it to complete before retrying"; | ||
var operationOutcome = createOperationOutcome(OperationOutcome.IssueType.BUSINESSRULE, | ||
OperationOutcome.IssueSeverity.ERROR, | ||
details, | ||
diagnostics); | ||
var errorBody = fhirParseService.encodeToJson(operationOutcome); | ||
return new ResponseEntity<>(errorBody, HttpStatus.CONFLICT); | ||
} | ||
|
||
var updatedEhrExtractStatus = prepareEhrExtractStatusForNewResend(ehrExtractStatus); | ||
ehrExtractStatusRepository.save(updatedEhrExtractStatus); | ||
createGetGpcStructuredTask(updatedEhrExtractStatus); | ||
LOGGER.info("Scheduled GetGpcStructuredTask for resend of ConversationId: {}", conversationId); | ||
|
||
return new ResponseEntity<>(HttpStatus.ACCEPTED); | ||
} | ||
|
||
private static CodeableConcept getCodeableConcept(String codeableConceptCode) { | ||
return new CodeableConcept().addCoding( | ||
new Coding("https://fhir.nhs.uk/STU3/ValueSet/Spine-ErrorOrWarningCode-1", codeableConceptCode, null)); | ||
} | ||
|
||
private static boolean hasNoErrorsInEhrReceivedAcknowledgement(EhrExtractStatus ehrExtractStatus) { | ||
var ehrReceivedAcknowledgement = ehrExtractStatus.getEhrReceivedAcknowledgement(); | ||
if (ehrReceivedAcknowledgement == null) { | ||
return true; | ||
} | ||
|
||
var errors = ehrReceivedAcknowledgement.getErrors(); | ||
if (errors == null || errors.isEmpty()) { | ||
return true; | ||
} | ||
return false; | ||
} | ||
|
||
private EhrExtractStatus prepareEhrExtractStatusForNewResend(EhrExtractStatus ehrExtractStatus) { | ||
|
||
var now = timestampService.now(); | ||
ehrExtractStatus.setUpdatedAt(now); | ||
ehrExtractStatus.setMessageTimestamp(now); | ||
ehrExtractStatus.setEhrExtractCorePending(null); | ||
ehrExtractStatus.setGpcAccessDocument(null); | ||
ehrExtractStatus.setEhrContinue(null); | ||
ehrExtractStatus.setEhrReceivedAcknowledgement(null); | ||
|
||
return ehrExtractStatus; | ||
} | ||
|
||
private void createGetGpcStructuredTask(EhrExtractStatus ehrExtractStatus) { | ||
var getGpcStructuredTaskDefinition = GetGpcStructuredTaskDefinition.getGetGpcStructuredTaskDefinition(randomIdGeneratorService, | ||
ehrExtractStatus); | ||
taskDispatcher.createTask(getGpcStructuredTaskDefinition); | ||
} | ||
|
||
public static OperationOutcome createOperationOutcome( | ||
OperationOutcome.IssueType type, OperationOutcome.IssueSeverity severity, CodeableConcept details, String diagnostics) { | ||
var operationOutcome = new OperationOutcome(); | ||
Meta meta = new Meta(); | ||
meta.setProfile(Collections.singletonList(new UriType(OPERATION_OUTCOME_URL))); | ||
operationOutcome.setMeta(meta); | ||
operationOutcome.addIssue() | ||
.setCode(type) | ||
.setSeverity(severity) | ||
.setDetails(details) | ||
.setDiagnostics(diagnostics); | ||
return operationOutcome; | ||
} | ||
|
||
} |
64 changes: 64 additions & 0 deletions
64
service/src/test/java/uk/nhs/adaptors/gp2gp/common/service/FhirParseServiceTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
package uk.nhs.adaptors.gp2gp.common.service; | ||
|
||
import com.fasterxml.jackson.core.JsonProcessingException; | ||
import com.fasterxml.jackson.databind.JsonNode; | ||
import com.fasterxml.jackson.databind.ObjectMapper; | ||
import org.hl7.fhir.dstu3.model.CodeableConcept; | ||
import org.hl7.fhir.dstu3.model.Coding; | ||
import org.hl7.fhir.dstu3.model.OperationOutcome; | ||
import org.junit.jupiter.api.BeforeEach; | ||
import org.junit.jupiter.api.Test; | ||
import org.junit.jupiter.api.extension.ExtendWith; | ||
import org.mockito.junit.jupiter.MockitoExtension; | ||
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder; | ||
import uk.nhs.adaptors.gp2gp.common.configuration.ObjectMapperBean; | ||
import uk.nhs.adaptors.gp2gp.ehr.EhrResendController; | ||
import java.util.List; | ||
import static org.junit.jupiter.api.Assertions.assertEquals; | ||
|
||
|
||
@ExtendWith(MockitoExtension.class) | ||
class FhirParseServiceTest { | ||
|
||
public static final String INVALID_IDENTIFIER_VALUE = "INVALID_IDENTIFIER_VALUE"; | ||
private static final String OPERATION_OUTCOME_URL = "https://fhir.nhs.uk/STU3/StructureDefinition/GPConnect-OperationOutcome-1"; | ||
private OperationOutcome operationOutcome; | ||
private ObjectMapper objectMapper; | ||
|
||
@BeforeEach | ||
void setUp() { | ||
ObjectMapperBean objectMapperBean = new ObjectMapperBean(); | ||
objectMapper = objectMapperBean.objectMapper(new Jackson2ObjectMapperBuilder()); | ||
|
||
var details = getCodeableConcept(); | ||
var diagnostics = "Provide a conversationId that exists and retry the operation"; | ||
operationOutcome = EhrResendController.createOperationOutcome(OperationOutcome.IssueType.VALUE, | ||
OperationOutcome.IssueSeverity.ERROR, | ||
details, | ||
diagnostics); | ||
} | ||
|
||
@Test | ||
void ableToEncodeOperationOutcomeToJson() throws JsonProcessingException { | ||
FhirParseService fhirParseService = new FhirParseService(); | ||
|
||
String convertedToJsonOperationOutcome = fhirParseService.encodeToJson(operationOutcome); | ||
|
||
JsonNode rootNode = objectMapper.readTree(convertedToJsonOperationOutcome); | ||
String code = | ||
rootNode.path("issue").get(0).path("details").path("coding").get(0).path("code").asText(); | ||
String operationOutcomeUrl = rootNode.path("meta").path("profile").get(0).asText(); | ||
|
||
assertEquals(INVALID_IDENTIFIER_VALUE, code); | ||
assertEquals(OPERATION_OUTCOME_URL, operationOutcomeUrl); | ||
} | ||
|
||
private static CodeableConcept getCodeableConcept() { | ||
var details = new CodeableConcept(); | ||
var codeableConceptCoding = new Coding(); | ||
codeableConceptCoding.setSystem("http://fhir.nhs.net/ValueSet/gpconnect-error-or-warning-code-1"); | ||
codeableConceptCoding.setCode(FhirParseServiceTest.INVALID_IDENTIFIER_VALUE); | ||
details.setCoding(List.of(codeableConceptCoding)); | ||
return details; | ||
} | ||
} |
Oops, something went wrong.