diff --git a/hapi-deployable-pom/pom.xml b/hapi-deployable-pom/pom.xml
index 0f912c19794..e2b1a4e85c4 100644
--- a/hapi-deployable-pom/pom.xml
+++ b/hapi-deployable-pom/pom.xml
@@ -4,7 +4,7 @@
ca.uhn.hapi.fhir
hapi-fhir
- 6.3.0-PRE1-SNAPSHOT
+ 6.3.0-PRE2-SNAPSHOT
../pom.xml
diff --git a/hapi-fhir-android/pom.xml b/hapi-fhir-android/pom.xml
index ce84d65ced5..6c2342e66dd 100644
--- a/hapi-fhir-android/pom.xml
+++ b/hapi-fhir-android/pom.xml
@@ -5,7 +5,7 @@
ca.uhn.hapi.fhir
hapi-deployable-pom
- 6.3.0-PRE1-SNAPSHOT
+ 6.3.0-PRE2-SNAPSHOT
../hapi-deployable-pom/pom.xml
diff --git a/hapi-fhir-base/pom.xml b/hapi-fhir-base/pom.xml
index 5929271e832..37aa8760b9b 100644
--- a/hapi-fhir-base/pom.xml
+++ b/hapi-fhir-base/pom.xml
@@ -5,7 +5,7 @@
ca.uhn.hapi.fhir
hapi-deployable-pom
- 6.3.0-PRE1-SNAPSHOT
+ 6.3.0-PRE2-SNAPSHOT
../hapi-deployable-pom/pom.xml
diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/api/Constants.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/api/Constants.java
index 7be590b3469..2d49950d01a 100644
--- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/api/Constants.java
+++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/api/Constants.java
@@ -210,8 +210,11 @@ public class Constants {
public static final String PARAM_MEMBER_PATIENT = "MemberPatient";
public static final String PARAM_OLD_COVERAGE = "OldCoverage";
public static final String PARAM_NEW_COVERAGE = "NewCoverage";
+ public static final String PARAM_CONSENT = "Consent";
public static final String PARAM_MEMBER_PATIENT_NAME = PARAM_MEMBER_PATIENT + " Name";
public static final String PARAM_MEMBER_PATIENT_BIRTHDATE = PARAM_MEMBER_PATIENT + " Birthdate";
+ public static final String PARAM_CONSENT_PATIENT_REFERENCE = PARAM_CONSENT + "'s Patient Reference";
+ public static final String PARAM_CONSENT_PERFORMER_REFERENCE = PARAM_CONSENT + "'s Performer Reference";
public static final String PARAMQUALIFIER_MISSING = ":missing";
public static final String PARAMQUALIFIER_MISSING_FALSE = "false";
diff --git a/hapi-fhir-base/src/main/resources/ca/uhn/fhir/i18n/hapi-messages.properties b/hapi-fhir-base/src/main/resources/ca/uhn/fhir/i18n/hapi-messages.properties
index 46cee008a5e..455ee02f3a6 100644
--- a/hapi-fhir-base/src/main/resources/ca/uhn/fhir/i18n/hapi-messages.properties
+++ b/hapi-fhir-base/src/main/resources/ca/uhn/fhir/i18n/hapi-messages.properties
@@ -190,4 +190,4 @@ operation.member.match.error.beneficiary.not.found=Could not find beneficiary fo
operation.member.match.error.missing.parameter=Parameter "{0}" is required.
operation.member.match.error.beneficiary.without.identifier=Coverage beneficiary does not have an identifier.
operation.member.match.error.patient.not.found=Could not find matching patient for coverage.
-
+operation.member.match.error.consent.release.data.mismatch=Consent policy does not match the data release segmentation capabilities.
diff --git a/hapi-fhir-batch/pom.xml b/hapi-fhir-batch/pom.xml
index 5d3d17b7998..4c835e08e17 100644
--- a/hapi-fhir-batch/pom.xml
+++ b/hapi-fhir-batch/pom.xml
@@ -6,7 +6,7 @@
ca.uhn.hapi.fhir
hapi-deployable-pom
- 6.3.0-PRE1-SNAPSHOT
+ 6.3.0-PRE2-SNAPSHOT
../hapi-deployable-pom/pom.xml
diff --git a/hapi-fhir-bom/pom.xml b/hapi-fhir-bom/pom.xml
index 4630a252af7..68e9fcd26b1 100644
--- a/hapi-fhir-bom/pom.xml
+++ b/hapi-fhir-bom/pom.xml
@@ -3,14 +3,14 @@
4.0.0
ca.uhn.hapi.fhir
hapi-fhir-bom
- 6.3.0-PRE1-SNAPSHOT
+ 6.3.0-PRE2-SNAPSHOT
pom
HAPI FHIR BOM
ca.uhn.hapi.fhir
hapi-deployable-pom
- 6.3.0-PRE1-SNAPSHOT
+ 6.3.0-PRE2-SNAPSHOT
../hapi-deployable-pom/pom.xml
diff --git a/hapi-fhir-checkstyle/pom.xml b/hapi-fhir-checkstyle/pom.xml
index 5a600f7227b..6b762465e87 100644
--- a/hapi-fhir-checkstyle/pom.xml
+++ b/hapi-fhir-checkstyle/pom.xml
@@ -5,7 +5,7 @@
ca.uhn.hapi.fhir
hapi-fhir
- 6.3.0-PRE1-SNAPSHOT
+ 6.3.0-PRE2-SNAPSHOT
../pom.xml
diff --git a/hapi-fhir-cli/hapi-fhir-cli-api/pom.xml b/hapi-fhir-cli/hapi-fhir-cli-api/pom.xml
index f95564325cb..201b0a61378 100644
--- a/hapi-fhir-cli/hapi-fhir-cli-api/pom.xml
+++ b/hapi-fhir-cli/hapi-fhir-cli-api/pom.xml
@@ -4,7 +4,7 @@
ca.uhn.hapi.fhir
hapi-deployable-pom
- 6.3.0-PRE1-SNAPSHOT
+ 6.3.0-PRE2-SNAPSHOT
../../hapi-deployable-pom/pom.xml
diff --git a/hapi-fhir-cli/hapi-fhir-cli-app/pom.xml b/hapi-fhir-cli/hapi-fhir-cli-app/pom.xml
index 6bb03060a21..f025c1daf09 100644
--- a/hapi-fhir-cli/hapi-fhir-cli-app/pom.xml
+++ b/hapi-fhir-cli/hapi-fhir-cli-app/pom.xml
@@ -6,7 +6,7 @@
ca.uhn.hapi.fhir
hapi-fhir-cli
- 6.3.0-PRE1-SNAPSHOT
+ 6.3.0-PRE2-SNAPSHOT
../pom.xml
diff --git a/hapi-fhir-cli/hapi-fhir-cli-jpaserver/pom.xml b/hapi-fhir-cli/hapi-fhir-cli-jpaserver/pom.xml
index f68da1908d3..9426400ce16 100644
--- a/hapi-fhir-cli/hapi-fhir-cli-jpaserver/pom.xml
+++ b/hapi-fhir-cli/hapi-fhir-cli-jpaserver/pom.xml
@@ -6,7 +6,7 @@
ca.uhn.hapi.fhir
hapi-deployable-pom
- 6.3.0-PRE1-SNAPSHOT
+ 6.3.0-PRE2-SNAPSHOT
../../hapi-deployable-pom
diff --git a/hapi-fhir-cli/pom.xml b/hapi-fhir-cli/pom.xml
index 52d53c7ec48..1d093cab89b 100644
--- a/hapi-fhir-cli/pom.xml
+++ b/hapi-fhir-cli/pom.xml
@@ -5,7 +5,7 @@
ca.uhn.hapi.fhir
hapi-fhir
- 6.3.0-PRE1-SNAPSHOT
+ 6.3.0-PRE2-SNAPSHOT
../pom.xml
diff --git a/hapi-fhir-client-okhttp/pom.xml b/hapi-fhir-client-okhttp/pom.xml
index 01c15a20474..ce54439eed4 100644
--- a/hapi-fhir-client-okhttp/pom.xml
+++ b/hapi-fhir-client-okhttp/pom.xml
@@ -4,7 +4,7 @@
ca.uhn.hapi.fhir
hapi-deployable-pom
- 6.3.0-PRE1-SNAPSHOT
+ 6.3.0-PRE2-SNAPSHOT
../hapi-deployable-pom/pom.xml
diff --git a/hapi-fhir-client/pom.xml b/hapi-fhir-client/pom.xml
index b34796331b8..83c21fee9d3 100644
--- a/hapi-fhir-client/pom.xml
+++ b/hapi-fhir-client/pom.xml
@@ -4,7 +4,7 @@
ca.uhn.hapi.fhir
hapi-deployable-pom
- 6.3.0-PRE1-SNAPSHOT
+ 6.3.0-PRE2-SNAPSHOT
../hapi-deployable-pom/pom.xml
diff --git a/hapi-fhir-converter/pom.xml b/hapi-fhir-converter/pom.xml
index 29cd0fa0aa0..21a43107a8b 100644
--- a/hapi-fhir-converter/pom.xml
+++ b/hapi-fhir-converter/pom.xml
@@ -5,7 +5,7 @@
ca.uhn.hapi.fhir
hapi-deployable-pom
- 6.3.0-PRE1-SNAPSHOT
+ 6.3.0-PRE2-SNAPSHOT
../hapi-deployable-pom/pom.xml
diff --git a/hapi-fhir-dist/pom.xml b/hapi-fhir-dist/pom.xml
index 9be262111c9..0672fad4433 100644
--- a/hapi-fhir-dist/pom.xml
+++ b/hapi-fhir-dist/pom.xml
@@ -5,7 +5,7 @@
ca.uhn.hapi.fhir
hapi-fhir
- 6.3.0-PRE1-SNAPSHOT
+ 6.3.0-PRE2-SNAPSHOT
../pom.xml
diff --git a/hapi-fhir-docs/pom.xml b/hapi-fhir-docs/pom.xml
index 38c6685dbd3..ca16d485654 100644
--- a/hapi-fhir-docs/pom.xml
+++ b/hapi-fhir-docs/pom.xml
@@ -5,7 +5,7 @@
ca.uhn.hapi.fhir
hapi-deployable-pom
- 6.3.0-PRE1-SNAPSHOT
+ 6.3.0-PRE2-SNAPSHOT
../hapi-deployable-pom/pom.xml
diff --git a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/6_3_0/4153-extend-member-match-to-store-consent-if-matched.yaml b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/6_3_0/4153-extend-member-match-to-store-consent-if-matched.yaml
new file mode 100644
index 00000000000..157ce31e627
--- /dev/null
+++ b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/6_3_0/4153-extend-member-match-to-store-consent-if-matched.yaml
@@ -0,0 +1,4 @@
+---
+type: add
+issue: 4153
+title: "Extend $member-match to store Consent resource when there is a matching patient."
diff --git a/hapi-fhir-jacoco/pom.xml b/hapi-fhir-jacoco/pom.xml
index c503e374500..d43c4d57588 100644
--- a/hapi-fhir-jacoco/pom.xml
+++ b/hapi-fhir-jacoco/pom.xml
@@ -11,7 +11,7 @@
ca.uhn.hapi.fhir
hapi-deployable-pom
- 6.3.0-PRE1-SNAPSHOT
+ 6.3.0-PRE2-SNAPSHOT
../hapi-deployable-pom/pom.xml
diff --git a/hapi-fhir-jaxrsserver-base/pom.xml b/hapi-fhir-jaxrsserver-base/pom.xml
index ebf8794ee2a..a3ebdf61763 100644
--- a/hapi-fhir-jaxrsserver-base/pom.xml
+++ b/hapi-fhir-jaxrsserver-base/pom.xml
@@ -4,7 +4,7 @@
ca.uhn.hapi.fhir
hapi-deployable-pom
- 6.3.0-PRE1-SNAPSHOT
+ 6.3.0-PRE2-SNAPSHOT
../hapi-deployable-pom/pom.xml
diff --git a/hapi-fhir-jpa/pom.xml b/hapi-fhir-jpa/pom.xml
index 63616d5dcdd..fdaed9ee04e 100644
--- a/hapi-fhir-jpa/pom.xml
+++ b/hapi-fhir-jpa/pom.xml
@@ -5,7 +5,7 @@
ca.uhn.hapi.fhir
hapi-deployable-pom
- 6.3.0-PRE1-SNAPSHOT
+ 6.3.0-PRE2-SNAPSHOT
../hapi-deployable-pom/pom.xml
4.0.0
diff --git a/hapi-fhir-jpaserver-base/pom.xml b/hapi-fhir-jpaserver-base/pom.xml
index b08fca2910f..1a18839bc90 100644
--- a/hapi-fhir-jpaserver-base/pom.xml
+++ b/hapi-fhir-jpaserver-base/pom.xml
@@ -5,7 +5,7 @@
ca.uhn.hapi.fhir
hapi-deployable-pom
- 6.3.0-PRE1-SNAPSHOT
+ 6.3.0-PRE2-SNAPSHOT
../hapi-deployable-pom/pom.xml
diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/config/JpaConfig.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/config/JpaConfig.java
index e38742ae454..3074016e1a2 100644
--- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/config/JpaConfig.java
+++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/config/JpaConfig.java
@@ -8,6 +8,7 @@ import ca.uhn.fhir.interceptor.api.IInterceptorService;
import ca.uhn.fhir.interceptor.executor.InterceptorService;
import ca.uhn.fhir.jpa.api.config.DaoConfig;
import ca.uhn.fhir.jpa.api.dao.DaoRegistry;
+import ca.uhn.fhir.jpa.api.dao.IFhirResourceDao;
import ca.uhn.fhir.jpa.api.model.ExpungeOptions;
import ca.uhn.fhir.jpa.api.svc.IIdHelperService;
import ca.uhn.fhir.jpa.binary.interceptor.BinaryStorageInterceptor;
@@ -63,6 +64,7 @@ import ca.uhn.fhir.jpa.provider.DiffProvider;
import ca.uhn.fhir.jpa.provider.SubscriptionTriggeringProvider;
import ca.uhn.fhir.jpa.provider.TerminologyUploaderProvider;
import ca.uhn.fhir.jpa.provider.ValueSetOperationProvider;
+import ca.uhn.fhir.jpa.provider.r4.IConsentExtensionProvider;
import ca.uhn.fhir.jpa.provider.r4.MemberMatcherR4Helper;
import ca.uhn.fhir.jpa.sched.AutowiringSpringBeanJobFactory;
import ca.uhn.fhir.jpa.sched.HapiSchedulerServiceImpl;
@@ -111,8 +113,8 @@ import ca.uhn.fhir.jpa.searchparam.nickname.NicknameInterceptor;
import ca.uhn.fhir.jpa.searchparam.registry.ISearchParamProvider;
import ca.uhn.fhir.jpa.sp.ISearchParamPresenceSvc;
import ca.uhn.fhir.jpa.sp.SearchParamPresenceSvcImpl;
-import ca.uhn.fhir.jpa.term.TermReadSvcImpl;
import ca.uhn.fhir.jpa.term.TermConceptMappingSvcImpl;
+import ca.uhn.fhir.jpa.term.TermReadSvcImpl;
import ca.uhn.fhir.jpa.term.api.ITermConceptMappingSvc;
import ca.uhn.fhir.jpa.term.api.ITermReadSvc;
import ca.uhn.fhir.jpa.term.config.TermCodeSystemConfig;
@@ -129,6 +131,9 @@ import ca.uhn.fhir.rest.server.interceptor.consent.IConsentContextServices;
import ca.uhn.fhir.rest.server.interceptor.partition.RequestTenantPartitionInterceptor;
import ca.uhn.hapi.converters.canonical.VersionCanonicalizer;
import org.hl7.fhir.common.hapi.validation.support.UnknownCodeSystemWarningValidationSupport;
+import org.hl7.fhir.r4.model.Consent;
+import org.hl7.fhir.r4.model.Coverage;
+import org.hl7.fhir.r4.model.Patient;
import org.hl7.fhir.utilities.graphql.IGraphQLStorageServices;
import org.hl7.fhir.utilities.npm.PackageClient;
import org.springframework.beans.factory.annotation.Autowired;
@@ -710,6 +715,20 @@ public class JpaConfig {
return new UnknownCodeSystemWarningValidationSupport(theFhirContext);
}
+ @Lazy
+ @Bean
+ public MemberMatcherR4Helper memberMatcherR4Helper(
+ @Autowired FhirContext theContext,
+ @Autowired IFhirResourceDao theCoverageDao,
+ @Autowired IFhirResourceDao thePatientDao,
+ @Autowired IFhirResourceDao theConsentDao,
+ @Autowired(required = false) IConsentExtensionProvider theExtensionProvider
+ ) {
+ return new MemberMatcherR4Helper(
+ theContext, theCoverageDao, thePatientDao, theConsentDao, theExtensionProvider
+ );
+ }
+
@Lazy
@Bean
public NicknameInterceptor nicknameInterceptor() throws IOException {
@@ -732,5 +751,4 @@ public class JpaConfig {
return new TermReadSvcImpl();
}
-
}
diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/config/r4/JpaR4Config.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/config/r4/JpaR4Config.java
index 978514440a2..21f12606c4d 100644
--- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/config/r4/JpaR4Config.java
+++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/config/r4/JpaR4Config.java
@@ -3,6 +3,7 @@ package ca.uhn.fhir.jpa.config.r4;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.context.support.IValidationSupport;
import ca.uhn.fhir.jpa.api.IDaoRegistry;
+import ca.uhn.fhir.jpa.api.dao.IFhirResourceDao;
import ca.uhn.fhir.jpa.api.dao.IFhirSystemDao;
import ca.uhn.fhir.jpa.config.GeneratedDaoAndResourceProviderConfigR4;
import ca.uhn.fhir.jpa.config.JpaConfig;
@@ -12,6 +13,7 @@ import ca.uhn.fhir.jpa.dao.r4.TransactionProcessorVersionAdapterR4;
import ca.uhn.fhir.jpa.graphql.GraphQLProvider;
import ca.uhn.fhir.jpa.graphql.GraphQLProviderWithIntrospection;
import ca.uhn.fhir.jpa.provider.JpaSystemProvider;
+import ca.uhn.fhir.jpa.provider.r4.IConsentExtensionProvider;
import ca.uhn.fhir.jpa.provider.r4.MemberMatchR4ResourceProvider;
import ca.uhn.fhir.jpa.provider.r4.MemberMatcherR4Helper;
import ca.uhn.fhir.jpa.term.TermLoaderSvcImpl;
@@ -23,8 +25,12 @@ import ca.uhn.fhir.jpa.term.api.ITermVersionAdapterSvc;
import ca.uhn.fhir.rest.server.provider.ResourceProviderFactory;
import ca.uhn.fhir.rest.server.util.ISearchParamRegistry;
import org.hl7.fhir.r4.model.Bundle;
+import org.hl7.fhir.r4.model.Consent;
+import org.hl7.fhir.r4.model.Coverage;
import org.hl7.fhir.r4.model.Meta;
+import org.hl7.fhir.r4.model.Patient;
import org.hl7.fhir.utilities.graphql.IGraphQLStorageServices;
+import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
@@ -97,27 +103,24 @@ public class JpaR4Config {
}
@Bean
- public MemberMatcherR4Helper memberMatcherR4Helper(FhirContext theFhirContext) {
- return new MemberMatcherR4Helper(theFhirContext);
+ public MemberMatcherR4Helper memberMatcherR4Helper(
+ @Autowired FhirContext theContext,
+ @Autowired IFhirResourceDao theCoverageDao,
+ @Autowired IFhirResourceDao thePatientDao,
+ @Autowired IFhirResourceDao theConsentDao,
+ @Autowired(required = false) IConsentExtensionProvider theExtensionProvider
+ ) {
+ return new MemberMatcherR4Helper(
+ theContext,
+ theCoverageDao,
+ thePatientDao,
+ theConsentDao,
+ theExtensionProvider
+ );
}
@Bean
public MemberMatchR4ResourceProvider memberMatchR4ResourceProvider(FhirContext theFhirContext, MemberMatcherR4Helper theMemberMatchR4Helper) {
return new MemberMatchR4ResourceProvider(theFhirContext, theMemberMatchR4Helper);
}
-
- @Bean
- public ProviderLoader r4ProviderLoader(ResourceProviderFactory theResourceProviderFactory, MemberMatchR4ResourceProvider theMemberMatchR4ResourceProvider) {
- return new ProviderLoader(theResourceProviderFactory, theMemberMatchR4ResourceProvider);
- }
-
- public static class ProviderLoader {
-
- public ProviderLoader(ResourceProviderFactory theResourceProviderFactory, MemberMatchR4ResourceProvider theMemberMatchR4ResourceProvider) {
- theResourceProviderFactory.addSupplier(()->theMemberMatchR4ResourceProvider);
- }
-
- }
-
-
}
diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/provider/r4/IConsentExtensionProvider.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/provider/r4/IConsentExtensionProvider.java
new file mode 100644
index 00000000000..0483a6fe452
--- /dev/null
+++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/provider/r4/IConsentExtensionProvider.java
@@ -0,0 +1,21 @@
+package ca.uhn.fhir.jpa.provider.r4;
+
+import org.hl7.fhir.instance.model.api.IBaseExtension;
+import org.hl7.fhir.instance.model.api.IBaseResource;
+
+import java.util.Collection;
+import java.util.Collections;
+
+public interface IConsentExtensionProvider {
+
+ /**
+ * Takes a Consent resource and returns a collection of Extensions that will
+ * be added to the base resource.
+ *
+ * @param theConsentResource - the consent resource
+ * @return - a collection of resources (or an empty collection if none).
+ */
+ default Collection getConsentExtension(IBaseResource theConsentResource) {
+ return Collections.emptyList();
+ };
+}
diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/provider/r4/MemberMatchR4ResourceProvider.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/provider/r4/MemberMatchR4ResourceProvider.java
index ae0157ae2c6..09cd4cc8782 100644
--- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/provider/r4/MemberMatchR4ResourceProvider.java
+++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/provider/r4/MemberMatchR4ResourceProvider.java
@@ -32,6 +32,7 @@ import ca.uhn.fhir.rest.server.provider.ProviderConstants;
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;
@@ -69,16 +70,20 @@ public class MemberMatchR4ResourceProvider {
@OperationParam(name = Constants.PARAM_NEW_COVERAGE, min = 1, max = 1)
Coverage newCoverage,
+ @Description(shortDefinition = "Consent information. Consent held by the system seeking the match that grants permission to access the patient information.")
+ @OperationParam(name = Constants.PARAM_CONSENT, min = 1, max = 1)
+ Consent theConsent,
+
RequestDetails theRequestDetails
) {
- return doMemberMatchOperation(theServletRequest, theMemberPatient, oldCoverage, newCoverage, theRequestDetails);
+ return doMemberMatchOperation(theServletRequest, theMemberPatient, oldCoverage, newCoverage, theConsent, theRequestDetails);
}
private Parameters doMemberMatchOperation(HttpServletRequest theServletRequest, Patient theMemberPatient,
- Coverage theCoverageToMatch, Coverage theCoverageToLink, RequestDetails theRequestDetails) {
+ Coverage theCoverageToMatch, Coverage theCoverageToLink, Consent theConsent, RequestDetails theRequestDetails) {
- validateParams(theMemberPatient, theCoverageToMatch, theCoverageToLink);
+ validateParams(theMemberPatient, theCoverageToMatch, theCoverageToLink, theConsent);
Optional coverageOpt = myMemberMatcherR4Helper.findMatchingCoverage(theCoverageToMatch);
if ( ! coverageOpt.isPresent()) {
@@ -108,16 +113,24 @@ public class MemberMatchR4ResourceProvider {
throw new UnprocessableEntityException(Msg.code(1157) + i18nMessage);
}
- myMemberMatcherR4Helper.addMemberIdentifierToMemberPatient(theMemberPatient, patient.getIdentifierFirstRep());
+ if (!myMemberMatcherR4Helper.validConsentDataAccess(theConsent)) {
+ String i18nMessage = myFhirContext.getLocalizer().getMessage(
+ "operation.member.match.error.consent.release.data.mismatch");
+ throw new UnprocessableEntityException(Msg.code(2147) + i18nMessage);
+ }
- return myMemberMatcherR4Helper.buildSuccessReturnParameters(theMemberPatient, theCoverageToLink);
+ myMemberMatcherR4Helper.addMemberIdentifierToMemberPatient(theMemberPatient, patient.getIdentifierFirstRep());
+ myMemberMatcherR4Helper.updateConsentForMemberMatch(theConsent, patient);
+ return myMemberMatcherR4Helper.buildSuccessReturnParameters(theMemberPatient, theCoverageToLink, theConsent);
}
- private void validateParams(Patient theMemberPatient, Coverage theOldCoverage, Coverage theNewCoverage) {
+ private void validateParams(Patient theMemberPatient, Coverage theOldCoverage, Coverage theNewCoverage, Consent theConsent) {
validateParam(theMemberPatient, Constants.PARAM_MEMBER_PATIENT);
validateParam(theOldCoverage, Constants.PARAM_OLD_COVERAGE);
validateParam(theNewCoverage, Constants.PARAM_NEW_COVERAGE);
+ validateParam(theConsent, Constants.PARAM_CONSENT);
validateMemberPatientParam(theMemberPatient);
+ validateConsentParam(theConsent);
}
private void validateParam(Object theParam, String theParamName) {
@@ -136,4 +149,13 @@ public class MemberMatchR4ResourceProvider {
validateParam(theMemberPatient.getName().get(0).getFamily(), Constants.PARAM_MEMBER_PATIENT_NAME);
validateParam(theMemberPatient.getBirthDate(), Constants.PARAM_MEMBER_PATIENT_BIRTHDATE);
}
+
+ private void validateConsentParam(Consent theConsent) {
+ if (theConsent.getPatient().isEmpty()) {
+ validateParam(null, Constants.PARAM_CONSENT_PATIENT_REFERENCE);
+ }
+ if (theConsent.getPerformer().isEmpty()) {
+ validateParam(null, Constants.PARAM_CONSENT_PERFORMER_REFERENCE);
+ }
+ }
}
diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/provider/r4/MemberMatcherR4Helper.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/provider/r4/MemberMatcherR4Helper.java
index c3336ba87d8..a42eb2ae2f1 100644
--- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/provider/r4/MemberMatcherR4Helper.java
+++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/provider/r4/MemberMatcherR4Helper.java
@@ -2,6 +2,7 @@ package ca.uhn.fhir.jpa.provider.r4;
import ca.uhn.fhir.context.FhirContext;
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;
@@ -10,22 +11,31 @@ import ca.uhn.fhir.rest.param.StringParam;
import ca.uhn.fhir.rest.param.TokenOrListParam;
import ca.uhn.fhir.util.ParametersUtil;
import com.google.common.collect.Lists;
+import org.apache.commons.lang3.StringUtils;
+import org.hl7.fhir.instance.model.api.IBaseExtension;
import org.hl7.fhir.instance.model.api.IBaseParameters;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.instance.model.api.IIdType;
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.Extension;
import org.hl7.fhir.r4.model.HumanName;
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_PATIENT;
import static ca.uhn.fhir.rest.api.Constants.PARAM_NEW_COVERAGE;
@@ -50,23 +60,39 @@ import static ca.uhn.fhir.rest.api.Constants.PARAM_NEW_COVERAGE;
*/
public class MemberMatcherR4Helper {
+ private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(MemberMatcherR4Helper.class);
private static final String OUT_COVERAGE_IDENTIFIER_CODE_SYSTEM = "http://terminology.hl7.org/CodeSystem/v2-0203";
private static final String OUT_COVERAGE_IDENTIFIER_CODE = "MB";
private static final String OUT_COVERAGE_IDENTIFIER_TEXT = "Member Number";
private static final String COVERAGE_TYPE = "Coverage";
+ private static final String CONSENT_POLICY_REGULAR_TYPE = "regular";
+ private static final String CONSENT_POLICY_SENSITIVE_TYPE = "sensitive";
+ public static final String CONSENT_IDENTIFIER_CODE_SYSTEM = "https://smilecdr.com/fhir/ns/member-match-fixme";
private final FhirContext myFhirContext;
+ private final IFhirResourceDao myCoverageDao;
+ private final IFhirResourceDao myPatientDao;
+ private final IFhirResourceDao myConsentDao;
+ // by default, not provided
+ // but if it is, extensions can be added to Consent on $member-match
+ @Nullable
+ private final IConsentExtensionProvider myIConsentExtensionProvider;
- @Autowired
- private IFhirResourceDao myCoverageDao;
+ private boolean myRegularFilterSupported = false;
- @Autowired
- private IFhirResourceDao myPatientDao;
-
-
- public MemberMatcherR4Helper(FhirContext theContext) {
+ public MemberMatcherR4Helper(
+ FhirContext theContext,
+ IFhirResourceDao theCoverageDao,
+ IFhirResourceDao thePatientDao,
+ IFhirResourceDao theConsentDao,
+ @Nullable IConsentExtensionProvider theExtensionProvider
+ ) {
myFhirContext = theContext;
+ myConsentDao = theConsentDao;
+ myPatientDao = thePatientDao;
+ myCoverageDao = theCoverageDao;
+ myIConsentExtensionProvider = theExtensionProvider;
}
/**
@@ -116,15 +142,23 @@ public class MemberMatcherR4Helper {
return retVal.getAllResources();
}
+ public void updateConsentForMemberMatch(Consent theConsent, Patient thePatient) {
+ addClientIdAsExtensionToConsentIfAvailable(theConsent);
+ addIdentifierToConsent(theConsent);
+ updateConsentPatientAndPerformer(theConsent, thePatient);
- public Parameters buildSuccessReturnParameters(Patient theMemberPatient, Coverage theCoverage) {
+ // save the resource
+ myConsentDao.create(theConsent);
+ }
+
+ public Parameters buildSuccessReturnParameters(Patient theMemberPatient, Coverage theCoverage, Consent theConsent) {
IBaseParameters parameters = ParametersUtil.newInstance(myFhirContext);
ParametersUtil.addParameterToParameters(myFhirContext, parameters, PARAM_MEMBER_PATIENT, theMemberPatient);
ParametersUtil.addParameterToParameters(myFhirContext, parameters, PARAM_NEW_COVERAGE, theCoverage);
+ ParametersUtil.addParameterToParameters(myFhirContext, parameters, PARAM_CONSENT, theConsent);
return (Parameters) parameters;
}
-
public void addMemberIdentifierToMemberPatient(Patient theMemberPatient, Identifier theNewIdentifier) {
Coding coding = new Coding()
.setSystem(OUT_COVERAGE_IDENTIFIER_CODE_SYSTEM)
@@ -145,6 +179,28 @@ public class MemberMatcherR4Helper {
theMemberPatient.addIdentifier(newIdentifier);
}
+ /**
+ * If there is a client id
+ * @param theConsent - the consent to modify
+ */
+ private void addClientIdAsExtensionToConsentIfAvailable(Consent theConsent) {
+ if (myIConsentExtensionProvider != null) {
+ Collection extensions = myIConsentExtensionProvider.getConsentExtension(theConsent);
+
+ for (IBaseExtension ext : extensions) {
+ if (ext instanceof Extension) {
+ theConsent.addExtension((Extension) ext);
+ } else {
+ Extension extR4 = new Extension();
+ extR4.setUrl(ext.getUrl());
+ extR4.setValue(ext.getValue());
+ theConsent.addExtension(extR4);
+ }
+ }
+
+ ourLog.trace("{} extension(s) added to Consent", extensions.size());
+ }
+ }
public Optional getBeneficiaryPatient(Coverage theCoverage) {
if (theCoverage.getBeneficiaryTarget() == null && theCoverage.getBeneficiary() == null) {
@@ -181,19 +237,62 @@ public class MemberMatcherR4Helper {
return false;
}
StringOrListParam familyName = new StringOrListParam();
- for (HumanName name: thePatientToMatch.getName()) {
+ for (HumanName name : thePatientToMatch.getName()) {
familyName.addOr(new StringParam(name.getFamily()));
}
SearchParameterMap map = new SearchParameterMap()
.add("family", familyName)
.add("birthdate", new DateParam(thePatientToMatch.getBirthDateElement().getValueAsString()));
ca.uhn.fhir.rest.api.server.IBundleProvider bundle = myPatientDao.search(map);
- for (IBaseResource patientResource: bundle.getAllResources()) {
+ for (IBaseResource patientResource : bundle.getAllResources()) {
IIdType patientId = patientResource.getIdElement().toUnqualifiedVersionless();
- if ( patientId.getValue().equals(thePatientFromContract.getIdElement().toUnqualifiedVersionless().getValue())) {
+ if (patientId.getValue().equals(thePatientFromContract.getIdElement().toUnqualifiedVersionless().getValue())) {
return true;
}
}
return false;
}
+
+ public boolean validConsentDataAccess(Consent theConsent) {
+ if (theConsent.getPolicy().isEmpty()) {
+ return false;
+ }
+ for (Consent.ConsentPolicyComponent policyComponent: theConsent.getPolicy()) {
+ if (policyComponent.getUri() == null || !validConsentPolicy(policyComponent.getUri())) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * This is filtering the Consent policy data. The rule is specified in
+ * https://build.fhir.org/ig/HL7/davinci-ehrx/StructureDefinition-hrex-consent.html#notes
+ */
+ private boolean validConsentPolicy(String thePolicyUri) {
+ String policyTypes = StringUtils.substringAfterLast(thePolicyUri, "#");
+ if (policyTypes.equals(CONSENT_POLICY_SENSITIVE_TYPE)) {
+ return true;
+ }
+ if (policyTypes.equals(CONSENT_POLICY_REGULAR_TYPE) && myRegularFilterSupported) {
+ return true;
+ }
+ return false;
+ }
+
+ private void addIdentifierToConsent(Consent theConsent) {
+ String consentId = UUID.randomUUID().toString();
+ Identifier consentIdentifier = new Identifier().setSystem(CONSENT_IDENTIFIER_CODE_SYSTEM).setValue(consentId);
+ theConsent.addIdentifier(consentIdentifier);
+ }
+
+ public void setRegularFilterSupported(boolean theRegularFilterSupported) {
+ myRegularFilterSupported = theRegularFilterSupported;
+ }
+
+ private void updateConsentPatientAndPerformer(Consent theConsent, Patient thePatient) {
+ String patientRef = thePatient.getIdElement().toUnqualifiedVersionless().getValue();
+ theConsent.getPatient().setReference(patientRef);
+ theConsent.getPerformer().set(0, new Reference(patientRef));
+ }
}
diff --git a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/MemberMatcherR4HelperTest.java b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/MemberMatcherR4HelperTest.java
new file mode 100644
index 00000000000..7fc778c588c
--- /dev/null
+++ b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/MemberMatcherR4HelperTest.java
@@ -0,0 +1,597 @@
+package ca.uhn.fhir.jpa.provider;
+
+import ca.uhn.fhir.context.FhirContext;
+import ca.uhn.fhir.jpa.api.dao.IFhirResourceDao;
+import ca.uhn.fhir.jpa.provider.r4.IConsentExtensionProvider;
+import ca.uhn.fhir.jpa.provider.r4.MemberMatcherR4Helper;
+import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
+import ca.uhn.fhir.model.api.IQueryParameterType;
+import ca.uhn.fhir.model.primitive.IdDt;
+import ca.uhn.fhir.rest.api.server.IBundleProvider;
+import ca.uhn.fhir.rest.server.SimpleBundleProvider;
+import ch.qos.logback.classic.Level;
+import ch.qos.logback.classic.Logger;
+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.Consent;
+import org.hl7.fhir.r4.model.Coverage;
+import org.hl7.fhir.r4.model.DateType;
+import org.hl7.fhir.r4.model.Extension;
+import org.hl7.fhir.r4.model.HumanName;
+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.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Nested;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.Answers;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
+import org.mockito.Mock;
+import org.mockito.Spy;
+import org.mockito.junit.jupiter.MockitoExtension;
+import org.slf4j.LoggerFactory;
+
+import java.util.Collections;
+import java.util.List;
+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_PATIENT;
+import static ca.uhn.fhir.rest.api.Constants.PARAM_NEW_COVERAGE;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.isA;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+@ExtendWith(MockitoExtension.class)
+public class MemberMatcherR4HelperTest {
+
+ private static final Logger ourLog = (Logger) LoggerFactory.getLogger(MemberMatcherR4Helper.class);
+
+ @Mock
+ private ListAppender myAppender;
+
+ @Spy
+ private final FhirContext myFhirContext = FhirContext.forR4();
+ @Mock
+ private IFhirResourceDao myCoverageDao;
+ @Mock
+ private IFhirResourceDao myPatientDao;
+ @Mock
+ private IFhirResourceDao myConsentDao;
+
+ private MemberMatcherR4Helper myHelper;
+
+ @BeforeEach
+ public void before() {
+ myHelper = new MemberMatcherR4Helper(
+ myFhirContext,
+ myCoverageDao,
+ myPatientDao,
+ myConsentDao,
+ null // extension provider
+ );
+
+ ourLog.addAppender(myAppender);
+ }
+
+ @AfterEach
+ public void after() {
+ ourLog.detachAppender(myAppender);
+ }
+
+ @Mock private Coverage myCoverageToMatch;
+ @Mock private IBundleProvider myBundleProvider;
+
+ private final Coverage myMatchedCoverage = new Coverage()
+ .setBeneficiary(new Reference("Patient/123"));
+ private final Identifier myMatchingIdentifier = new Identifier()
+ .setSystem("identifier-system").setValue("identifier-value");
+
+ @Captor
+ ArgumentCaptor mySearchParameterMapCaptor;
+
+ @Test
+ void findMatchingCoverageMatchByIdReturnsMatched() {
+ when(myCoverageToMatch.getId()).thenReturn("cvg-to-match-id");
+ when(myCoverageDao.search(isA(SearchParameterMap.class))).thenReturn(myBundleProvider);
+ when(myBundleProvider.getAllResources()).thenReturn(Collections.singletonList(myMatchedCoverage));
+
+ Optional result = myHelper.findMatchingCoverage(myCoverageToMatch);
+
+ assertEquals(Optional.of(myMatchedCoverage), result);
+ verify(myCoverageDao).search(mySearchParameterMapCaptor.capture());
+ SearchParameterMap spMap = mySearchParameterMapCaptor.getValue();
+ assertTrue(spMap.containsKey("_id"));
+ List> listListParams = spMap.get("_id");
+ assertEquals(1, listListParams.size());
+ assertEquals(1, listListParams.get(0).size());
+ IQueryParameterType param = listListParams.get(0).get(0);
+ assertEquals("cvg-to-match-id", param.getValueAsQueryToken(myFhirContext));
+ }
+
+
+ @Test
+ void findMatchingCoverageMatchByIdentifierReturnsMatched() {
+ when(myCoverageToMatch.getId()).thenReturn("non-matching-id");
+ when(myCoverageToMatch.getIdentifier()).thenReturn(Collections.singletonList(myMatchingIdentifier));
+ when(myCoverageDao.search(isA(SearchParameterMap.class))).thenReturn(myBundleProvider);
+ when(myBundleProvider.getAllResources()).thenReturn(
+ Collections.emptyList(), Collections.singletonList(myMatchedCoverage));
+
+ Optional result = myHelper.findMatchingCoverage(myCoverageToMatch);
+
+ assertEquals(Optional.of(myMatchedCoverage), result);
+ verify(myCoverageDao, times(2)).search(mySearchParameterMapCaptor.capture());
+ List spMap = mySearchParameterMapCaptor.getAllValues();
+ assertTrue(spMap.get(0).containsKey("_id"));
+ assertTrue(spMap.get(1).containsKey("identifier"));
+ List> listListParams = spMap.get(1).get("identifier");
+ assertEquals(1, listListParams.size());
+ assertEquals(1, listListParams.get(0).size());
+ IQueryParameterType param = listListParams.get(0).get(0);
+ assertEquals(myMatchingIdentifier.getSystem() + "|" + myMatchingIdentifier.getValue(),
+ param.getValueAsQueryToken(myFhirContext));
+ }
+
+
+ @Test
+ void findMatchingCoverageNoMatchReturnsEmpty() {
+ when(myCoverageToMatch.getId()).thenReturn("non-matching-id");
+ when(myCoverageToMatch.getIdentifier()).thenReturn(Collections.singletonList(myMatchingIdentifier));
+ when(myCoverageDao.search(any(SearchParameterMap.class))).thenReturn(myBundleProvider);
+ when(myBundleProvider.getAllResources()).thenReturn(Collections.emptyList(), Collections.emptyList());
+
+ Optional result = myHelper.findMatchingCoverage(myCoverageToMatch);
+
+ assertFalse(result.isPresent());
+ }
+
+
+ @Test
+ void buildSuccessReturnParameters() {
+ Patient patient = new Patient();
+ Coverage coverage = new Coverage();
+ Consent consent = new Consent();
+
+ Parameters result = myHelper.buildSuccessReturnParameters(patient, coverage, consent);
+
+ assertEquals(PARAM_MEMBER_PATIENT, result.getParameter().get(0).getName());
+ assertEquals(patient, result.getParameter().get(0).getResource());
+
+ assertEquals(PARAM_NEW_COVERAGE, result.getParameter().get(1).getName());
+ assertEquals(coverage, result.getParameter().get(1).getResource());
+
+ assertEquals(PARAM_CONSENT, result.getParameter().get(2).getName());
+ assertEquals(consent, result.getParameter().get(2).getResource());
+ }
+
+
+ @Test
+ void addMemberIdentifierToMemberPatient() {
+ Identifier originalIdentifier = new Identifier()
+ .setSystem("original-identifier-system").setValue("original-identifier-value");
+
+ Identifier newIdentifier = new Identifier()
+ .setSystem("new-identifier-system").setValue("new-identifier-value");
+
+ Patient patient = new Patient().setIdentifier(Lists.newArrayList(originalIdentifier));
+
+ myHelper.addMemberIdentifierToMemberPatient(patient, newIdentifier);
+
+ assertEquals(2, patient.getIdentifier().size());
+
+ assertEquals("original-identifier-system", patient.getIdentifier().get(0).getSystem());
+ assertEquals("original-identifier-value", patient.getIdentifier().get(0).getValue());
+
+ assertEquals("new-identifier-system", patient.getIdentifier().get(1).getSystem());
+ assertEquals("new-identifier-value", patient.getIdentifier().get(1).getValue());
+ }
+
+ /**
+ * Testing multiple scenarios for getting patient resource from coverage's plan beneficiary
+ */
+ @Nested
+ public class TestGetBeneficiaryPatient {
+
+ @Mock(answer = Answers.RETURNS_DEEP_STUBS)
+ private Coverage coverage;
+
+
+ @Test
+ void noBeneficiaryOrBeneficiaryTargetReturnsEmpty() {
+ when(coverage.getBeneficiaryTarget()).thenReturn(null);
+ when(coverage.getBeneficiary()).thenReturn(null);
+
+ Optional result = myHelper.getBeneficiaryPatient(coverage);
+
+ assertFalse(result.isPresent());
+ }
+
+
+ @Test
+ void beneficiaryTargetWithNoIdentifierReturnsEmpty() {
+ when(coverage.getBeneficiary()).thenReturn(null);
+ when(coverage.getBeneficiaryTarget()).thenReturn(new Patient());
+
+ Optional result = myHelper.getBeneficiaryPatient(coverage);
+
+ assertFalse(result.isPresent());
+ }
+
+
+ @Test
+ void beneficiaryTargetWithIdentifierReturnsBeneficiary() {
+ Patient patient = new Patient().setIdentifier(Collections.singletonList(new Identifier()));
+ when(coverage.getBeneficiaryTarget()).thenReturn(patient);
+
+ Optional result = myHelper.getBeneficiaryPatient(coverage);
+
+ assertTrue(result.isPresent());
+ assertEquals(patient, result.get());
+ }
+
+
+ @Test
+ void beneficiaryReferenceResourceReturnsBeneficiary() {
+ Patient patient = new Patient().setIdentifier(Collections.singletonList(new Identifier()));
+ when(coverage.getBeneficiaryTarget()).thenReturn(null);
+ when(coverage.getBeneficiary().getResource()).thenReturn(patient);
+
+ Optional result = myHelper.getBeneficiaryPatient(coverage);
+
+ assertTrue(result.isPresent());
+ assertEquals(patient, result.get());
+ }
+
+
+ @Test
+ void beneficiaryReferenceNoResourceOrReferenceReturnsEmpty() {
+ when(coverage.getBeneficiaryTarget()).thenReturn(null);
+ when(coverage.getBeneficiary()).thenReturn(new Reference());
+
+ Optional result = myHelper.getBeneficiaryPatient(coverage);
+
+ assertFalse(result.isPresent());
+ }
+
+
+ @Test
+ void beneficiaryReferenceReferenceReturnsReadPatient() {
+ when(coverage.getBeneficiaryTarget()).thenReturn(null);
+ when(coverage.getBeneficiary().getResource()).thenReturn(null);
+ when(coverage.getBeneficiary().getReference()).thenReturn("patient-id");
+
+ myHelper.getBeneficiaryPatient(coverage);
+
+ verify(myPatientDao).read(new IdDt("patient-id"));
+ }
+
+ }
+
+ /**
+ * Testing multiple scenarios for validity of Patient Member parameter
+ */
+ @Nested
+ public class TestValidPatientMember {
+
+ @Mock(answer = Answers.RETURNS_DEEP_STUBS)
+ private Coverage coverage;
+ private Patient patient;
+
+ @Test
+ void noPatientFoundFromContractReturnsFalse() {
+ boolean result = myHelper.validPatientMember(null, patient);
+ assertFalse(result);
+ }
+
+ @Test
+ void noPatientFoundFromPatientMemberReturnsFalse() {
+ boolean result = myHelper.validPatientMember(patient, null);
+ assertFalse(result);
+ }
+
+ @Test
+ void noMatchingFamilyNameReturnsFalse() {
+ Patient patientFromMemberMatch = getPatientWithNoIDParm("Person", "2020-01-01");
+ Patient patientFromContractFound = getPatientWithIDParm("A123", "Smith", "2020-01-01");
+ when(myPatientDao.search(any(SearchParameterMap.class))).thenAnswer(t -> {
+ IBundleProvider provider = new SimpleBundleProvider(Collections.singletonList(new Patient().setId("B123")));
+ return provider;
+ });
+ boolean result = myHelper.validPatientMember(patientFromContractFound, patientFromMemberMatch);
+ assertFalse(result);
+ }
+
+
+ @Test
+ void noMatchingBirthdayReturnsFalse() {
+ Patient patientFromMemberMatch = getPatientWithNoIDParm("Person", "1990-01-01");
+ Patient patientFromContractFound = getPatientWithIDParm("A123", "Person", "2020-01-01");
+ when(myPatientDao.search(any(SearchParameterMap.class))).thenAnswer(t -> {
+ IBundleProvider provider = new SimpleBundleProvider(Collections.singletonList(new Patient().setId("B123")));
+ return provider;
+ });
+ boolean result = myHelper.validPatientMember(patientFromContractFound, patientFromMemberMatch);
+ assertFalse(result);
+ }
+
+ @Test
+ void noMatchingFieldsReturnsFalse() {
+ Patient patientFromMemberMatch = getPatientWithNoIDParm("Person", "1990-01-01");
+ Patient patientFromContractFound = getPatientWithIDParm("A123", "Smith", "2020-01-01");
+ when(myPatientDao.search(any(SearchParameterMap.class))).thenAnswer(t -> {
+ IBundleProvider provider = new SimpleBundleProvider(Collections.singletonList(new Patient().setId("B123")));
+ return provider;
+ });
+ boolean result = myHelper.validPatientMember(patientFromContractFound, patientFromMemberMatch);
+ assertFalse(result);
+ }
+
+ @Test
+ void patientMatchingReturnTrue() {
+ Patient patientFromMemberMatch = getPatientWithNoIDParm("Person", "2020-01-01");
+ Patient patientFromContractFound = getPatientWithIDParm("A123", "Person", "2020-01-01");
+ when(myPatientDao.search(any(SearchParameterMap.class))).thenAnswer(t -> {
+ IBundleProvider provider = new SimpleBundleProvider(Collections.singletonList(patientFromContractFound));
+ return provider;
+ });
+ boolean result = myHelper.validPatientMember(patientFromContractFound, patientFromMemberMatch);
+ assertTrue(result);
+ }
+
+ private Patient getPatientWithNoIDParm(String familyName, String birthdate) {
+ Patient patient = new Patient().setName(Lists.newArrayList(new HumanName()
+ .setUse(HumanName.NameUse.OFFICIAL).setFamily(familyName)))
+ .setBirthDateElement(new DateType(birthdate));
+ return patient;
+ }
+
+ private Patient getPatientWithIDParm(String id, String familyName, String birthdate) {
+ Patient patient = getPatientWithNoIDParm(familyName, birthdate);
+ patient.setId(id);
+ return patient;
+ }
+
+ }
+
+ /**
+ * Testing multiple scenarios for consent's policy data that is defined in
+ * https://build.fhir.org/ig/HL7/davinci-ehrx/StructureDefinition-hrex-consent.html#notes
+ */
+ @Nested
+ public class TestValidvalidConsentDataAccess {
+
+ @Mock(answer = Answers.RETURNS_DEEP_STUBS)
+ private Coverage coverage;
+ private Patient patient;
+ private Consent consent;
+
+ @Test
+ void noConsentProfileFoundReturnsFalse() {
+ consent = new Consent();
+ boolean result = myHelper.validConsentDataAccess(consent);
+ assertFalse(result);
+ }
+
+ @Test
+ void noDataAccessValueProvidedReturnsFalse() {
+ consent = getConsent();
+ boolean result = myHelper.validConsentDataAccess(consent);
+ assertFalse(result);
+ }
+
+ @Test
+ void wrongDataAccessValueProvidedReturnsFalse() {
+ consent = getConsent();
+ consent.addPolicy(constructConsentPolicyComponent("#access_data"));
+ boolean result = myHelper.validConsentDataAccess(consent);
+ assertFalse(result);
+ }
+
+ @Test
+ void regularDataAccessWithRegularNotAllowedReturnsFalse() {
+ consent = getConsent();
+ consent.addPolicy(constructConsentPolicyComponent("#regular"));
+ boolean result = myHelper.validConsentDataAccess(consent);
+ assertFalse(result);
+ }
+
+ @Test
+ void regularDataAccessWithRegularAllowedReturnsTrue() {
+ myHelper.setRegularFilterSupported(true);
+ consent = getConsent();
+ consent.addPolicy(constructConsentPolicyComponent("#regular"));
+ boolean result = myHelper.validConsentDataAccess(consent);
+ assertTrue(result);
+ }
+
+ @Test
+ void sensitiveDataAccessAllowedReturnsTrue() {
+ consent = getConsent();
+ consent.addPolicy(constructConsentPolicyComponent("#sensitive"));
+ boolean result = myHelper.validConsentDataAccess(consent);
+ assertTrue(result);
+ }
+
+ @Test
+ void multipleSensitivePolicyDataAccessAllowedReturnsTrue() {
+ consent = getConsent();
+ consent.addPolicy(constructConsentPolicyComponent("#sensitive"));
+ consent.addPolicy(constructConsentPolicyComponent("#sensitive"));
+ boolean result = myHelper.validConsentDataAccess(consent);
+ assertTrue(result);
+ }
+
+ @Test
+ void multipleRegularPolicyDataAccessWithRegularAllowedReturnsTrue() {
+ myHelper.setRegularFilterSupported(true);
+ consent = getConsent();
+ consent.addPolicy(constructConsentPolicyComponent("#regular"));
+ consent.addPolicy(constructConsentPolicyComponent("#regular"));
+ boolean result = myHelper.validConsentDataAccess(consent);
+ assertTrue(result);
+ }
+
+ @Test
+ void multipleMixedPolicyDataAccessWithRegularNotAllowedReturnsFalse() {
+ consent = getConsent();
+ consent.addPolicy(constructConsentPolicyComponent("#regular"));
+ consent.addPolicy(constructConsentPolicyComponent("#sensitive"));
+ boolean result = myHelper.validConsentDataAccess(consent);
+ assertFalse(result);
+ }
+
+ @Test
+ void multipleMixedPolicyDataAccessWithRegularAllowedReturnsTrue() {
+ myHelper.setRegularFilterSupported(true);
+ consent = getConsent();
+ consent.addPolicy(constructConsentPolicyComponent("#regular"));
+ consent.addPolicy(constructConsentPolicyComponent("#sensitive"));
+ boolean result = myHelper.validConsentDataAccess(consent);
+ assertTrue(result);
+ }
+ }
+
+ private Consent getConsent() {
+ Consent consent = new Consent();
+ consent.getPerformer().add(new Reference("Patient/1"));
+ return consent;
+ }
+
+ private Consent.ConsentPolicyComponent constructConsentPolicyComponent(String uriAccess) {
+ String uri = "http://hl7.org/fhir/us/davinci-hrex/StructureDefinition-hrex-consent.html";
+ return new Consent.ConsentPolicyComponent().setUri(uri + uriAccess);
+ }
+
+ private Patient createPatientForMemberMatchUpdate() {
+ Patient patient = new Patient();
+ patient.setId("Patient/RED");
+
+ return patient;
+ }
+
+ private void verifyConsentUpdatedAfterMemberMatch(
+ Consent theConsent,
+ Patient thePatient,
+ List 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());
+
+ // check consent patient info
+ String patientRef = thePatient.getIdElement().toUnqualifiedVersionless().getValue();
+ assertEquals(patientRef, theConsent.getPatient().getReference());
+ assertEquals(patientRef, theConsent.getPerformer().get(0).getReference());
+
+ if (!theSavedExtensions.isEmpty()) {
+ // check consent extensions
+ assertNotNull(theConsent.getExtension());
+ assertEquals(theSavedExtensions.size(), theConsent.getExtension().size());
+ for (Extension ext : theSavedExtensions) {
+ boolean found = false;
+ for (Extension consentExt : theConsent.getExtension()) {
+ if (consentExt.getUrl().equals(ext.getUrl())
+ && consentExt.getValue().equals(ext.getValue())) {
+ found = true;
+ break;
+ }
+ }
+ assertTrue(found,
+ "Extension " + ext.getUrl() + "|" + ext.getValue().toString() + " not found"
+ );
+ }
+ }
+ }
+
+ @Nested
+ public class MemberMatchWithoutConsentProvider {
+
+ @Test
+ public void updateConsentForMemberMatch_noProvider_addsIdentifierUpdatePatientButNotExtensionAndSaves() {
+ // setup
+ Consent consent = getConsent();
+ consent.addPolicy(constructConsentPolicyComponent("#sensitive"));
+ Patient patient = createPatientForMemberMatchUpdate();
+
+ ourLog.setLevel(Level.TRACE);
+
+ // test
+ myHelper.updateConsentForMemberMatch(consent, patient);
+
+ // verify
+ verify(myAppender, never())
+ .doAppend(any(ILoggingEvent.class));
+
+ ArgumentCaptor consentCaptor = ArgumentCaptor.forClass(Consent.class);
+ verify(myConsentDao).create(consentCaptor.capture());
+ Consent saved = consentCaptor.getValue();
+ verifyConsentUpdatedAfterMemberMatch(saved, patient, Collections.emptyList());
+ }
+ }
+
+ @Nested
+ public class MemberMatchWithConsentProvider {
+ @Mock
+ private IConsentExtensionProvider myExtensionProvider;
+
+ @BeforeEach
+ public void before() {
+ myHelper = new MemberMatcherR4Helper(
+ myFhirContext,
+ myCoverageDao,
+ myPatientDao,
+ myConsentDao,
+ myExtensionProvider
+ );
+ }
+
+ @Test
+ public void addClientIdAsExtensionToConsentIfAvailable_withProvider_addsExtensionAndSaves() {
+ // setup
+ Consent consent = getConsent();
+ consent.addPolicy(constructConsentPolicyComponent("#sensitive"));
+ consent.setId("Consent/RED");
+ Extension ext = new Extension();
+ ext.setUrl("http://example.com");
+ ext.setValue(new StringType("value"));
+ Patient patient = createPatientForMemberMatchUpdate();
+
+ ourLog.setLevel(Level.TRACE);
+
+ // when
+ when(myExtensionProvider.getConsentExtension(any(IBaseResource.class)))
+ .thenReturn(Collections.singleton(ext));
+
+ // test
+ myHelper.updateConsentForMemberMatch(consent, patient);
+
+ // verify
+ ArgumentCaptor consentCaptor = ArgumentCaptor.forClass(Consent.class);
+ verify(myConsentDao).create(consentCaptor.capture());
+ Consent saved = consentCaptor.getValue();
+ verifyConsentUpdatedAfterMemberMatch(saved, patient, Collections.emptyList());
+
+ ArgumentCaptor eventCaptor = ArgumentCaptor.forClass(ILoggingEvent.class);
+ verify(myAppender).doAppend(eventCaptor.capture());
+ ILoggingEvent event = eventCaptor.getValue();
+ assertEquals("1 extension(s) added to Consent", event.getFormattedMessage());
+ }
+ }
+}
diff --git a/hapi-fhir-jpaserver-cql/pom.xml b/hapi-fhir-jpaserver-cql/pom.xml
index 32d02cfefd4..db7a25faeba 100644
--- a/hapi-fhir-jpaserver-cql/pom.xml
+++ b/hapi-fhir-jpaserver-cql/pom.xml
@@ -7,7 +7,7 @@
ca.uhn.hapi.fhir
hapi-deployable-pom
- 6.3.0-PRE1-SNAPSHOT
+ 6.3.0-PRE2-SNAPSHOT
../hapi-deployable-pom/pom.xml
diff --git a/hapi-fhir-jpaserver-elastic-test-utilities/pom.xml b/hapi-fhir-jpaserver-elastic-test-utilities/pom.xml
index 12dabc769ed..3ae132f069d 100644
--- a/hapi-fhir-jpaserver-elastic-test-utilities/pom.xml
+++ b/hapi-fhir-jpaserver-elastic-test-utilities/pom.xml
@@ -6,7 +6,7 @@
ca.uhn.hapi.fhir
hapi-deployable-pom
- 6.3.0-PRE1-SNAPSHOT
+ 6.3.0-PRE2-SNAPSHOT
../hapi-deployable-pom/pom.xml
diff --git a/hapi-fhir-jpaserver-mdm/pom.xml b/hapi-fhir-jpaserver-mdm/pom.xml
index 3c1b4ec3757..0bbc1a3799d 100644
--- a/hapi-fhir-jpaserver-mdm/pom.xml
+++ b/hapi-fhir-jpaserver-mdm/pom.xml
@@ -6,7 +6,7 @@
ca.uhn.hapi.fhir
hapi-deployable-pom
- 6.3.0-PRE1-SNAPSHOT
+ 6.3.0-PRE2-SNAPSHOT
../hapi-deployable-pom/pom.xml
diff --git a/hapi-fhir-jpaserver-model/pom.xml b/hapi-fhir-jpaserver-model/pom.xml
index e05cf224956..2c24cb96fdf 100644
--- a/hapi-fhir-jpaserver-model/pom.xml
+++ b/hapi-fhir-jpaserver-model/pom.xml
@@ -5,7 +5,7 @@
ca.uhn.hapi.fhir
hapi-deployable-pom
- 6.3.0-PRE1-SNAPSHOT
+ 6.3.0-PRE2-SNAPSHOT
../hapi-deployable-pom/pom.xml
diff --git a/hapi-fhir-jpaserver-model/src/main/java/ca/uhn/fhir/jpa/model/util/JpaConstants.java b/hapi-fhir-jpaserver-model/src/main/java/ca/uhn/fhir/jpa/model/util/JpaConstants.java
index 30f7b9f467c..0dfd78544b6 100644
--- a/hapi-fhir-jpaserver-model/src/main/java/ca/uhn/fhir/jpa/model/util/JpaConstants.java
+++ b/hapi-fhir-jpaserver-model/src/main/java/ca/uhn/fhir/jpa/model/util/JpaConstants.java
@@ -172,6 +172,11 @@ public class JpaConstants {
*/
public static final String OPERATION_LASTN = "$lastn";
+ /**
+ * Operation name for the $member-match operation
+ */
+ public static final String OPERATION_MEMBER_MATCH = "$member-match";
+
/**
* Parameter for the $export operation
*/
diff --git a/hapi-fhir-jpaserver-searchparam/pom.xml b/hapi-fhir-jpaserver-searchparam/pom.xml
index bd28a08e9ea..d0edd4fb80a 100755
--- a/hapi-fhir-jpaserver-searchparam/pom.xml
+++ b/hapi-fhir-jpaserver-searchparam/pom.xml
@@ -5,7 +5,7 @@
ca.uhn.hapi.fhir
hapi-deployable-pom
- 6.3.0-PRE1-SNAPSHOT
+ 6.3.0-PRE2-SNAPSHOT
../hapi-deployable-pom/pom.xml
diff --git a/hapi-fhir-jpaserver-subscription/pom.xml b/hapi-fhir-jpaserver-subscription/pom.xml
index 363c06dd6ae..8972baf7789 100644
--- a/hapi-fhir-jpaserver-subscription/pom.xml
+++ b/hapi-fhir-jpaserver-subscription/pom.xml
@@ -5,7 +5,7 @@
ca.uhn.hapi.fhir
hapi-deployable-pom
- 6.3.0-PRE1-SNAPSHOT
+ 6.3.0-PRE2-SNAPSHOT
../hapi-deployable-pom/pom.xml
diff --git a/hapi-fhir-jpaserver-test-dstu2/pom.xml b/hapi-fhir-jpaserver-test-dstu2/pom.xml
index e486e66c733..dbe117f54a6 100644
--- a/hapi-fhir-jpaserver-test-dstu2/pom.xml
+++ b/hapi-fhir-jpaserver-test-dstu2/pom.xml
@@ -6,7 +6,7 @@
ca.uhn.hapi.fhir
hapi-deployable-pom
- 6.3.0-PRE1-SNAPSHOT
+ 6.3.0-PRE2-SNAPSHOT
../hapi-deployable-pom/pom.xml
diff --git a/hapi-fhir-jpaserver-test-dstu3/pom.xml b/hapi-fhir-jpaserver-test-dstu3/pom.xml
index 7506bb60588..e75a6ceb78c 100644
--- a/hapi-fhir-jpaserver-test-dstu3/pom.xml
+++ b/hapi-fhir-jpaserver-test-dstu3/pom.xml
@@ -6,7 +6,7 @@
ca.uhn.hapi.fhir
hapi-deployable-pom
- 6.3.0-PRE1-SNAPSHOT
+ 6.3.0-PRE2-SNAPSHOT
../hapi-deployable-pom/pom.xml
diff --git a/hapi-fhir-jpaserver-test-r4/pom.xml b/hapi-fhir-jpaserver-test-r4/pom.xml
index 6c7b10f0338..9fbe1e4995b 100644
--- a/hapi-fhir-jpaserver-test-r4/pom.xml
+++ b/hapi-fhir-jpaserver-test-r4/pom.xml
@@ -6,7 +6,7 @@
ca.uhn.hapi.fhir
hapi-deployable-pom
- 6.3.0-PRE1-SNAPSHOT
+ 6.3.0-PRE2-SNAPSHOT
../hapi-deployable-pom/pom.xml
diff --git a/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/provider/r4/MemberMatcherR4HelperTest.java b/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/provider/r4/MemberMatcherR4HelperTest.java
deleted file mode 100644
index 52b1e2dc5cb..00000000000
--- a/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/provider/r4/MemberMatcherR4HelperTest.java
+++ /dev/null
@@ -1,327 +0,0 @@
-package ca.uhn.fhir.jpa.provider.r4;
-
-import ca.uhn.fhir.context.FhirContext;
-import ca.uhn.fhir.jpa.api.dao.IFhirResourceDao;
-import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
-import ca.uhn.fhir.model.api.IQueryParameterType;
-import ca.uhn.fhir.model.primitive.IdDt;
-import ca.uhn.fhir.rest.api.server.IBundleProvider;
-import ca.uhn.fhir.rest.server.SimpleBundleProvider;
-import com.google.common.collect.Lists;
-import org.hl7.fhir.r4.model.Coverage;
-import org.hl7.fhir.r4.model.DateType;
-import org.hl7.fhir.r4.model.HumanName;
-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.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Nested;
-import org.junit.jupiter.api.Test;
-import org.junit.jupiter.api.extension.ExtendWith;
-import org.mockito.Answers;
-import org.mockito.ArgumentCaptor;
-import org.mockito.Captor;
-import org.mockito.Mock;
-import org.mockito.junit.jupiter.MockitoExtension;
-import org.springframework.test.util.ReflectionTestUtils;
-
-import java.util.Collections;
-import java.util.List;
-import java.util.Optional;
-
-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.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertFalse;
-import static org.junit.jupiter.api.Assertions.assertTrue;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.isA;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-@ExtendWith(MockitoExtension.class)
-class MemberMatcherR4HelperTest {
-
- private final FhirContext myFhirContext = FhirContext.forR4();
- @Mock private IFhirResourceDao myCoverageDao;
- @Mock private IFhirResourceDao myPatientDao;
-
- private MemberMatcherR4Helper myTestedHelper;
-
- @Mock private Coverage myCoverageToMatch;
- @Mock private IBundleProvider myBundleProvider;
-
- private final Coverage myMatchedCoverage = new Coverage()
- .setBeneficiary(new Reference("Patient/123"));
- private final Identifier myMatchingIdentifier = new Identifier()
- .setSystem("identifier-system").setValue("identifier-value");
-
- @Captor ArgumentCaptor mySearchParameterMapCaptor;
-
- @BeforeEach
- public void beforeEach() {
- myTestedHelper = new MemberMatcherR4Helper(myFhirContext);
-
- // @InjectMocks didn't work
- ReflectionTestUtils.setField(myTestedHelper, "myCoverageDao", myCoverageDao);
- ReflectionTestUtils.setField(myTestedHelper, "myPatientDao", myPatientDao);
- }
-
-
- @Test
- void findMatchingCoverageMatchByIdReturnsMatched() {
- when(myCoverageToMatch.getId()).thenReturn("cvg-to-match-id");
- when(myCoverageDao.search(isA(SearchParameterMap.class))).thenReturn(myBundleProvider);
- when(myBundleProvider.getAllResources()).thenReturn(Collections.singletonList(myMatchedCoverage));
-
- Optional result = myTestedHelper.findMatchingCoverage(myCoverageToMatch);
-
- assertEquals(Optional.of(myMatchedCoverage), result);
- verify(myCoverageDao).search(mySearchParameterMapCaptor.capture());
- SearchParameterMap spMap = mySearchParameterMapCaptor.getValue();
- assertTrue(spMap.containsKey("_id"));
- List> listListParams = spMap.get("_id");
- assertEquals(1, listListParams.size());
- assertEquals(1, listListParams.get(0).size());
- IQueryParameterType param = listListParams.get(0).get(0);
- assertEquals("cvg-to-match-id", param.getValueAsQueryToken(myFhirContext));
- }
-
-
- @Test
- void findMatchingCoverageMatchByIdentifierReturnsMatched() {
- when(myCoverageToMatch.getId()).thenReturn("non-matching-id");
- when(myCoverageToMatch.getIdentifier()).thenReturn(Collections.singletonList(myMatchingIdentifier));
- when(myCoverageDao.search(isA(SearchParameterMap.class))).thenReturn(myBundleProvider);
- when(myBundleProvider.getAllResources()).thenReturn(
- Collections.emptyList(), Collections.singletonList(myMatchedCoverage));
-
- Optional result = myTestedHelper.findMatchingCoverage(myCoverageToMatch);
-
- assertEquals(Optional.of(myMatchedCoverage), result);
- verify(myCoverageDao, times(2)).search(mySearchParameterMapCaptor.capture());
- List spMap = mySearchParameterMapCaptor.getAllValues();
- assertTrue(spMap.get(0).containsKey("_id"));
- assertTrue(spMap.get(1).containsKey("identifier"));
- List> listListParams = spMap.get(1).get("identifier");
- assertEquals(1, listListParams.size());
- assertEquals(1, listListParams.get(0).size());
- IQueryParameterType param = listListParams.get(0).get(0);
- assertEquals(myMatchingIdentifier.getSystem() + "|" + myMatchingIdentifier.getValue(),
- param.getValueAsQueryToken(myFhirContext));
- }
-
-
- @Test
- void findMatchingCoverageNoMatchReturnsEmpty() {
- when(myCoverageToMatch.getId()).thenReturn("non-matching-id");
- when(myCoverageToMatch.getIdentifier()).thenReturn(Collections.singletonList(myMatchingIdentifier));
- when(myCoverageDao.search(isA(SearchParameterMap.class))).thenReturn(myBundleProvider);
- when(myBundleProvider.getAllResources()).thenReturn(Collections.emptyList(), Collections.emptyList());
-
- Optional result = myTestedHelper.findMatchingCoverage(myCoverageToMatch);
-
- assertFalse(result.isPresent());
- }
-
-
- @Test
- void buildSuccessReturnParameters() {
- Patient patient = new Patient();
- Coverage coverage = new Coverage();
-
- Parameters result = myTestedHelper.buildSuccessReturnParameters(patient, coverage);
-
- assertEquals(PARAM_MEMBER_PATIENT, result.getParameter().get(0).getName());
- assertEquals(patient, result.getParameter().get(0).getResource());
-
- assertEquals(PARAM_NEW_COVERAGE, result.getParameter().get(1).getName());
- assertEquals(coverage, result.getParameter().get(1).getResource());
- }
-
-
- @Test
- void addMemberIdentifierToMemberPatient() {
- Identifier originalIdentifier = new Identifier()
- .setSystem("original-identifier-system").setValue("original-identifier-value");
-
- Identifier newIdentifier = new Identifier()
- .setSystem("new-identifier-system").setValue("new-identifier-value");
-
- Patient patient = new Patient().setIdentifier(Lists.newArrayList(originalIdentifier));
-
- myTestedHelper.addMemberIdentifierToMemberPatient(patient, newIdentifier);
-
- assertEquals(2, patient.getIdentifier().size());
-
- assertEquals("original-identifier-system", patient.getIdentifier().get(0).getSystem());
- assertEquals("original-identifier-value", patient.getIdentifier().get(0).getValue());
-
- assertEquals("new-identifier-system", patient.getIdentifier().get(1).getSystem());
- assertEquals("new-identifier-value", patient.getIdentifier().get(1).getValue());
- }
-
- @Nested
- public class TestGetBeneficiaryPatient {
-
- @Mock(answer = Answers.RETURNS_DEEP_STUBS)
- private Coverage coverage;
-
-
- @Test
- void noBeneficiaryOrBeneficiaryTargetReturnsEmpty() {
- when(coverage.getBeneficiaryTarget()).thenReturn(null);
- when(coverage.getBeneficiary()).thenReturn(null);
-
- Optional result = myTestedHelper.getBeneficiaryPatient(coverage);
-
- assertFalse(result.isPresent());
- }
-
-
- @Test
- void beneficiaryTargetWithNoIdentifierReturnsEmpty() {
- when(coverage.getBeneficiary()).thenReturn(null);
- when(coverage.getBeneficiaryTarget()).thenReturn(new Patient());
-
- Optional result = myTestedHelper.getBeneficiaryPatient(coverage);
-
- assertFalse(result.isPresent());
- }
-
-
- @Test
- void beneficiaryTargetWithIdentifierReturnsBeneficiary() {
- Patient patient = new Patient().setIdentifier(Collections.singletonList(new Identifier()));
- when(coverage.getBeneficiaryTarget()).thenReturn(patient);
-
- Optional result = myTestedHelper.getBeneficiaryPatient(coverage);
-
- assertTrue(result.isPresent());
- assertEquals(patient, result.get());
- }
-
-
- @Test
- void beneficiaryReferenceResourceReturnsBeneficiary() {
- Patient patient = new Patient().setIdentifier(Collections.singletonList(new Identifier()));
- when(coverage.getBeneficiaryTarget()).thenReturn(null);
- when(coverage.getBeneficiary().getResource()).thenReturn(patient);
-
- Optional result = myTestedHelper.getBeneficiaryPatient(coverage);
-
- assertTrue(result.isPresent());
- assertEquals(patient, result.get());
- }
-
-
- @Test
- void beneficiaryReferenceNoResourceOrReferenceReturnsEmpty() {
- when(coverage.getBeneficiaryTarget()).thenReturn(null);
- when(coverage.getBeneficiary()).thenReturn(new Reference());
-
- Optional result = myTestedHelper.getBeneficiaryPatient(coverage);
-
- assertFalse(result.isPresent());
- }
-
-
- @Test
- void beneficiaryReferenceReferenceReturnsReadPatient() {
- when(coverage.getBeneficiaryTarget()).thenReturn(null);
- when(coverage.getBeneficiary().getResource()).thenReturn(null);
- when(coverage.getBeneficiary().getReference()).thenReturn("patient-id");
-
- myTestedHelper.getBeneficiaryPatient(coverage);
-
- verify(myPatientDao).read(new IdDt("patient-id"));
- }
-
- }
-
- @Nested
- public class TestValidPatientMember {
-
- @Mock(answer = Answers.RETURNS_DEEP_STUBS)
- private Coverage coverage;
- private Patient patient;
-
- @Test
- void noPatientFoundFromContractReturnsFalse() {
- boolean result = myTestedHelper.validPatientMember(null, patient);
- assertFalse(result);
- }
-
- @Test
- void noPatientFoundFromPatientMemberReturnsFalse() {
- boolean result = myTestedHelper.validPatientMember(patient, null);
- assertFalse(result);
- }
-
- @Test
- void noMatchingFamilyNameReturnsFalse() {
- Patient patientFromMemberMatch = getPatientWithNoIDParm("Person", "2020-01-01");
- Patient patientFromContractFound = getPatientWithIDParm("A123", "Smith", "2020-01-01");
- when(myPatientDao.search(any(SearchParameterMap.class))).thenAnswer(t -> {
- IBundleProvider provider = new SimpleBundleProvider(Collections.singletonList(new Patient().setId("B123")));
- return provider;
- });
- boolean result = myTestedHelper.validPatientMember(patientFromContractFound, patientFromMemberMatch);
- assertFalse(result);
- }
-
-
- @Test
- void noMatchingBirthdayReturnsFalse() {
- Patient patientFromMemberMatch = getPatientWithNoIDParm("Person", "1990-01-01");
- Patient patientFromContractFound = getPatientWithIDParm("A123", "Person", "2020-01-01");
- when(myPatientDao.search(any(SearchParameterMap.class))).thenAnswer(t -> {
- IBundleProvider provider = new SimpleBundleProvider(Collections.singletonList(new Patient().setId("B123")));
- return provider;
- });
- boolean result = myTestedHelper.validPatientMember(patientFromContractFound, patientFromMemberMatch);
- assertFalse(result);
- }
-
- @Test
- void noMatchingFieldsReturnsFalse() {
- Patient patientFromMemberMatch = getPatientWithNoIDParm("Person", "1990-01-01");
- Patient patientFromContractFound = getPatientWithIDParm("A123", "Smith", "2020-01-01");
- when(myPatientDao.search(any(SearchParameterMap.class))).thenAnswer(t -> {
- IBundleProvider provider = new SimpleBundleProvider(Collections.singletonList(new Patient().setId("B123")));
- return provider;
- });
- boolean result = myTestedHelper.validPatientMember(patientFromContractFound, patientFromMemberMatch);
- assertFalse(result);
- }
-
- @Test
- void patientMatchingReturnTrue() {
- Patient patientFromMemberMatch = getPatientWithNoIDParm("Person", "2020-01-01");
- Patient patientFromContractFound = getPatientWithIDParm("A123", "Person", "2020-01-01");
- when(myPatientDao.search(any(SearchParameterMap.class))).thenAnswer(t -> {
- IBundleProvider provider = new SimpleBundleProvider(Collections.singletonList(patientFromContractFound));
- return provider;
- });
- boolean result = myTestedHelper.validPatientMember(patientFromContractFound, patientFromMemberMatch);
- assertTrue(result);
- }
-
- private Patient getPatientWithNoIDParm(String familyName, String birthdate) {
- Patient patient = new Patient().setName(Lists.newArrayList(new HumanName()
- .setUse(HumanName.NameUse.OFFICIAL).setFamily(familyName)))
- .setBirthDateElement(new DateType(birthdate));
- return patient;
- }
-
- private Patient getPatientWithIDParm(String id, String familyName, String birthdate) {
- Patient patient = getPatientWithNoIDParm(familyName, birthdate);
- patient.setId(id);
- return patient;
- }
-
- }
-
-}
diff --git a/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/provider/r4/PatientMemberMatchOperationR4Test.java b/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/provider/r4/PatientMemberMatchOperationR4Test.java
index 9cc527f9443..73e4bfec966 100644
--- a/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/provider/r4/PatientMemberMatchOperationR4Test.java
+++ b/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/provider/r4/PatientMemberMatchOperationR4Test.java
@@ -5,7 +5,6 @@ import ca.uhn.fhir.parser.StrictErrorHandler;
import ca.uhn.fhir.rest.api.Constants;
import ca.uhn.fhir.rest.api.EncodingEnum;
import ca.uhn.fhir.rest.client.apache.ResourceEntity;
-import ca.uhn.fhir.rest.param.DateParam;
import ca.uhn.fhir.util.ParametersUtil;
import com.google.common.collect.Lists;
import org.apache.commons.io.IOUtils;
@@ -14,12 +13,12 @@ import org.apache.http.client.methods.HttpPost;
import org.hl7.fhir.instance.model.api.IBase;
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;
import org.hl7.fhir.r4.model.Enumerations;
import org.hl7.fhir.r4.model.HumanName;
import org.hl7.fhir.r4.model.Identifier;
-import org.hl7.fhir.r4.model.Organization;
import org.hl7.fhir.r4.model.Parameters;
import org.hl7.fhir.r4.model.Patient;
import org.hl7.fhir.r4.model.Reference;
@@ -27,14 +26,20 @@ import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
import java.nio.charset.StandardCharsets;
import java.util.Collections;
import java.util.List;
+import static ca.uhn.fhir.rest.api.Constants.PARAM_CONSENT_PATIENT_REFERENCE;
+import static ca.uhn.fhir.rest.api.Constants.PARAM_CONSENT_PERFORMER_REFERENCE;
import static ca.uhn.fhir.rest.api.Constants.PARAM_MEMBER_PATIENT;
+import static ca.uhn.fhir.rest.api.Constants.PARAM_MEMBER_PATIENT_BIRTHDATE;
+import static ca.uhn.fhir.rest.api.Constants.PARAM_MEMBER_PATIENT_NAME;
import static ca.uhn.fhir.rest.api.Constants.PARAM_NEW_COVERAGE;
import static ca.uhn.fhir.rest.api.Constants.PARAM_OLD_COVERAGE;
+import static ca.uhn.fhir.rest.api.Constants.PARAM_CONSENT;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.containsString;
import static org.junit.jupiter.api.Assertions.assertEquals;
@@ -51,11 +56,20 @@ public class PatientMemberMatchOperationR4Test extends BaseResourceProviderR4Tes
private static final String EXISTING_COVERAGE_IDENT_VALUE = "U1234567890";
private static final String EXISTING_COVERAGE_PATIENT_IDENT_SYSTEM = "http://oldhealthplan.example.com";
private static final String EXISTING_COVERAGE_PATIENT_IDENT_VALUE = "DHU-55678";
+ private static final String CONSENT_POLICY_SENSITIVE_DATA_URI = "http://hl7.org/fhir/us/davinci-hrex/StructureDefinition-hrex-consent.html#sensitive";
+ private static final String CONSENT_POLICY_REGULAR_DATA_URI = "http://hl7.org/fhir/us/davinci-hrex/StructureDefinition-hrex-consent.html#regular";
private Identifier ourExistingCoverageIdentifier;
private Patient myPatient;
private Coverage oldCoverage; // Old Coverage (must match field)
private Coverage newCoverage; // New Coverage (must return unchanged)
+ private Consent myConsent;
+
+ @Autowired
+ MemberMatcherR4Helper myMemberMatcherR4Helper;
+
+ @Autowired
+ MemberMatchR4ResourceProvider theMemberMatchR4ResourceProvider;
@BeforeEach
public void beforeDisableResultReuse() {
@@ -70,6 +84,7 @@ public class PatientMemberMatchOperationR4Test extends BaseResourceProviderR4Tes
myDaoConfig.setEverythingIncludesFetchPageSize(new DaoConfig().getEverythingIncludesFetchPageSize());
myDaoConfig.setSearchPreFetchThresholds(new DaoConfig().getSearchPreFetchThresholds());
myDaoConfig.setAllowExternalReferences(new DaoConfig().isAllowExternalReferences());
+ ourRestServer.unregisterProvider(theMemberMatchR4ResourceProvider);
}
@Override
@@ -90,6 +105,15 @@ public class PatientMemberMatchOperationR4Test extends BaseResourceProviderR4Tes
newCoverage = (Coverage) new Coverage()
.setIdentifier(Lists.newArrayList(new Identifier().setSystem("http://newealthplan.example.com").setValue("234567")))
.setId("AA87654");
+
+ myConsent = new Consent()
+ .setStatus(Consent.ConsentState.ACTIVE)
+ .setScope(new CodeableConcept().addCoding(new Coding("http://terminology.hl7.org/CodeSystem/consentscope", "patient-privacy", null)))
+ .addPolicy(new Consent.ConsentPolicyComponent().setUri(CONSENT_POLICY_SENSITIVE_DATA_URI))
+ .setPatient(new Reference("Patient/A123"))
+ .addPerformer(new Reference("Patient/A123"));
+ ourRestServer.registerProvider(theMemberMatchR4ResourceProvider);
+ myMemberMatcherR4Helper.setRegularFilterSupported(false);
}
private void createCoverageWithBeneficiary(
@@ -125,12 +149,11 @@ public class PatientMemberMatchOperationR4Test extends BaseResourceProviderR4Tes
myClient.create().resource(ourExistingCoverage).execute().getId().toUnqualifiedVersionless().getValue();
}
-
@Test
public void testMemberMatchByCoverageId() throws Exception {
createCoverageWithBeneficiary(true, true);
- Parameters inputParameters = buildInputParameters(myPatient, oldCoverage, newCoverage);
+ Parameters inputParameters = buildInputParameters(myPatient, oldCoverage, newCoverage, myConsent);
Parameters parametersResponse = performOperation(ourServerBase + ourQuery,
EncodingEnum.JSON, inputParameters);
@@ -143,7 +166,7 @@ public class PatientMemberMatchOperationR4Test extends BaseResourceProviderR4Tes
public void testCoverageNoBeneficiaryReturns422() throws Exception {
createCoverageWithBeneficiary(false, false);
- Parameters inputParameters = buildInputParameters(myPatient, oldCoverage, newCoverage);
+ Parameters inputParameters = buildInputParameters(myPatient, oldCoverage, newCoverage, myConsent);
performOperationExpecting422(ourServerBase + ourQuery, EncodingEnum.JSON, inputParameters,
"Could not find beneficiary for coverage.");
}
@@ -152,7 +175,7 @@ public class PatientMemberMatchOperationR4Test extends BaseResourceProviderR4Tes
public void testCoverageBeneficiaryNoIdentifierReturns422() throws Exception {
createCoverageWithBeneficiary(true, false);
- Parameters inputParameters = buildInputParameters(myPatient, oldCoverage, newCoverage);
+ Parameters inputParameters = buildInputParameters(myPatient, oldCoverage, newCoverage, myConsent);
performOperationExpecting422(ourServerBase + ourQuery, EncodingEnum.JSON, inputParameters,
"Coverage beneficiary does not have an identifier.");
}
@@ -162,7 +185,7 @@ public class PatientMemberMatchOperationR4Test extends BaseResourceProviderR4Tes
createCoverageWithBeneficiary(true, true);
myPatient.setName(Lists.newArrayList(new HumanName().setUse(HumanName.NameUse.OFFICIAL).setFamily("Smith")));
- Parameters inputParameters = buildInputParameters(myPatient, oldCoverage, newCoverage);
+ Parameters inputParameters = buildInputParameters(myPatient, oldCoverage, newCoverage, myConsent);
performOperationExpecting422(ourServerBase + ourQuery, EncodingEnum.JSON, inputParameters,
"Could not find matching patient for coverage.");
}
@@ -172,16 +195,64 @@ public class PatientMemberMatchOperationR4Test extends BaseResourceProviderR4Tes
createCoverageWithBeneficiary(true, false);
myPatient.setBirthDateElement(new DateType("2000-01-01"));
- Parameters inputParameters = buildInputParameters(myPatient, oldCoverage, newCoverage);
+ Parameters inputParameters = buildInputParameters(myPatient, oldCoverage, newCoverage, myConsent);
performOperationExpecting422(ourServerBase + ourQuery, EncodingEnum.JSON, inputParameters,
"Could not find matching patient for coverage.");
}
+ @Test
+ public void testRegularContentProfileAccessWithRegularNotAllowedReturns422() throws Exception {
+ createCoverageWithBeneficiary(true, true);
+ myConsent.getPolicy().get(0).setUri(CONSENT_POLICY_REGULAR_DATA_URI);
+ Parameters inputParameters = buildInputParameters(myPatient, oldCoverage, newCoverage, myConsent);
+ performOperationExpecting422(ourServerBase + ourQuery, EncodingEnum.JSON, inputParameters,
+ "Consent policy does not match the data release segmentation capabilities.");
+ }
+
+ @Test
+ public void testSensitiveContentProfileAccessWithRegularNotAllowed() throws Exception {
+ createCoverageWithBeneficiary(true, true);
+ Parameters inputParameters = buildInputParameters(myPatient, oldCoverage, newCoverage, myConsent);
+ Parameters parametersResponse = performOperation(ourServerBase + ourQuery,
+ EncodingEnum.JSON, inputParameters);
+
+ validateMemberPatient(parametersResponse);
+ validateNewCoverage(parametersResponse, newCoverage);
+ }
+
+ @Test
+ public void testRegularContentProfileAccessWithRegularAllowed() throws Exception {
+ createCoverageWithBeneficiary(true, true);
+ myConsent.getPolicy().get(0).setUri(CONSENT_POLICY_REGULAR_DATA_URI);
+ myMemberMatcherR4Helper.setRegularFilterSupported(true);
+ Parameters inputParameters = buildInputParameters(myPatient, oldCoverage, newCoverage, myConsent);
+ Parameters parametersResponse = performOperation(ourServerBase + ourQuery,
+ EncodingEnum.JSON, inputParameters);
+
+ validateMemberPatient(parametersResponse);
+ validateNewCoverage(parametersResponse, newCoverage);
+ }
+
+ @Test
+ public void testConsentReturns() throws Exception {
+ createCoverageWithBeneficiary(true, true);
+ myConsent.getPolicy().get(0).setUri(CONSENT_POLICY_REGULAR_DATA_URI);
+ myMemberMatcherR4Helper.setRegularFilterSupported(true);
+ Parameters inputParameters = buildInputParameters(myPatient, oldCoverage, newCoverage, myConsent);
+ Parameters parametersResponse = performOperation(ourServerBase + ourQuery,
+ EncodingEnum.JSON, inputParameters);
+
+ validateMemberPatient(parametersResponse);
+ validateNewCoverage(parametersResponse, newCoverage);
+ validateResponseConsent(parametersResponse, myConsent);
+ }
+
@Nested
public class ValidateParameterErrors {
private Patient ourPatient;
private Coverage ourOldCoverage;
private Coverage ourNewCoverage;
+ private Consent ourConsent;
@BeforeEach
public void beforeValidateParameterErrors() {
@@ -194,28 +265,77 @@ public class PatientMemberMatchOperationR4Test extends BaseResourceProviderR4Tes
ourNewCoverage.setId("AA87654");
ourNewCoverage.setIdentifier(Lists.newArrayList(
new Identifier().setSystem("http://newealthplan.example.com").setValue("234567")));
+
+ ourConsent = new Consent();
+ ourConsent.setStatus(Consent.ConsentState.ACTIVE);
}
@Test
public void testInvalidPatient() throws Exception {
- Parameters inputParameters = buildInputParameters(new Patient(), ourOldCoverage, ourNewCoverage);
+ Parameters inputParameters = buildInputParameters(new Patient(), ourOldCoverage, ourNewCoverage, ourConsent);
performOperationExpecting422(ourServerBase + ourQuery, EncodingEnum.JSON, inputParameters,
"Parameter \\\"" + PARAM_MEMBER_PATIENT + "\\\" is required.");
}
@Test
public void testInvalidOldCoverage() throws Exception {
- Parameters inputParameters = buildInputParameters(ourPatient, new Coverage(), ourNewCoverage);
+ Parameters inputParameters = buildInputParameters(ourPatient, new Coverage(), ourNewCoverage, ourConsent);
performOperationExpecting422(ourServerBase + ourQuery, EncodingEnum.JSON, inputParameters,
"Parameter \\\"" + PARAM_OLD_COVERAGE + "\\\" is required.");
}
@Test
public void testInvalidNewCoverage() throws Exception {
- Parameters inputParameters = buildInputParameters(ourPatient, ourOldCoverage, new Coverage());
+ Parameters inputParameters = buildInputParameters(ourPatient, ourOldCoverage, new Coverage(), ourConsent);
performOperationExpecting422(ourServerBase + ourQuery, EncodingEnum.JSON, inputParameters,
"Parameter \\\"" + PARAM_NEW_COVERAGE + "\\\" is required.");
}
+
+ @Test
+ public void testInvalidConsent() throws Exception {
+ Parameters inputParameters = buildInputParameters(ourPatient, ourOldCoverage, ourNewCoverage, new Consent());
+ performOperationExpecting422(ourServerBase + ourQuery, EncodingEnum.JSON, inputParameters,
+ "Parameter \\\"" + PARAM_CONSENT + "\\\" is required.");
+ }
+
+ @Test
+ public void testMissingPatientFamilyName() throws Exception {
+ Parameters inputParameters = buildInputParameters(ourPatient, ourOldCoverage, ourNewCoverage, ourConsent);
+ performOperationExpecting422(ourServerBase + ourQuery, EncodingEnum.JSON, inputParameters,
+ "Parameter \\\"" + PARAM_MEMBER_PATIENT_NAME + "\\\" is required.");
+ }
+
+ @Test
+ public void testMissingPatientBirthdate() throws Exception {
+ ourPatient.setName(Lists.newArrayList(new HumanName()
+ .setUse(HumanName.NameUse.OFFICIAL).setFamily("Person")));
+ Parameters inputParameters = buildInputParameters(ourPatient, ourOldCoverage, ourNewCoverage, ourConsent);
+ performOperationExpecting422(ourServerBase + ourQuery, EncodingEnum.JSON, inputParameters,
+ "Parameter \\\"" + PARAM_MEMBER_PATIENT_BIRTHDATE + "\\\" is required.");
+ }
+
+ @Test
+ public void testMissingConsentPatientReference() throws Exception {
+ ourPatient.setName(Lists.newArrayList(new HumanName()
+ .setUse(HumanName.NameUse.OFFICIAL).setFamily("Person")))
+ .setBirthDateElement(new DateType("2020-01-01"));
+
+ Parameters inputParameters = buildInputParameters(ourPatient, ourOldCoverage, ourNewCoverage, ourConsent);
+ performOperationExpecting422(ourServerBase + ourQuery, EncodingEnum.JSON, inputParameters,
+ "Parameter \\\"" + PARAM_CONSENT_PATIENT_REFERENCE + "\\\" is required.");
+ }
+
+ @Test
+ public void testMissingConsentPerformerReference() throws Exception {
+ ourPatient.setName(Lists.newArrayList(new HumanName()
+ .setUse(HumanName.NameUse.OFFICIAL).setFamily("Person")))
+ .setBirthDateElement(new DateType("2020-01-01"));
+
+ ourConsent.setPatient(new Reference("Patient/1"));
+ Parameters inputParameters = buildInputParameters(ourPatient, ourOldCoverage, ourNewCoverage, ourConsent);
+ performOperationExpecting422(ourServerBase + ourQuery, EncodingEnum.JSON, inputParameters,
+ "Parameter \\\"" + PARAM_CONSENT_PERFORMER_REFERENCE + "\\\" is required.");
+ }
}
@@ -223,7 +343,7 @@ public class PatientMemberMatchOperationR4Test extends BaseResourceProviderR4Tes
public void testMemberMatchByCoverageIdentifier() throws Exception {
createCoverageWithBeneficiary(true, true);
- Parameters inputParameters = buildInputParameters(myPatient, oldCoverage, newCoverage);
+ Parameters inputParameters = buildInputParameters(myPatient, oldCoverage, newCoverage, myConsent);
Parameters parametersResponse = performOperation(ourServerBase + ourQuery, EncodingEnum.JSON, inputParameters);
validateMemberPatient(parametersResponse);
@@ -244,6 +364,12 @@ public class PatientMemberMatchOperationR4Test extends BaseResourceProviderR4Tes
assertEquals(theOriginalCoverage.getIdentifierFirstRep().getValue(), respCoverage.getIdentifierFirstRep().getValue());
}
+ private void validateConsentPatientAndPerformerRef(Patient thePatient, Consent theConsent) {
+ String patientRef = thePatient.getIdElement().toUnqualifiedVersionless().getValue();
+ assertEquals(patientRef, theConsent.getPatient().getReference());
+ assertEquals(patientRef, theConsent.getPerformer().get(0).getReference());
+ }
+
private void validateMemberPatient(Parameters response) {
// parameter MemberPatient must have a new identifier with:
@@ -279,17 +405,29 @@ public class PatientMemberMatchOperationR4Test extends BaseResourceProviderR4Tes
@Test
public void testNoCoverageMatchFound() throws Exception {
- Parameters inputParameters = buildInputParameters(myPatient, oldCoverage, newCoverage);
+ Parameters inputParameters = buildInputParameters(myPatient, oldCoverage, newCoverage, myConsent);
performOperationExpecting422(ourServerBase + ourQuery, EncodingEnum.JSON, inputParameters,
"Could not find coverage for member");
}
+ @Test
+ public void testConsentUpdatePatientAndPerformer() throws Exception {
+ createCoverageWithBeneficiary(true, true);
+ Parameters inputParameters = buildInputParameters(myPatient, oldCoverage, newCoverage, myConsent);
+ Parameters parametersResponse = performOperation(ourServerBase + ourQuery,
+ EncodingEnum.JSON, inputParameters);
- private Parameters buildInputParameters(Patient thePatient, Coverage theOldCoverage, Coverage theNewCoverage) {
+ Consent respConsent = validateResponseConsent(parametersResponse, myConsent);
+ validateConsentPatientAndPerformerRef(myPatient, respConsent);
+ }
+
+
+ private Parameters buildInputParameters(Patient thePatient, Coverage theOldCoverage, Coverage theNewCoverage, Consent theConsent) {
Parameters p = new Parameters();
ParametersUtil.addParameterToParameters(this.getFhirContext(), p, PARAM_MEMBER_PATIENT, thePatient);
ParametersUtil.addParameterToParameters(this.getFhirContext(), p, PARAM_OLD_COVERAGE, theOldCoverage);
ParametersUtil.addParameterToParameters(this.getFhirContext(), p, PARAM_NEW_COVERAGE, theNewCoverage);
+ ParametersUtil.addParameterToParameters(this.getFhirContext(), p, PARAM_CONSENT, theConsent);
return p;
}
@@ -345,6 +483,19 @@ public class PatientMemberMatchOperationR4Test extends BaseResourceProviderR4Tes
assertFalse(coding.getUserSelected());
}
+ /**
+ * Validates that consent from the response is same as the received consent with additional identifier and extension
+ */
+ private Consent validateResponseConsent(Parameters theResponse, Consent theOriginalConsent) {
+ List consentList = ParametersUtil.getNamedParameters(this.getFhirContext(), theResponse, PARAM_CONSENT);
+ assertEquals(1, consentList.size());
+ Consent respConsent= (Consent) theResponse.getParameter().get(2).getResource();
+ assertEquals(theOriginalConsent.getScope().getCodingFirstRep().getSystem(), respConsent.getScope().getCodingFirstRep().getSystem());
+ assertEquals(theOriginalConsent.getScope().getCodingFirstRep().getCode(), respConsent.getScope().getCodingFirstRep().getCode());
+ assertEquals(myMemberMatcherR4Helper.CONSENT_IDENTIFIER_CODE_SYSTEM, respConsent.getIdentifier().get(0).getSystem());
+ assertNotNull(respConsent.getIdentifier().get(0).getValue());
+ return respConsent;
+ }
}
diff --git a/hapi-fhir-jpaserver-test-r4b/pom.xml b/hapi-fhir-jpaserver-test-r4b/pom.xml
index 3001abce656..1ed22408ee5 100644
--- a/hapi-fhir-jpaserver-test-r4b/pom.xml
+++ b/hapi-fhir-jpaserver-test-r4b/pom.xml
@@ -6,7 +6,7 @@
ca.uhn.hapi.fhir
hapi-deployable-pom
- 6.3.0-PRE1-SNAPSHOT
+ 6.3.0-PRE2-SNAPSHOT
../hapi-deployable-pom/pom.xml
diff --git a/hapi-fhir-jpaserver-test-r5/pom.xml b/hapi-fhir-jpaserver-test-r5/pom.xml
index b7691f2314b..a84c5d01af4 100644
--- a/hapi-fhir-jpaserver-test-r5/pom.xml
+++ b/hapi-fhir-jpaserver-test-r5/pom.xml
@@ -6,7 +6,7 @@
ca.uhn.hapi.fhir
hapi-deployable-pom
- 6.3.0-PRE1-SNAPSHOT
+ 6.3.0-PRE2-SNAPSHOT
../hapi-deployable-pom/pom.xml
diff --git a/hapi-fhir-jpaserver-test-utilities/pom.xml b/hapi-fhir-jpaserver-test-utilities/pom.xml
index b19277e2d3a..9ca5a676fa1 100644
--- a/hapi-fhir-jpaserver-test-utilities/pom.xml
+++ b/hapi-fhir-jpaserver-test-utilities/pom.xml
@@ -6,7 +6,7 @@
ca.uhn.hapi.fhir
hapi-deployable-pom
- 6.3.0-PRE1-SNAPSHOT
+ 6.3.0-PRE2-SNAPSHOT
../hapi-deployable-pom/pom.xml
diff --git a/hapi-fhir-jpaserver-uhnfhirtest/pom.xml b/hapi-fhir-jpaserver-uhnfhirtest/pom.xml
index e94c5fe7be3..41298dfc6f7 100644
--- a/hapi-fhir-jpaserver-uhnfhirtest/pom.xml
+++ b/hapi-fhir-jpaserver-uhnfhirtest/pom.xml
@@ -5,7 +5,7 @@
ca.uhn.hapi.fhir
hapi-fhir
- 6.3.0-PRE1-SNAPSHOT
+ 6.3.0-PRE2-SNAPSHOT
../pom.xml
diff --git a/hapi-fhir-server-mdm/pom.xml b/hapi-fhir-server-mdm/pom.xml
index 475273cbfd2..1d9e1d02ef1 100644
--- a/hapi-fhir-server-mdm/pom.xml
+++ b/hapi-fhir-server-mdm/pom.xml
@@ -7,7 +7,7 @@
ca.uhn.hapi.fhir
hapi-deployable-pom
- 6.3.0-PRE1-SNAPSHOT
+ 6.3.0-PRE2-SNAPSHOT
../hapi-deployable-pom/pom.xml
diff --git a/hapi-fhir-server-openapi/pom.xml b/hapi-fhir-server-openapi/pom.xml
index 0a86cffe6ba..567d2d91d91 100644
--- a/hapi-fhir-server-openapi/pom.xml
+++ b/hapi-fhir-server-openapi/pom.xml
@@ -5,7 +5,7 @@
ca.uhn.hapi.fhir
hapi-deployable-pom
- 6.3.0-PRE1-SNAPSHOT
+ 6.3.0-PRE2-SNAPSHOT
../hapi-deployable-pom/pom.xml
diff --git a/hapi-fhir-server/pom.xml b/hapi-fhir-server/pom.xml
index 939c3215739..11d42001f7f 100644
--- a/hapi-fhir-server/pom.xml
+++ b/hapi-fhir-server/pom.xml
@@ -5,7 +5,7 @@
ca.uhn.hapi.fhir
hapi-deployable-pom
- 6.3.0-PRE1-SNAPSHOT
+ 6.3.0-PRE2-SNAPSHOT
../hapi-deployable-pom/pom.xml
diff --git a/hapi-fhir-spring-boot/hapi-fhir-spring-boot-autoconfigure/pom.xml b/hapi-fhir-spring-boot/hapi-fhir-spring-boot-autoconfigure/pom.xml
index d516cd9aa5c..6b54240e8ec 100644
--- a/hapi-fhir-spring-boot/hapi-fhir-spring-boot-autoconfigure/pom.xml
+++ b/hapi-fhir-spring-boot/hapi-fhir-spring-boot-autoconfigure/pom.xml
@@ -5,7 +5,7 @@
ca.uhn.hapi.fhir
hapi-deployable-pom
- 6.3.0-PRE1-SNAPSHOT
+ 6.3.0-PRE2-SNAPSHOT
../../hapi-deployable-pom/pom.xml
diff --git a/hapi-fhir-spring-boot/hapi-fhir-spring-boot-samples/hapi-fhir-spring-boot-sample-client-apache/pom.xml b/hapi-fhir-spring-boot/hapi-fhir-spring-boot-samples/hapi-fhir-spring-boot-sample-client-apache/pom.xml
index 6dda78886cb..d604e590ee6 100644
--- a/hapi-fhir-spring-boot/hapi-fhir-spring-boot-samples/hapi-fhir-spring-boot-sample-client-apache/pom.xml
+++ b/hapi-fhir-spring-boot/hapi-fhir-spring-boot-samples/hapi-fhir-spring-boot-sample-client-apache/pom.xml
@@ -5,7 +5,7 @@
ca.uhn.hapi.fhir
hapi-fhir-spring-boot-samples
- 6.3.0-PRE1-SNAPSHOT
+ 6.3.0-PRE2-SNAPSHOT
hapi-fhir-spring-boot-sample-client-apache
diff --git a/hapi-fhir-spring-boot/hapi-fhir-spring-boot-samples/hapi-fhir-spring-boot-sample-client-okhttp/pom.xml b/hapi-fhir-spring-boot/hapi-fhir-spring-boot-samples/hapi-fhir-spring-boot-sample-client-okhttp/pom.xml
index d23b43c8885..a2b86796529 100644
--- a/hapi-fhir-spring-boot/hapi-fhir-spring-boot-samples/hapi-fhir-spring-boot-sample-client-okhttp/pom.xml
+++ b/hapi-fhir-spring-boot/hapi-fhir-spring-boot-samples/hapi-fhir-spring-boot-sample-client-okhttp/pom.xml
@@ -5,7 +5,7 @@
ca.uhn.hapi.fhir
hapi-fhir-spring-boot-samples
- 6.3.0-PRE1-SNAPSHOT
+ 6.3.0-PRE2-SNAPSHOT
hapi-fhir-spring-boot-sample-client-okhttp
diff --git a/hapi-fhir-spring-boot/hapi-fhir-spring-boot-samples/hapi-fhir-spring-boot-sample-server-jersey/pom.xml b/hapi-fhir-spring-boot/hapi-fhir-spring-boot-samples/hapi-fhir-spring-boot-sample-server-jersey/pom.xml
index f7df0a7dfed..90a9ac73b68 100644
--- a/hapi-fhir-spring-boot/hapi-fhir-spring-boot-samples/hapi-fhir-spring-boot-sample-server-jersey/pom.xml
+++ b/hapi-fhir-spring-boot/hapi-fhir-spring-boot-samples/hapi-fhir-spring-boot-sample-server-jersey/pom.xml
@@ -5,7 +5,7 @@
ca.uhn.hapi.fhir
hapi-fhir-spring-boot-samples
- 6.3.0-PRE1-SNAPSHOT
+ 6.3.0-PRE2-SNAPSHOT
hapi-fhir-spring-boot-sample-server-jersey
diff --git a/hapi-fhir-spring-boot/hapi-fhir-spring-boot-samples/pom.xml b/hapi-fhir-spring-boot/hapi-fhir-spring-boot-samples/pom.xml
index f850c3d590b..040bd66fd2e 100644
--- a/hapi-fhir-spring-boot/hapi-fhir-spring-boot-samples/pom.xml
+++ b/hapi-fhir-spring-boot/hapi-fhir-spring-boot-samples/pom.xml
@@ -5,7 +5,7 @@
ca.uhn.hapi.fhir
hapi-fhir-spring-boot
- 6.3.0-PRE1-SNAPSHOT
+ 6.3.0-PRE2-SNAPSHOT
hapi-fhir-spring-boot-samples
diff --git a/hapi-fhir-spring-boot/hapi-fhir-spring-boot-starter/pom.xml b/hapi-fhir-spring-boot/hapi-fhir-spring-boot-starter/pom.xml
index 7be7a52667a..f934e564e8c 100644
--- a/hapi-fhir-spring-boot/hapi-fhir-spring-boot-starter/pom.xml
+++ b/hapi-fhir-spring-boot/hapi-fhir-spring-boot-starter/pom.xml
@@ -5,7 +5,7 @@
ca.uhn.hapi.fhir
hapi-deployable-pom
- 6.3.0-PRE1-SNAPSHOT
+ 6.3.0-PRE2-SNAPSHOT
../../hapi-deployable-pom/pom.xml
diff --git a/hapi-fhir-spring-boot/pom.xml b/hapi-fhir-spring-boot/pom.xml
index 57fdb3ef852..d00b63f9e79 100644
--- a/hapi-fhir-spring-boot/pom.xml
+++ b/hapi-fhir-spring-boot/pom.xml
@@ -5,7 +5,7 @@
ca.uhn.hapi.fhir
hapi-fhir
- 6.3.0-PRE1-SNAPSHOT
+ 6.3.0-PRE2-SNAPSHOT
../pom.xml
diff --git a/hapi-fhir-sql-migrate/pom.xml b/hapi-fhir-sql-migrate/pom.xml
index 67b35543832..79a854a1e53 100644
--- a/hapi-fhir-sql-migrate/pom.xml
+++ b/hapi-fhir-sql-migrate/pom.xml
@@ -5,7 +5,7 @@
ca.uhn.hapi.fhir
hapi-deployable-pom
- 6.3.0-PRE1-SNAPSHOT
+ 6.3.0-PRE2-SNAPSHOT
../hapi-deployable-pom/pom.xml
diff --git a/hapi-fhir-storage-batch2-jobs/pom.xml b/hapi-fhir-storage-batch2-jobs/pom.xml
index 8f3e2d962f0..66d907374b1 100644
--- a/hapi-fhir-storage-batch2-jobs/pom.xml
+++ b/hapi-fhir-storage-batch2-jobs/pom.xml
@@ -5,7 +5,7 @@
ca.uhn.hapi.fhir
hapi-deployable-pom
- 6.3.0-PRE1-SNAPSHOT
+ 6.3.0-PRE2-SNAPSHOT
../hapi-deployable-pom/pom.xml
4.0.0
diff --git a/hapi-fhir-storage-batch2/pom.xml b/hapi-fhir-storage-batch2/pom.xml
index e4d7deb6b51..1b6ba40bef2 100644
--- a/hapi-fhir-storage-batch2/pom.xml
+++ b/hapi-fhir-storage-batch2/pom.xml
@@ -6,7 +6,7 @@
ca.uhn.hapi.fhir
hapi-deployable-pom
- 6.3.0-PRE1-SNAPSHOT
+ 6.3.0-PRE2-SNAPSHOT
../hapi-deployable-pom/pom.xml
diff --git a/hapi-fhir-storage-mdm/pom.xml b/hapi-fhir-storage-mdm/pom.xml
index efbbb95c559..0cc54962563 100644
--- a/hapi-fhir-storage-mdm/pom.xml
+++ b/hapi-fhir-storage-mdm/pom.xml
@@ -5,7 +5,7 @@
ca.uhn.hapi.fhir
hapi-deployable-pom
- 6.3.0-PRE1-SNAPSHOT
+ 6.3.0-PRE2-SNAPSHOT
../hapi-deployable-pom/pom.xml
4.0.0
diff --git a/hapi-fhir-storage-test-utilities/pom.xml b/hapi-fhir-storage-test-utilities/pom.xml
index 71d4387cdec..76f9b766ddd 100644
--- a/hapi-fhir-storage-test-utilities/pom.xml
+++ b/hapi-fhir-storage-test-utilities/pom.xml
@@ -5,7 +5,7 @@
ca.uhn.hapi.fhir
hapi-deployable-pom
- 6.3.0-PRE1-SNAPSHOT
+ 6.3.0-PRE2-SNAPSHOT
../hapi-deployable-pom/pom.xml
4.0.0
diff --git a/hapi-fhir-storage/pom.xml b/hapi-fhir-storage/pom.xml
index 73614ba09bb..3002598eb2b 100644
--- a/hapi-fhir-storage/pom.xml
+++ b/hapi-fhir-storage/pom.xml
@@ -5,7 +5,7 @@
ca.uhn.hapi.fhir
hapi-deployable-pom
- 6.3.0-PRE1-SNAPSHOT
+ 6.3.0-PRE2-SNAPSHOT
../hapi-deployable-pom/pom.xml
diff --git a/hapi-fhir-structures-dstu2.1/pom.xml b/hapi-fhir-structures-dstu2.1/pom.xml
index a690cbd863b..7fb29f3b479 100644
--- a/hapi-fhir-structures-dstu2.1/pom.xml
+++ b/hapi-fhir-structures-dstu2.1/pom.xml
@@ -5,7 +5,7 @@
ca.uhn.hapi.fhir
hapi-deployable-pom
- 6.3.0-PRE1-SNAPSHOT
+ 6.3.0-PRE2-SNAPSHOT
../hapi-deployable-pom/pom.xml
diff --git a/hapi-fhir-structures-dstu2/pom.xml b/hapi-fhir-structures-dstu2/pom.xml
index e1f1462884c..1ab9b676a87 100644
--- a/hapi-fhir-structures-dstu2/pom.xml
+++ b/hapi-fhir-structures-dstu2/pom.xml
@@ -4,7 +4,7 @@
ca.uhn.hapi.fhir
hapi-deployable-pom
- 6.3.0-PRE1-SNAPSHOT
+ 6.3.0-PRE2-SNAPSHOT
../hapi-deployable-pom/pom.xml
diff --git a/hapi-fhir-structures-dstu3/pom.xml b/hapi-fhir-structures-dstu3/pom.xml
index cd5a96aa6d5..e870ec9b19a 100644
--- a/hapi-fhir-structures-dstu3/pom.xml
+++ b/hapi-fhir-structures-dstu3/pom.xml
@@ -5,7 +5,7 @@
ca.uhn.hapi.fhir
hapi-deployable-pom
- 6.3.0-PRE1-SNAPSHOT
+ 6.3.0-PRE2-SNAPSHOT
../hapi-deployable-pom/pom.xml
diff --git a/hapi-fhir-structures-hl7org-dstu2/pom.xml b/hapi-fhir-structures-hl7org-dstu2/pom.xml
index c967e7ed072..a0888be5bad 100644
--- a/hapi-fhir-structures-hl7org-dstu2/pom.xml
+++ b/hapi-fhir-structures-hl7org-dstu2/pom.xml
@@ -5,7 +5,7 @@
ca.uhn.hapi.fhir
hapi-deployable-pom
- 6.3.0-PRE1-SNAPSHOT
+ 6.3.0-PRE2-SNAPSHOT
../hapi-deployable-pom/pom.xml
diff --git a/hapi-fhir-structures-r4/pom.xml b/hapi-fhir-structures-r4/pom.xml
index 02566a02587..299b268d308 100644
--- a/hapi-fhir-structures-r4/pom.xml
+++ b/hapi-fhir-structures-r4/pom.xml
@@ -5,7 +5,7 @@
ca.uhn.hapi.fhir
hapi-deployable-pom
- 6.3.0-PRE1-SNAPSHOT
+ 6.3.0-PRE2-SNAPSHOT
../hapi-deployable-pom/pom.xml
diff --git a/hapi-fhir-structures-r4b/pom.xml b/hapi-fhir-structures-r4b/pom.xml
index 09d0469a850..f8e1975157b 100644
--- a/hapi-fhir-structures-r4b/pom.xml
+++ b/hapi-fhir-structures-r4b/pom.xml
@@ -5,7 +5,7 @@
ca.uhn.hapi.fhir
hapi-deployable-pom
- 6.3.0-PRE1-SNAPSHOT
+ 6.3.0-PRE2-SNAPSHOT
../hapi-deployable-pom/pom.xml
diff --git a/hapi-fhir-structures-r5/pom.xml b/hapi-fhir-structures-r5/pom.xml
index 85a9951e805..99903f06a14 100644
--- a/hapi-fhir-structures-r5/pom.xml
+++ b/hapi-fhir-structures-r5/pom.xml
@@ -5,7 +5,7 @@
ca.uhn.hapi.fhir
hapi-deployable-pom
- 6.3.0-PRE1-SNAPSHOT
+ 6.3.0-PRE2-SNAPSHOT
../hapi-deployable-pom/pom.xml
diff --git a/hapi-fhir-test-utilities/pom.xml b/hapi-fhir-test-utilities/pom.xml
index 786a4dbae6c..5df3a925631 100644
--- a/hapi-fhir-test-utilities/pom.xml
+++ b/hapi-fhir-test-utilities/pom.xml
@@ -5,7 +5,7 @@
ca.uhn.hapi.fhir
hapi-deployable-pom
- 6.3.0-PRE1-SNAPSHOT
+ 6.3.0-PRE2-SNAPSHOT
../hapi-deployable-pom/pom.xml
diff --git a/hapi-fhir-testpage-overlay/pom.xml b/hapi-fhir-testpage-overlay/pom.xml
index c2ea5180f34..e4474237130 100644
--- a/hapi-fhir-testpage-overlay/pom.xml
+++ b/hapi-fhir-testpage-overlay/pom.xml
@@ -4,7 +4,7 @@
ca.uhn.hapi.fhir
hapi-fhir
- 6.3.0-PRE1-SNAPSHOT
+ 6.3.0-PRE2-SNAPSHOT
../pom.xml
diff --git a/hapi-fhir-testpage-overlay/src/main/java/ca/uhn/fhir/to/BaseController.java b/hapi-fhir-testpage-overlay/src/main/java/ca/uhn/fhir/to/BaseController.java
index a5e83c74644..6fb3dcb66b2 100644
--- a/hapi-fhir-testpage-overlay/src/main/java/ca/uhn/fhir/to/BaseController.java
+++ b/hapi-fhir-testpage-overlay/src/main/java/ca/uhn/fhir/to/BaseController.java
@@ -1,9 +1,9 @@
package ca.uhn.fhir.to;
-import ca.uhn.fhir.i18n.Msg;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.context.FhirVersionEnum;
import ca.uhn.fhir.context.RuntimeResourceDefinition;
+import ca.uhn.fhir.i18n.Msg;
import ca.uhn.fhir.model.api.IResource;
import ca.uhn.fhir.rest.api.Constants;
import ca.uhn.fhir.rest.api.EncodingEnum;
@@ -35,7 +35,11 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
import static ca.uhn.fhir.util.UrlUtil.sanitizeUrlPart;
import static org.apache.commons.lang3.StringUtils.defaultString;
diff --git a/hapi-fhir-validation-resources-dstu2.1/pom.xml b/hapi-fhir-validation-resources-dstu2.1/pom.xml
index 554b53e3526..c2a1a7eb6eb 100644
--- a/hapi-fhir-validation-resources-dstu2.1/pom.xml
+++ b/hapi-fhir-validation-resources-dstu2.1/pom.xml
@@ -4,7 +4,7 @@
ca.uhn.hapi.fhir
hapi-deployable-pom
- 6.3.0-PRE1-SNAPSHOT
+ 6.3.0-PRE2-SNAPSHOT
../hapi-deployable-pom/pom.xml
diff --git a/hapi-fhir-validation-resources-dstu2/pom.xml b/hapi-fhir-validation-resources-dstu2/pom.xml
index f9e25f07842..1cda9139883 100644
--- a/hapi-fhir-validation-resources-dstu2/pom.xml
+++ b/hapi-fhir-validation-resources-dstu2/pom.xml
@@ -4,7 +4,7 @@
ca.uhn.hapi.fhir
hapi-deployable-pom
- 6.3.0-PRE1-SNAPSHOT
+ 6.3.0-PRE2-SNAPSHOT
../hapi-deployable-pom/pom.xml
diff --git a/hapi-fhir-validation-resources-dstu3/pom.xml b/hapi-fhir-validation-resources-dstu3/pom.xml
index ce79b51c3b0..6570d325bd4 100644
--- a/hapi-fhir-validation-resources-dstu3/pom.xml
+++ b/hapi-fhir-validation-resources-dstu3/pom.xml
@@ -4,7 +4,7 @@
ca.uhn.hapi.fhir
hapi-deployable-pom
- 6.3.0-PRE1-SNAPSHOT
+ 6.3.0-PRE2-SNAPSHOT
../hapi-deployable-pom/pom.xml
diff --git a/hapi-fhir-validation-resources-r4/pom.xml b/hapi-fhir-validation-resources-r4/pom.xml
index dc790e26971..ddf5804120e 100644
--- a/hapi-fhir-validation-resources-r4/pom.xml
+++ b/hapi-fhir-validation-resources-r4/pom.xml
@@ -4,7 +4,7 @@
ca.uhn.hapi.fhir
hapi-deployable-pom
- 6.3.0-PRE1-SNAPSHOT
+ 6.3.0-PRE2-SNAPSHOT
../hapi-deployable-pom/pom.xml
diff --git a/hapi-fhir-validation-resources-r5/pom.xml b/hapi-fhir-validation-resources-r5/pom.xml
index efae68d09c6..5abcf27bd4a 100644
--- a/hapi-fhir-validation-resources-r5/pom.xml
+++ b/hapi-fhir-validation-resources-r5/pom.xml
@@ -4,7 +4,7 @@
ca.uhn.hapi.fhir
hapi-deployable-pom
- 6.3.0-PRE1-SNAPSHOT
+ 6.3.0-PRE2-SNAPSHOT
../hapi-deployable-pom/pom.xml
diff --git a/hapi-fhir-validation/pom.xml b/hapi-fhir-validation/pom.xml
index 0bec314353c..e6bf11151fc 100644
--- a/hapi-fhir-validation/pom.xml
+++ b/hapi-fhir-validation/pom.xml
@@ -5,7 +5,7 @@
ca.uhn.hapi.fhir
hapi-deployable-pom
- 6.3.0-PRE1-SNAPSHOT
+ 6.3.0-PRE2-SNAPSHOT
../hapi-deployable-pom/pom.xml
diff --git a/hapi-tinder-plugin/pom.xml b/hapi-tinder-plugin/pom.xml
index df1ca4fc9b2..0d041806e5c 100644
--- a/hapi-tinder-plugin/pom.xml
+++ b/hapi-tinder-plugin/pom.xml
@@ -5,7 +5,7 @@
ca.uhn.hapi.fhir
hapi-fhir
- 6.3.0-PRE1-SNAPSHOT
+ 6.3.0-PRE2-SNAPSHOT
../pom.xml
@@ -65,42 +65,42 @@
ca.uhn.hapi.fhir
hapi-fhir-structures-dstu3
- 6.3.0-PRE1-SNAPSHOT
+ 6.3.0-PRE2-SNAPSHOT
ca.uhn.hapi.fhir
hapi-fhir-structures-hl7org-dstu2
- 6.3.0-PRE1-SNAPSHOT
+ 6.3.0-PRE2-SNAPSHOT
ca.uhn.hapi.fhir
hapi-fhir-structures-r4
- 6.3.0-PRE1-SNAPSHOT
+ 6.3.0-PRE2-SNAPSHOT
ca.uhn.hapi.fhir
hapi-fhir-structures-r4b
- 6.3.0-PRE1-SNAPSHOT
+ 6.3.0-PRE2-SNAPSHOT
ca.uhn.hapi.fhir
hapi-fhir-structures-r5
- 6.3.0-PRE1-SNAPSHOT
+ 6.3.0-PRE2-SNAPSHOT
ca.uhn.hapi.fhir
hapi-fhir-validation-resources-dstu2
- 6.3.0-PRE1-SNAPSHOT
+ 6.3.0-PRE2-SNAPSHOT
ca.uhn.hapi.fhir
hapi-fhir-validation-resources-dstu3
- 6.3.0-PRE1-SNAPSHOT
+ 6.3.0-PRE2-SNAPSHOT
ca.uhn.hapi.fhir
hapi-fhir-validation-resources-r4
- 6.3.0-PRE1-SNAPSHOT
+ 6.3.0-PRE2-SNAPSHOT
ca.uhn.hapi.fhir
diff --git a/hapi-tinder-test/pom.xml b/hapi-tinder-test/pom.xml
index 0268f0a7b46..3700638251c 100644
--- a/hapi-tinder-test/pom.xml
+++ b/hapi-tinder-test/pom.xml
@@ -4,7 +4,7 @@
ca.uhn.hapi.fhir
hapi-fhir
- 6.3.0-PRE1-SNAPSHOT
+ 6.3.0-PRE2-SNAPSHOT
../pom.xml
diff --git a/pom.xml b/pom.xml
index 912bb270c95..be98dd3f52a 100644
--- a/pom.xml
+++ b/pom.xml
@@ -6,7 +6,7 @@
ca.uhn.hapi.fhir
hapi-fhir
pom
- 6.3.0-PRE1-SNAPSHOT
+ 6.3.0-PRE2-SNAPSHOT
HAPI-FHIR
An open-source implementation of the FHIR specification in Java.
https://hapifhir.io
@@ -1998,7 +1998,7 @@
ca.uhn.hapi.fhir
hapi-fhir-checkstyle
- 6.3.0-PRE1-SNAPSHOT
+ 6.3.0-PRE2-SNAPSHOT
diff --git a/tests/hapi-fhir-base-test-jaxrsserver-kotlin/pom.xml b/tests/hapi-fhir-base-test-jaxrsserver-kotlin/pom.xml
index 0678f314119..b247541c7a6 100644
--- a/tests/hapi-fhir-base-test-jaxrsserver-kotlin/pom.xml
+++ b/tests/hapi-fhir-base-test-jaxrsserver-kotlin/pom.xml
@@ -6,7 +6,7 @@
ca.uhn.hapi.fhir
hapi-fhir
- 6.3.0-PRE1-SNAPSHOT
+ 6.3.0-PRE2-SNAPSHOT
../../pom.xml
diff --git a/tests/hapi-fhir-base-test-mindeps-client/pom.xml b/tests/hapi-fhir-base-test-mindeps-client/pom.xml
index 302e863962c..2277e49cecc 100644
--- a/tests/hapi-fhir-base-test-mindeps-client/pom.xml
+++ b/tests/hapi-fhir-base-test-mindeps-client/pom.xml
@@ -4,7 +4,7 @@
ca.uhn.hapi.fhir
hapi-fhir
- 6.3.0-PRE1-SNAPSHOT
+ 6.3.0-PRE2-SNAPSHOT
../../pom.xml
diff --git a/tests/hapi-fhir-base-test-mindeps-server/pom.xml b/tests/hapi-fhir-base-test-mindeps-server/pom.xml
index 3434b73cd9b..5f60aff00de 100644
--- a/tests/hapi-fhir-base-test-mindeps-server/pom.xml
+++ b/tests/hapi-fhir-base-test-mindeps-server/pom.xml
@@ -5,7 +5,7 @@
ca.uhn.hapi.fhir
hapi-fhir
- 6.3.0-PRE1-SNAPSHOT
+ 6.3.0-PRE2-SNAPSHOT
../../pom.xml