Skip to content

Commit

Permalink
Merge pull request #267 from nhsconnect/PRMP-534
Browse files Browse the repository at this point in the history
PRMP-534 ORC IN NACK POC
  • Loading branch information
AndyFlintNHS authored Jul 9, 2024
2 parents 80cd2f3 + 2ebb8c3 commit 66fce12
Show file tree
Hide file tree
Showing 11 changed files with 161 additions and 36 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package uk.nhs.prm.repo.ehrtransferservice.exceptions.acknowledgement;

import uk.nhs.prm.repo.ehrtransferservice.exceptions.base.AcknowledgementException;

import java.util.UUID;

public class NegativeAcknowledgementFailedException extends AcknowledgementException {
private static final String EXCEPTION_MESSAGE =
"Failed to send a Negative Acknowledgement with error code %s for Inbound Conversation ID %s";

public NegativeAcknowledgementFailedException(String errorCode, UUID inboundConversationId, Throwable cause) {
super(EXCEPTION_MESSAGE.formatted(errorCode, inboundConversationId.toString().toUpperCase()), cause);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package uk.nhs.prm.repo.ehrtransferservice.gp2gp_message_models;

import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
import lombok.Getter;

@Getter
public abstract class Gp2gpMessengerAcknowledgementRequestBody {
protected final String repositoryAsid;
protected final String odsCode;
protected final String conversationId;
protected final String messageId;

protected Gp2gpMessengerAcknowledgementRequestBody(
@JsonProperty("repositoryAsid") String repositoryAsid,
@JsonProperty("odsCode") String odsCode,
@JsonProperty("conversationId") String conversationId,
@JsonProperty("messageId") String messageId
) {
this.repositoryAsid = repositoryAsid;
this.odsCode = odsCode;
this.conversationId = conversationId;
this.messageId = messageId;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package uk.nhs.prm.repo.ehrtransferservice.gp2gp_message_models;

import lombok.Getter;
import uk.nhs.prm.repo.ehrtransferservice.models.enums.AcknowledgementErrorCode;

@Getter
public class Gp2gpMessengerNegativeAcknowledgementRequestBody extends Gp2gpMessengerAcknowledgementRequestBody {
private final String errorCode;
private final String errorDisplayName;

public Gp2gpMessengerNegativeAcknowledgementRequestBody(
String repositoryAsid,
String odsCode,
String conversationId,
String messageId,
AcknowledgementErrorCode acknowledgementErrorCode
) {
super(repositoryAsid, odsCode, conversationId, messageId);
this.errorCode = acknowledgementErrorCode.errorCode;
this.errorDisplayName = acknowledgementErrorCode.displayName;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,13 @@
import lombok.Data;

@Data
public class Gp2gpMessengerPositiveAcknowledgementRequestBody {
private final String repositoryAsid;
private final String odsCode;
private final String conversationId;
private final String messageId;

public Gp2gpMessengerPositiveAcknowledgementRequestBody(@JsonProperty("repositoryAsid") String repositoryAsid,
@JsonProperty("odsCode") String odsCode,
@JsonProperty("conversationId") String conversationId,
@JsonProperty("messageId") String messageId
public class Gp2gpMessengerPositiveAcknowledgementRequestBody extends Gp2gpMessengerAcknowledgementRequestBody{
public Gp2gpMessengerPositiveAcknowledgementRequestBody(
String repositoryAsid,
String odsCode,
String conversationId,
String messageId
) {
this.repositoryAsid = repositoryAsid;
this.odsCode = odsCode;
this.conversationId = conversationId;
this.messageId = messageId;
super(repositoryAsid, odsCode, conversationId, messageId);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package uk.nhs.prm.repo.ehrtransferservice.models.enums;

import lombok.AllArgsConstructor;

@AllArgsConstructor
public enum AcknowledgementErrorCode {
ERROR_CODE_06("06", "Patient not at surgery"),
ERROR_CODE_09("09", "EHR Extract received without corresponding request"),
ERROR_CODE_10("10", "Failed to successfully generate EHR Extract"),
ERROR_CODE_12("12", "Duplicate EHR Extract received");

public final String errorCode;
public final String displayName;
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import uk.nhs.prm.repo.ehrtransferservice.models.confirmmessagestored.StoreMessageRequestBody;
import uk.nhs.prm.repo.ehrtransferservice.models.confirmmessagestored.StoreMessageResponseBody;
import uk.nhs.prm.repo.ehrtransferservice.services.PresignedUrl;
import uk.nhs.prm.repo.ehrtransferservice.services.gp2gp_messenger.Gp2gpMessengerService;

import java.io.IOException;
import java.net.MalformedURLException;
Expand All @@ -24,6 +25,8 @@
import java.net.http.HttpResponse;
import java.util.UUID;

import static uk.nhs.prm.repo.ehrtransferservice.models.enums.AcknowledgementErrorCode.ERROR_CODE_12;

@Slf4j
@Service
public class EhrRepoClient {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,38 +2,63 @@

import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import uk.nhs.prm.repo.ehrtransferservice.exceptions.DuplicateMessageException;
import uk.nhs.prm.repo.ehrtransferservice.gp2gp_message_models.ParsedMessage;
import uk.nhs.prm.repo.ehrtransferservice.services.ConversationActivityService;
import uk.nhs.prm.repo.ehrtransferservice.services.PresignedUrl;
import uk.nhs.prm.repo.ehrtransferservice.services.gp2gp_messenger.Gp2gpMessengerService;

import java.util.UUID;

import static uk.nhs.prm.repo.ehrtransferservice.models.enums.AcknowledgementErrorCode.ERROR_CODE_12;

@Service
@Slf4j
public class EhrRepoService {
private final EhrRepoClient ehrRepoClient;
private final ConversationActivityService activityService;
private final Gp2gpMessengerService gp2gpMessengerService;

public EhrRepoService(
EhrRepoClient ehrRepoClient,
ConversationActivityService conversationActivityService
EhrRepoClient ehrRepoClient,
ConversationActivityService conversationActivityService,
Gp2gpMessengerService gp2gpMessengerService
) {
this.ehrRepoClient = ehrRepoClient;
this.activityService = conversationActivityService;
this.gp2gpMessengerService = gp2gpMessengerService;
}

public StoreMessageResult storeMessage(ParsedMessage parsedMessage) throws Exception {
activityService.captureConversationActivity(parsedMessage.getConversationId());

PresignedUrl presignedUrl = ehrRepoClient.fetchStorageUrl(parsedMessage.getConversationId(), parsedMessage.getMessageId());
log.info("Retrieved Presigned URL");
presignedUrl.uploadMessage(parsedMessage);
log.info("Uploaded message to S3");
var confirmedMessageStored = ehrRepoClient.confirmMessageStored(parsedMessage);
log.info("Message stored in EHR Repo");
return new StoreMessageResult(confirmedMessageStored);
UUID conversationId = parsedMessage.getConversationId();
UUID messageId = parsedMessage.getMessageId();

activityService.captureConversationActivity(conversationId);

try {
PresignedUrl presignedUrl = ehrRepoClient.fetchStorageUrl(conversationId, messageId);
log.info("Retrieved Presigned URL");
presignedUrl.uploadMessage(parsedMessage);
log.info("Uploaded message to S3");
var confirmedMessageStored = ehrRepoClient.confirmMessageStored(parsedMessage);
log.info("Message stored in EHR Repo");
return new StoreMessageResult(confirmedMessageStored);
} catch (Exception exception) {
sendNegativeAcknowledgement(exception, conversationId);
throw exception;
}
}

@Deprecated
public void softDeleteEhrRecord(String nhsNumber) {
this.ehrRepoClient.softDeleteEhrRecord(nhsNumber);
}

private void sendNegativeAcknowledgement(Exception exception, UUID conversationId) {
switch (exception) {
case DuplicateMessageException e ->
gp2gpMessengerService.sendNegativeAcknowledgement(conversationId, ERROR_CODE_12);
default -> {} // Do nothing
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import uk.nhs.prm.repo.ehrtransferservice.gp2gp_message_models.Gp2gpMessengerAcknowledgementRequestBody;
import uk.nhs.prm.repo.ehrtransferservice.logging.Tracer;
import uk.nhs.prm.repo.ehrtransferservice.exceptions.HttpException;
import uk.nhs.prm.repo.ehrtransferservice.gp2gp_message_models.Gp2gpMessengerContinueMessageRequestBody;
import uk.nhs.prm.repo.ehrtransferservice.gp2gp_message_models.Gp2gpMessengerEhrRequestBody;
import uk.nhs.prm.repo.ehrtransferservice.gp2gp_message_models.Gp2gpMessengerPositiveAcknowledgementRequestBody;

import java.io.IOException;
import java.net.MalformedURLException;
Expand Down Expand Up @@ -47,7 +47,7 @@ public void sendGp2gpMessengerEhrRequest(String nhsNumber, Gp2gpMessengerEhrRequ
}
}

public void sendGp2gpMessengerPositiveAcknowledgement(String nhsNumber, Gp2gpMessengerPositiveAcknowledgementRequestBody body) throws IOException, URISyntaxException, InterruptedException, HttpException {
public void sendGp2gpMessengerAcknowledgement(String nhsNumber, Gp2gpMessengerAcknowledgementRequestBody body) throws IOException, URISyntaxException, InterruptedException, HttpException {
String jsonPayloadString = new Gson().toJson(body);
HttpRequest.BodyPublisher jsonPayload = HttpRequest.BodyPublishers.ofString(jsonPayloadString);
String endpoint = "/health-record-requests/" + nhsNumber + "/acknowledgement";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,9 @@
import uk.nhs.prm.repo.ehrtransferservice.database.model.ConversationRecord;
import uk.nhs.prm.repo.ehrtransferservice.exceptions.HttpException;
import uk.nhs.prm.repo.ehrtransferservice.exceptions.acknowledgement.EhrCompleteAcknowledgementFailedException;
import uk.nhs.prm.repo.ehrtransferservice.gp2gp_message_models.Gp2gpMessengerContinueMessageRequestBody;
import uk.nhs.prm.repo.ehrtransferservice.gp2gp_message_models.Gp2gpMessengerEhrRequestBody;
import uk.nhs.prm.repo.ehrtransferservice.gp2gp_message_models.Gp2gpMessengerPositiveAcknowledgementRequestBody;
import uk.nhs.prm.repo.ehrtransferservice.gp2gp_message_models.ParsedMessage;
import uk.nhs.prm.repo.ehrtransferservice.exceptions.acknowledgement.NegativeAcknowledgementFailedException;
import uk.nhs.prm.repo.ehrtransferservice.gp2gp_message_models.*;
import uk.nhs.prm.repo.ehrtransferservice.models.enums.AcknowledgementErrorCode;
import uk.nhs.prm.repo.ehrtransferservice.repo_incoming.RepoIncomingEvent;

import java.io.IOException;
Expand Down Expand Up @@ -78,11 +77,41 @@ public void sendEhrCompletePositiveAcknowledgement(UUID inboundConversationId) {
);

try {
gp2gpMessengerClient.sendGp2gpMessengerPositiveAcknowledgement(record.nhsNumber(), requestBody);
gp2gpMessengerClient.sendGp2gpMessengerAcknowledgement(record.nhsNumber(), requestBody);
log.info("EHR complete positive acknowledgement sent for Inbound Conversation ID {}", inboundConversationId.toString().toUpperCase());
} catch (IOException | URISyntaxException | InterruptedException | HttpException exception) {
log.error("An exception occurred while sending an EHR complete positive acknowledgement {}", exception.getMessage());
throw new EhrCompleteAcknowledgementFailedException(inboundConversationId, exception);
}
}

public void sendNegativeAcknowledgement(
UUID inboundConversationId,
AcknowledgementErrorCode acknowledgementErrorCode
) {
final ConversationRecord record =
transferService.getConversationByInboundConversationId(inboundConversationId);

final UUID ehrCoreMessageId =
transferService.getEhrCoreInboundMessageIdForInboundConversationId(inboundConversationId);

final var requestBody = new Gp2gpMessengerNegativeAcknowledgementRequestBody(
repositoryAsid,
record.sourceGp(),
inboundConversationId.toString().toUpperCase(),
ehrCoreMessageId.toString().toUpperCase(),
acknowledgementErrorCode
);

try {
gp2gpMessengerClient.sendGp2gpMessengerAcknowledgement(record.nhsNumber(), requestBody);
log.info("Negative acknowledgement with code {} sent for Inbound Conversation ID {}",
requestBody.getErrorCode(), inboundConversationId.toString().toUpperCase());
} catch (IOException | URISyntaxException | InterruptedException | HttpException exception) {
log.error("An exception occurred while sending a negative acknowledgement with code {} " +
"sent for Inbound Conversation ID {}. Exception message is: {}",
requestBody.getErrorCode(), inboundConversationId.toString().toUpperCase(), exception.getMessage());
throw new NegativeAcknowledgementFailedException(acknowledgementErrorCode.errorCode, inboundConversationId, exception);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ void shouldCallGP2GpMessengerPositiveRequest() throws IOException, URISyntaxExce
tracer.directlyUpdateTraceIdButNotConversationId("some-trace-id");

Gp2gpMessengerClient gp2gpMessengerClient = new Gp2gpMessengerClient(wireMockServer.baseUrl(), "secret", tracer);
gp2gpMessengerClient.sendGp2gpMessengerPositiveAcknowledgement("1234567890", requestBody);
gp2gpMessengerClient.sendGp2gpMessengerAcknowledgement("1234567890", requestBody);

verify(postRequestedFor(urlMatching("/health-record-requests/1234567890/acknowledgement"))
.withRequestBody(equalToJson((jsonPayloadString)))
Expand All @@ -122,7 +122,7 @@ void shouldThrowHTTPExceptionWhenWeGotAnyStatusCodeButNot204ForPositiveAcknowled
tracer.directlyUpdateTraceIdButNotConversationId("some-trace-id");

Gp2gpMessengerClient gp2gpMessengerClient = new Gp2gpMessengerClient(wireMockServer.baseUrl(), "secret", tracer);
assertThrows(HttpException.class, () -> gp2gpMessengerClient.sendGp2gpMessengerPositiveAcknowledgement("1234567890", requestBody));
assertThrows(HttpException.class, () -> gp2gpMessengerClient.sendGp2gpMessengerAcknowledgement("1234567890", requestBody));
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ void sendEhrCompletePositiveAcknowledgement_ExistingInboundConversationId_SendGp
gp2gpMessengerService.sendEhrCompletePositiveAcknowledgement(INBOUND_CONVERSATION_ID);

// then
verify(gp2gpMessengerClient).sendGp2gpMessengerPositiveAcknowledgement(
verify(gp2gpMessengerClient).sendGp2gpMessengerAcknowledgement(
eq(NHS_NUMBER),
gp2gpMessengerPositiveAcknowledgementRequestBodyArgumentCaptor.capture()
);
Expand All @@ -141,7 +141,7 @@ void sendEhrCompletePositiveAcknowledgement_SendGp2gpMessengerPositiveAcknowledg
when(conversationRecord.nhsNumber()).thenReturn(NHS_NUMBER);
doThrow(exception)
.when(gp2gpMessengerClient)
.sendGp2gpMessengerPositiveAcknowledgement(
.sendGp2gpMessengerAcknowledgement(
any(String.class),
gp2gpMessengerPositiveAcknowledgementRequestBodyArgumentCaptor.capture()
);
Expand Down

0 comments on commit 66fce12

Please sign in to comment.