1
0
mirror of https://github.com/pcvolkmer/mv64e-etl-processor synced 2025-09-13 09:02:50 +00:00

fix: Setze in der Broad Consent Resource das MII Broad Consent Profil und die Consent Policy, falls diese fehlen sollten. Die von gICS einzeln gelieferte Consent Provisions werden in einer Ressource zusammengefasst.

This commit is contained in:
Jakub Lidke
2025-09-05 14:55:58 +02:00
parent 3d9d84438d
commit db89d84353

View File

@@ -39,12 +39,15 @@ public class GicsConsentService implements IConsentService {
private final RestTemplate restTemplate; private final RestTemplate restTemplate;
private final FhirContext fhirContext; private final FhirContext fhirContext;
private final GIcsConfigProperties gIcsConfigProperties; private final GIcsConfigProperties gIcsConfigProperties;
private final String BROAD_CONSENT_PROFILE_URI = "https://www.medizininformatik-initiative.de/fhir/modul-consent/StructureDefinition/mii-pr-consent-einwilligung";
;
private final String BROAD_CONSENT_POLICY = "urn:oid:2.16.840.1.113883.3.1937.777.24.2.1791";
public GicsConsentService( public GicsConsentService(
GIcsConfigProperties gIcsConfigProperties, GIcsConfigProperties gIcsConfigProperties,
RetryTemplate retryTemplate, RetryTemplate retryTemplate,
RestTemplate restTemplate, RestTemplate restTemplate,
AppFhirConfig appFhirConfig AppFhirConfig appFhirConfig
) { ) {
this.retryTemplate = retryTemplate; this.retryTemplate = retryTemplate;
this.restTemplate = restTemplate; this.restTemplate = restTemplate;
@@ -54,34 +57,34 @@ public class GicsConsentService implements IConsentService {
} }
protected Parameters getFhirRequestParameters( protected Parameters getFhirRequestParameters(
String personIdentifierValue String personIdentifierValue
) { ) {
var result = new Parameters(); var result = new Parameters();
result.addParameter( result.addParameter(
new ParametersParameterComponent() new ParametersParameterComponent()
.setName("personIdentifier") .setName("personIdentifier")
.setValue( .setValue(
new Identifier() new Identifier()
.setValue(personIdentifierValue) .setValue(personIdentifierValue)
.setSystem(this.gIcsConfigProperties.getPersonIdentifierSystem()) .setSystem(this.gIcsConfigProperties.getPersonIdentifierSystem())
) )
); );
result.addParameter( result.addParameter(
new ParametersParameterComponent() new ParametersParameterComponent()
.setName("domain") .setName("domain")
.setValue( .setValue(
new StringType() new StringType()
.setValue(this.gIcsConfigProperties.getBroadConsentDomainName()) .setValue(this.gIcsConfigProperties.getBroadConsentDomainName())
) )
); );
result.addParameter( result.addParameter(
new ParametersParameterComponent() new ParametersParameterComponent()
.setName("policy") .setName("policy")
.setValue( .setValue(
new Coding() new Coding()
.setCode(this.gIcsConfigProperties.getBroadConsentPolicyCode()) .setCode(this.gIcsConfigProperties.getBroadConsentPolicyCode())
.setSystem(this.gIcsConfigProperties.getBroadConsentPolicySystem()) .setSystem(this.gIcsConfigProperties.getBroadConsentPolicySystem())
) )
); );
/* /*
@@ -89,10 +92,10 @@ public class GicsConsentService implements IConsentService {
* 'ignoreVersionNumber'. * 'ignoreVersionNumber'.
*/ */
result.addParameter( result.addParameter(
new ParametersParameterComponent() new ParametersParameterComponent()
.setName("version") .setName("version")
.setValue(new StringType().setValue("1.1") .setValue(new StringType().setValue("1.1")
) )
); );
/* add config parameter with: /* add config parameter with:
@@ -101,17 +104,17 @@ public class GicsConsentService implements IConsentService {
* unknownStateIsConsideredAsDecline -> true * unknownStateIsConsideredAsDecline -> true
*/ */
var config = new ParametersParameterComponent() var config = new ParametersParameterComponent()
.setName("config") .setName("config")
.addPart( .addPart(
new ParametersParameterComponent() new ParametersParameterComponent()
.setName("ignoreVersionNumber") .setName("ignoreVersionNumber")
.setValue(new BooleanType().setValue(true)) .setValue(new BooleanType().setValue(true))
) )
.addPart( .addPart(
new ParametersParameterComponent() new ParametersParameterComponent()
.setName("unknownStateIsConsideredAsDecline") .setName("unknownStateIsConsideredAsDecline")
.setValue(new BooleanType().setValue(false)) .setValue(new BooleanType().setValue(false))
); );
result.addParameter(config); result.addParameter(config);
@@ -130,8 +133,8 @@ public class GicsConsentService implements IConsentService {
headers.setContentType(MediaType.APPLICATION_XML); headers.setContentType(MediaType.APPLICATION_XML);
if ( if (
StringUtils.isBlank(this.gIcsConfigProperties.getUsername()) StringUtils.isBlank(this.gIcsConfigProperties.getUsername())
|| StringUtils.isBlank(this.gIcsConfigProperties.getPassword()) || StringUtils.isBlank(this.gIcsConfigProperties.getPassword())
) { ) {
return headers; return headers;
} }
@@ -145,28 +148,28 @@ public class GicsConsentService implements IConsentService {
HttpEntity<String> requestEntity = new HttpEntity<>(parameterAsXml, this.headersWithHttpBasicAuth()); HttpEntity<String> requestEntity = new HttpEntity<>(parameterAsXml, this.headersWithHttpBasicAuth());
try { try {
var responseEntity = retryTemplate.execute( var responseEntity = retryTemplate.execute(
ctx -> restTemplate.exchange(endpointUri(endpoint), HttpMethod.POST, requestEntity, String.class) ctx -> restTemplate.exchange(endpointUri(endpoint), HttpMethod.POST, requestEntity, String.class)
); );
if (responseEntity.getStatusCode().is2xxSuccessful()) { if (responseEntity.getStatusCode().is2xxSuccessful()) {
return responseEntity.getBody(); return responseEntity.getBody();
} else { } else {
var msg = String.format( var msg = String.format(
"Trusted party system reached but request failed! code: '%s' response: '%s'", "Trusted party system reached but request failed! code: '%s' response: '%s'",
responseEntity.getStatusCode(), responseEntity.getBody()); responseEntity.getStatusCode(), responseEntity.getBody());
log.error(msg); log.error(msg);
return null; return null;
} }
} catch (RestClientException e) { } catch (RestClientException e) {
var msg = String.format("Get consents status request failed reason: '%s", var msg = String.format("Get consents status request failed reason: '%s",
e.getMessage()); e.getMessage());
log.error(msg); log.error(msg);
return null; return null;
} catch (TerminatedRetryException terminatedRetryException) { } catch (TerminatedRetryException terminatedRetryException) {
var msg = String.format( var msg = String.format(
"Get consents status process has been terminated. termination reason: '%s", "Get consents status process has been terminated. termination reason: '%s",
terminatedRetryException.getMessage()); terminatedRetryException.getMessage());
log.error(msg); log.error(msg);
return null; return null;
} }
@@ -175,45 +178,45 @@ public class GicsConsentService implements IConsentService {
@Override @Override
public TtpConsentStatus getTtpBroadConsentStatus(String personIdentifierValue) { public TtpConsentStatus getTtpBroadConsentStatus(String personIdentifierValue) {
var consentStatusResponse = callGicsApi( var consentStatusResponse = callGicsApi(
getFhirRequestParameters(personIdentifierValue), getFhirRequestParameters(personIdentifierValue),
GicsConsentService.IS_CONSENTED_ENDPOINT GicsConsentService.IS_CONSENTED_ENDPOINT
); );
return evaluateConsentResponse(consentStatusResponse); return evaluateConsentResponse(consentStatusResponse);
} }
protected Bundle currentConsentForPersonAndTemplate( protected Bundle currentConsentForPersonAndTemplate(
String personIdentifierValue, String personIdentifierValue,
ConsentDomain consentDomain, ConsentDomain consentDomain,
Date requestDate Date requestDate
) { ) {
var requestParameter = buildRequestParameterCurrentPolicyStatesForPerson( var requestParameter = buildRequestParameterCurrentPolicyStatesForPerson(
personIdentifierValue, personIdentifierValue,
requestDate, requestDate,
consentDomain consentDomain
); );
var consentDataSerialized = callGicsApi(requestParameter, var consentDataSerialized = callGicsApi(requestParameter,
GicsConsentService.IS_POLICY_STATES_FOR_PERSON_ENDPOINT); GicsConsentService.IS_POLICY_STATES_FOR_PERSON_ENDPOINT);
if (consentDataSerialized == null) { if (consentDataSerialized == null) {
// error occurred - should not process further! // error occurred - should not process further!
throw new IllegalStateException( throw new IllegalStateException(
"consent data request failed - stopping processing! - try again or fix other problems first."); "consent data request failed - stopping processing! - try again or fix other problems first.");
} }
var iBaseResource = fhirContext.newJsonParser() var iBaseResource = fhirContext.newJsonParser()
.parseResource(consentDataSerialized); .parseResource(consentDataSerialized);
if (iBaseResource instanceof OperationOutcome) { if (iBaseResource instanceof OperationOutcome) {
// log error - very likely a configuration error // log error - very likely a configuration error
String errorMessage = String errorMessage =
"Consent request failed! Check outcome:\n " + consentDataSerialized; "Consent request failed! Check outcome:\n " + consentDataSerialized;
log.error(errorMessage); log.error(errorMessage);
throw new IllegalStateException(errorMessage); throw new IllegalStateException(errorMessage);
} else if (iBaseResource instanceof Bundle bundle) { } else if (iBaseResource instanceof Bundle bundle) {
return bundle; return bundle;
} else { } else {
String errorMessage = "Consent request failed! Unexpected response received! -> " String errorMessage = "Consent request failed! Unexpected response received! -> "
+ consentDataSerialized; + consentDataSerialized;
log.error(errorMessage); log.error(errorMessage);
throw new IllegalStateException(errorMessage); throw new IllegalStateException(errorMessage);
} }
@@ -228,43 +231,43 @@ public class GicsConsentService implements IConsentService {
} }
protected Parameters buildRequestParameterCurrentPolicyStatesForPerson( protected Parameters buildRequestParameterCurrentPolicyStatesForPerson(
String personIdentifierValue, String personIdentifierValue,
Date requestDate, Date requestDate,
ConsentDomain consentDomain ConsentDomain consentDomain
) { ) {
var requestParameter = new Parameters(); var requestParameter = new Parameters();
requestParameter.addParameter( requestParameter.addParameter(
new ParametersParameterComponent() new ParametersParameterComponent()
.setName("personIdentifier") .setName("personIdentifier")
.setValue( .setValue(
new Identifier() new Identifier()
.setValue(personIdentifierValue) .setValue(personIdentifierValue)
.setSystem(this.gIcsConfigProperties.getPersonIdentifierSystem()) .setSystem(this.gIcsConfigProperties.getPersonIdentifierSystem())
) )
); );
requestParameter.addParameter( requestParameter.addParameter(
new ParametersParameterComponent() new ParametersParameterComponent()
.setName("domain") .setName("domain")
.setValue(new StringType().setValue(getConsentDomainName(consentDomain))) .setValue(new StringType().setValue(getConsentDomainName(consentDomain)))
); );
Parameters nestedConfigParameters = new Parameters(); Parameters nestedConfigParameters = new Parameters();
nestedConfigParameters nestedConfigParameters
.addParameter( .addParameter(
new ParametersParameterComponent() new ParametersParameterComponent()
.setName("idMatchingType") .setName("idMatchingType")
.setValue(new Coding() .setValue(new Coding()
.setSystem("https://ths-greifswald.de/fhir/CodeSystem/gics/IdMatchingType") .setSystem("https://ths-greifswald.de/fhir/CodeSystem/gics/IdMatchingType")
.setCode("AT_LEAST_ONE") .setCode("AT_LEAST_ONE")
) )
) )
.addParameter("ignoreVersionNumber", false) .addParameter("ignoreVersionNumber", false)
.addParameter("unknownStateIsConsideredAsDecline", false) .addParameter("unknownStateIsConsideredAsDecline", false)
.addParameter("requestDate", new DateType().setValue(requestDate)); .addParameter("requestDate", new DateType().setValue(requestDate));
requestParameter.addParameter( requestParameter.addParameter(
new ParametersParameterComponent().setName("config").addPart().setResource(nestedConfigParameters) new ParametersParameterComponent().setName("config").addPart().setResource(nestedConfigParameters)
); );
return requestParameter; return requestParameter;
@@ -291,7 +294,7 @@ public class GicsConsentService implements IConsentService {
} }
} else if (response instanceof OperationOutcome outcome) { } else if (response instanceof OperationOutcome outcome) {
log.error("failed to get consent status from ttp. probably configuration error. " log.error("failed to get consent status from ttp. probably configuration error. "
+ "outcome: '{}'", fhirContext.newJsonParser().encodeToString(outcome)); + "outcome: '{}'", fhirContext.newJsonParser().encodeToString(outcome));
} }
} catch (DataFormatException dfe) { } catch (DataFormatException dfe) {
@@ -302,6 +305,34 @@ public class GicsConsentService implements IConsentService {
@Override @Override
public Bundle getConsent(String patientId, Date requestDate, ConsentDomain consentDomain) { public Bundle getConsent(String patientId, Date requestDate, ConsentDomain consentDomain) {
return currentConsentForPersonAndTemplate(patientId, consentDomain, requestDate); Bundle gIcsResultBundle = currentConsentForPersonAndTemplate(patientId, consentDomain, requestDate);
if (ConsentDomain.BROAD_CONSENT == consentDomain) {
return convertGicsResultToMiiBroadConsent(gIcsResultBundle);
}
return gIcsResultBundle;
}
protected Bundle convertGicsResultToMiiBroadConsent(Bundle gIcsResultBundle) {
if (gIcsResultBundle == null
|| gIcsResultBundle.getEntry().isEmpty()
|| !(gIcsResultBundle.getEntry().getFirst().getResource() instanceof Consent))
return gIcsResultBundle;
Bundle.BundleEntryComponent bundleEntryComponent = gIcsResultBundle.getEntry().getFirst();
var consentAsOne = (Consent) bundleEntryComponent.getResource();
if (consentAsOne.getPolicy().stream().noneMatch(p -> p.getUri().equals(BROAD_CONSENT_POLICY))) {
consentAsOne.addPolicy(new Consent.ConsentPolicyComponent().setUri(BROAD_CONSENT_POLICY));
}
if (consentAsOne.getMeta().getProfile().stream().noneMatch(p -> p.getValue().equals(BROAD_CONSENT_PROFILE_URI))) {
consentAsOne.getMeta().addProfile(BROAD_CONSENT_PROFILE_URI);
}
gIcsResultBundle.getEntry().stream().skip(1).forEach(c -> consentAsOne.getProvision().addProvision(((Consent) c.getResource()).getProvision().getProvisionFirstRep()));
gIcsResultBundle.getEntry().clear();
gIcsResultBundle.addEntry(bundleEntryComponent);
return gIcsResultBundle;
} }
} }