4312 add support for member identifier parameter return from $member match operation (#4314)
* added failing test * implemented solution * added change log * removed special character in change log file name * added check for member identifier of type MB * changed msg code to latest * fixed test for updated msg code Co-authored-by: Steven Li <steven@smilecdr.com>
This commit is contained in:
parent
403016f846
commit
0e59665711
|
@ -211,6 +211,8 @@ public class Constants {
|
|||
* $member-match operation
|
||||
*/
|
||||
public static final String PARAM_MEMBER_PATIENT = "MemberPatient";
|
||||
public static final String PARAM_MEMBER_IDENTIFIER = "MemberIdentifier";
|
||||
|
||||
public static final String PARAM_OLD_COVERAGE = "OldCoverage";
|
||||
public static final String PARAM_NEW_COVERAGE = "NewCoverage";
|
||||
public static final String PARAM_CONSENT = "Consent";
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
type: add
|
||||
issue: 4312
|
||||
title: "Previously, when $member-match operation is executed, the parameters that were returned did not include the member identifier as a parameter.
|
||||
This has now been added, and the consent resource is now updated with this identifier that's being returned."
|
|
@ -29,10 +29,10 @@ import ca.uhn.fhir.rest.api.Constants;
|
|||
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
||||
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
|
||||
import ca.uhn.fhir.rest.server.provider.ProviderConstants;
|
||||
import org.hl7.fhir.r4.model.Consent;
|
||||
import org.hl7.fhir.r4.model.Coverage;
|
||||
import org.hl7.fhir.r4.model.Parameters;
|
||||
import org.hl7.fhir.r4.model.Patient;
|
||||
import org.hl7.fhir.r4.model.Consent;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.util.Optional;
|
||||
|
@ -120,7 +120,7 @@ public class MemberMatchR4ResourceProvider {
|
|||
}
|
||||
|
||||
myMemberMatcherR4Helper.addMemberIdentifierToMemberPatient(theMemberPatient, patient.getIdentifierFirstRep());
|
||||
myMemberMatcherR4Helper.updateConsentForMemberMatch(theConsent, patient);
|
||||
myMemberMatcherR4Helper.updateConsentForMemberMatch(theConsent, patient, theMemberPatient);
|
||||
return myMemberMatcherR4Helper.buildSuccessReturnParameters(theMemberPatient, theCoverageToLink, theConsent);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,14 +1,15 @@
|
|||
package ca.uhn.fhir.jpa.provider.r4;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.i18n.Msg;
|
||||
import ca.uhn.fhir.jpa.api.dao.IFhirResourceDao;
|
||||
import ca.uhn.fhir.jpa.api.model.DaoMethodOutcome;
|
||||
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
|
||||
import ca.uhn.fhir.model.primitive.IdDt;
|
||||
import ca.uhn.fhir.rest.param.DateParam;
|
||||
import ca.uhn.fhir.rest.param.StringOrListParam;
|
||||
import ca.uhn.fhir.rest.param.StringParam;
|
||||
import ca.uhn.fhir.rest.param.TokenOrListParam;
|
||||
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
|
||||
import ca.uhn.fhir.util.ParametersUtil;
|
||||
import com.google.common.collect.Lists;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
@ -26,16 +27,14 @@ import org.hl7.fhir.r4.model.Identifier;
|
|||
import org.hl7.fhir.r4.model.Parameters;
|
||||
import org.hl7.fhir.r4.model.Patient;
|
||||
import org.hl7.fhir.r4.model.Reference;
|
||||
import org.hl7.fhir.r4.model.StringType;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
|
||||
import static ca.uhn.fhir.rest.api.Constants.PARAM_CONSENT;
|
||||
import static ca.uhn.fhir.rest.api.Constants.PARAM_MEMBER_IDENTIFIER;
|
||||
import static ca.uhn.fhir.rest.api.Constants.PARAM_MEMBER_PATIENT;
|
||||
import static ca.uhn.fhir.rest.api.Constants.PARAM_NEW_COVERAGE;
|
||||
|
||||
|
@ -102,13 +101,13 @@ public class MemberMatcherR4Helper {
|
|||
// search by received old coverage id
|
||||
List<IBaseResource> foundCoverages = findCoverageByCoverageId(theCoverageToMatch);
|
||||
if (foundCoverages.size() == 1 && isCoverage(foundCoverages.get(0))) {
|
||||
return Optional.of( (Coverage) foundCoverages.get(0) );
|
||||
return Optional.of((Coverage) foundCoverages.get(0));
|
||||
}
|
||||
|
||||
// search by received old coverage identifier
|
||||
foundCoverages = findCoverageByCoverageIdentifier(theCoverageToMatch);
|
||||
if (foundCoverages.size() == 1 && isCoverage(foundCoverages.get(0))) {
|
||||
return Optional.of( (Coverage) foundCoverages.get(0) );
|
||||
return Optional.of((Coverage) foundCoverages.get(0));
|
||||
}
|
||||
|
||||
return Optional.empty();
|
||||
|
@ -142,9 +141,9 @@ public class MemberMatcherR4Helper {
|
|||
return retVal.getAllResources();
|
||||
}
|
||||
|
||||
public void updateConsentForMemberMatch(Consent theConsent, Patient thePatient) {
|
||||
public void updateConsentForMemberMatch(Consent theConsent, Patient thePatient, Patient theMemberPatient) {
|
||||
addClientIdAsExtensionToConsentIfAvailable(theConsent);
|
||||
addIdentifierToConsent(theConsent);
|
||||
addIdentifierToConsent(theConsent, theMemberPatient);
|
||||
updateConsentPatientAndPerformer(theConsent, thePatient);
|
||||
|
||||
// save the resource
|
||||
|
@ -156,9 +155,29 @@ public class MemberMatcherR4Helper {
|
|||
ParametersUtil.addParameterToParameters(myFhirContext, parameters, PARAM_MEMBER_PATIENT, theMemberPatient);
|
||||
ParametersUtil.addParameterToParameters(myFhirContext, parameters, PARAM_NEW_COVERAGE, theCoverage);
|
||||
ParametersUtil.addParameterToParameters(myFhirContext, parameters, PARAM_CONSENT, theConsent);
|
||||
ParametersUtil.addParameterToParameters(myFhirContext, parameters, PARAM_MEMBER_IDENTIFIER, getIdentifier(theMemberPatient));
|
||||
return (Parameters) parameters;
|
||||
}
|
||||
|
||||
private Identifier getIdentifier(Patient theMemberPatient) {
|
||||
List<Identifier> memberIdentifiers = theMemberPatient.getIdentifier();
|
||||
if (memberIdentifiers != null && memberIdentifiers.size() > 0) {
|
||||
for (Identifier memberIdentifier : memberIdentifiers) {
|
||||
List<Coding> typeCodings = memberIdentifier.getType().getCoding();
|
||||
if (memberIdentifier.getType() != null && typeCodings != null && typeCodings.size() > 0) {
|
||||
for (Coding typeCoding : typeCodings) {
|
||||
if (typeCoding.getCode().equals("MB")) {
|
||||
return memberIdentifier;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
String i18nMessage = myFhirContext.getLocalizer().getMessage(
|
||||
"operation.member.match.error.beneficiary.without.identifier");
|
||||
throw new UnprocessableEntityException(Msg.code(2219) + i18nMessage);
|
||||
}
|
||||
|
||||
public void addMemberIdentifierToMemberPatient(Patient theMemberPatient, Identifier theNewIdentifier) {
|
||||
Coding coding = new Coding()
|
||||
.setSystem(OUT_COVERAGE_IDENTIFIER_CODE_SYSTEM)
|
||||
|
@ -170,7 +189,7 @@ public class MemberMatcherR4Helper {
|
|||
.setCoding(Lists.newArrayList(coding))
|
||||
.setText(OUT_COVERAGE_IDENTIFIER_TEXT);
|
||||
|
||||
Identifier newIdentifier = new Identifier()
|
||||
Identifier newIdentifier = new Identifier()
|
||||
.setUse(Identifier.IdentifierUse.USUAL)
|
||||
.setType(concept)
|
||||
.setSystem(theNewIdentifier.getSystem())
|
||||
|
@ -181,6 +200,7 @@ public class MemberMatcherR4Helper {
|
|||
|
||||
/**
|
||||
* If there is a client id
|
||||
*
|
||||
* @param theConsent - the consent to modify
|
||||
*/
|
||||
private void addClientIdAsExtensionToConsentIfAvailable(Consent theConsent) {
|
||||
|
@ -208,7 +228,7 @@ public class MemberMatcherR4Helper {
|
|||
}
|
||||
|
||||
if (theCoverage.getBeneficiaryTarget() != null
|
||||
&& ! theCoverage.getBeneficiaryTarget().getIdentifier().isEmpty()) {
|
||||
&& !theCoverage.getBeneficiaryTarget().getIdentifier().isEmpty()) {
|
||||
return Optional.of(theCoverage.getBeneficiaryTarget());
|
||||
}
|
||||
|
||||
|
@ -230,7 +250,7 @@ public class MemberMatcherR4Helper {
|
|||
}
|
||||
|
||||
/**
|
||||
* Matching by member patient demographics - family name and birthdate only
|
||||
* Matching by member patient demographics - family name and birthdate only
|
||||
*/
|
||||
public boolean validPatientMember(Patient thePatientFromContract, Patient thePatientToMatch) {
|
||||
if (thePatientFromContract == null || thePatientFromContract.getIdElement() == null) {
|
||||
|
@ -254,10 +274,10 @@ public class MemberMatcherR4Helper {
|
|||
}
|
||||
|
||||
public boolean validConsentDataAccess(Consent theConsent) {
|
||||
if (theConsent.getPolicy().isEmpty()) {
|
||||
if (theConsent.getPolicy().isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
for (Consent.ConsentPolicyComponent policyComponent: theConsent.getPolicy()) {
|
||||
for (Consent.ConsentPolicyComponent policyComponent : theConsent.getPolicy()) {
|
||||
if (policyComponent.getUri() == null || !validConsentPolicy(policyComponent.getUri())) {
|
||||
return false;
|
||||
}
|
||||
|
@ -280,8 +300,8 @@ public class MemberMatcherR4Helper {
|
|||
return false;
|
||||
}
|
||||
|
||||
private void addIdentifierToConsent(Consent theConsent) {
|
||||
String consentId = UUID.randomUUID().toString();
|
||||
private void addIdentifierToConsent(Consent theConsent, Patient thePatient) {
|
||||
String consentId = getIdentifier(thePatient).getValue();
|
||||
Identifier consentIdentifier = new Identifier().setSystem(CONSENT_IDENTIFIER_CODE_SYSTEM).setValue(consentId);
|
||||
theConsent.addIdentifier(consentIdentifier);
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package ca.uhn.fhir.jpa.provider;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.i18n.Msg;
|
||||
import ca.uhn.fhir.jpa.api.dao.IFhirResourceDao;
|
||||
import ca.uhn.fhir.jpa.provider.r4.IConsentExtensionProvider;
|
||||
import ca.uhn.fhir.jpa.provider.r4.MemberMatcherR4Helper;
|
||||
|
@ -15,6 +16,8 @@ import ch.qos.logback.classic.spi.ILoggingEvent;
|
|||
import ch.qos.logback.core.read.ListAppender;
|
||||
import com.google.common.collect.Lists;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.hl7.fhir.r4.model.CodeableConcept;
|
||||
import org.hl7.fhir.r4.model.Coding;
|
||||
import org.hl7.fhir.r4.model.Consent;
|
||||
import org.hl7.fhir.r4.model.Coverage;
|
||||
import org.hl7.fhir.r4.model.DateType;
|
||||
|
@ -44,8 +47,11 @@ import java.util.Optional;
|
|||
|
||||
import static ca.uhn.fhir.jpa.provider.r4.MemberMatcherR4Helper.CONSENT_IDENTIFIER_CODE_SYSTEM;
|
||||
import static ca.uhn.fhir.rest.api.Constants.PARAM_CONSENT;
|
||||
import static ca.uhn.fhir.rest.api.Constants.PARAM_MEMBER_IDENTIFIER;
|
||||
import static ca.uhn.fhir.rest.api.Constants.PARAM_MEMBER_PATIENT;
|
||||
import static ca.uhn.fhir.rest.api.Constants.PARAM_NEW_COVERAGE;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.startsWith;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
|
@ -164,9 +170,14 @@ public class MemberMatcherR4HelperTest {
|
|||
|
||||
@Test
|
||||
void buildSuccessReturnParameters() {
|
||||
Identifier identifier = new Identifier();
|
||||
CodeableConcept identifierType = new CodeableConcept();
|
||||
identifierType.addCoding(new Coding("", "MB", ""));
|
||||
identifier.setType(identifierType);
|
||||
Patient patient = new Patient();
|
||||
Coverage coverage = new Coverage();
|
||||
Consent consent = new Consent();
|
||||
patient.addIdentifier(identifier);
|
||||
|
||||
Parameters result = myHelper.buildSuccessReturnParameters(patient, coverage, consent);
|
||||
|
||||
|
@ -178,8 +189,25 @@ public class MemberMatcherR4HelperTest {
|
|||
|
||||
assertEquals(PARAM_CONSENT, result.getParameter().get(2).getName());
|
||||
assertEquals(consent, result.getParameter().get(2).getResource());
|
||||
|
||||
assertEquals(PARAM_MEMBER_IDENTIFIER, result.getParameter().get(3).getName());
|
||||
assertEquals(identifier, result.getParameter().get(3).getValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
void buildNotSuccessReturnParameters_IncorrectPatientIdentifier() {
|
||||
Identifier identifier = new Identifier();
|
||||
Patient patient = new Patient();
|
||||
Coverage coverage = new Coverage();
|
||||
Consent consent = new Consent();
|
||||
patient.addIdentifier(identifier);
|
||||
|
||||
try {
|
||||
myHelper.buildSuccessReturnParameters(patient, coverage, consent);
|
||||
} catch (Exception e) {
|
||||
assertThat(e.getMessage(), startsWith(Msg.code(2219)));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void addMemberIdentifierToMemberPatient() {
|
||||
|
@ -478,9 +506,17 @@ public class MemberMatcherR4HelperTest {
|
|||
return new Consent.ConsentPolicyComponent().setUri(uri + uriAccess);
|
||||
}
|
||||
|
||||
private Patient createPatientForMemberMatchUpdate() {
|
||||
private Patient createPatientForMemberMatchUpdate(boolean addIdentifier) {
|
||||
Patient patient = new Patient();
|
||||
patient.setId("Patient/RED");
|
||||
Identifier identifier = new Identifier();
|
||||
if (addIdentifier) {
|
||||
CodeableConcept identifierType = new CodeableConcept();
|
||||
identifierType.addCoding(new Coding("", "MB", ""));
|
||||
identifier.setType(identifierType);
|
||||
}
|
||||
identifier.setValue("RED-Patient");
|
||||
patient.addIdentifier(identifier);
|
||||
|
||||
return patient;
|
||||
}
|
||||
|
@ -488,12 +524,14 @@ public class MemberMatcherR4HelperTest {
|
|||
private void verifyConsentUpdatedAfterMemberMatch(
|
||||
Consent theConsent,
|
||||
Patient thePatient,
|
||||
Patient theMemberPatient,
|
||||
List<Extension> theSavedExtensions
|
||||
) {
|
||||
// check consent identifier
|
||||
assertEquals(1, theConsent.getIdentifier().size());
|
||||
assertEquals(CONSENT_IDENTIFIER_CODE_SYSTEM, theConsent.getIdentifier().get(0).getSystem());
|
||||
assertNotNull(theConsent.getIdentifier().get(0).getValue());
|
||||
assertEquals(theConsent.getIdentifier().get(0).getValue(), theMemberPatient.getIdentifier().get(0).getValue());
|
||||
|
||||
// check consent patient info
|
||||
String patientRef = thePatient.getIdElement().toUnqualifiedVersionless().getValue();
|
||||
|
@ -528,12 +566,13 @@ public class MemberMatcherR4HelperTest {
|
|||
// setup
|
||||
Consent consent = getConsent();
|
||||
consent.addPolicy(constructConsentPolicyComponent("#sensitive"));
|
||||
Patient patient = createPatientForMemberMatchUpdate();
|
||||
Patient patient = createPatientForMemberMatchUpdate(false);
|
||||
Patient memberPatient = createPatientForMemberMatchUpdate(true);
|
||||
|
||||
ourLog.setLevel(Level.TRACE);
|
||||
|
||||
// test
|
||||
myHelper.updateConsentForMemberMatch(consent, patient);
|
||||
myHelper.updateConsentForMemberMatch(consent, patient, memberPatient);
|
||||
|
||||
// verify
|
||||
verify(myAppender, never())
|
||||
|
@ -542,7 +581,7 @@ public class MemberMatcherR4HelperTest {
|
|||
ArgumentCaptor<Consent> consentCaptor = ArgumentCaptor.forClass(Consent.class);
|
||||
verify(myConsentDao).create(consentCaptor.capture());
|
||||
Consent saved = consentCaptor.getValue();
|
||||
verifyConsentUpdatedAfterMemberMatch(saved, patient, Collections.emptyList());
|
||||
verifyConsentUpdatedAfterMemberMatch(saved, patient, memberPatient, Collections.emptyList());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -571,7 +610,8 @@ public class MemberMatcherR4HelperTest {
|
|||
Extension ext = new Extension();
|
||||
ext.setUrl("http://example.com");
|
||||
ext.setValue(new StringType("value"));
|
||||
Patient patient = createPatientForMemberMatchUpdate();
|
||||
Patient patient = createPatientForMemberMatchUpdate(false);
|
||||
Patient memberPatient = createPatientForMemberMatchUpdate(true);
|
||||
|
||||
ourLog.setLevel(Level.TRACE);
|
||||
|
||||
|
@ -580,13 +620,13 @@ public class MemberMatcherR4HelperTest {
|
|||
.thenReturn(Collections.singleton(ext));
|
||||
|
||||
// test
|
||||
myHelper.updateConsentForMemberMatch(consent, patient);
|
||||
myHelper.updateConsentForMemberMatch(consent, patient, memberPatient);
|
||||
|
||||
// verify
|
||||
ArgumentCaptor<Consent> consentCaptor = ArgumentCaptor.forClass(Consent.class);
|
||||
verify(myConsentDao).create(consentCaptor.capture());
|
||||
Consent saved = consentCaptor.getValue();
|
||||
verifyConsentUpdatedAfterMemberMatch(saved, patient, Collections.emptyList());
|
||||
verifyConsentUpdatedAfterMemberMatch(saved, patient, memberPatient, Collections.emptyList());
|
||||
|
||||
ArgumentCaptor<ILoggingEvent> eventCaptor = ArgumentCaptor.forClass(ILoggingEvent.class);
|
||||
verify(myAppender).doAppend(eventCaptor.capture());
|
||||
|
|
Loading…
Reference in New Issue