Skip to content

Commit

Permalink
Release 2.6.0
Browse files Browse the repository at this point in the history
  • Loading branch information
Gematik-Entwicklung committed Sep 20, 2024
1 parent 69d361f commit ac258f3
Show file tree
Hide file tree
Showing 203 changed files with 31,891 additions and 261 deletions.
53 changes: 49 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,12 @@
<li>
<a href="#funktionsumfang">Funktionsumfang</a>
<ul>
<li><a href="#unterstützte-validierungsmodule">Unterstützte Validierungsmodule</a></li>
<li><a href="#e-rezept-modul">E-Rezept-Modul</a></li>
<li><a href="#eau-modul">EAU-Modul</a></li>
<li><a href="#core-modul">Code-Modul</a></li>
<li><a href="#e-rezept-abrechnungsdaten-modul-experimentell">E-Rezept Abrechnungsdaten-Modul (EXPERIMENTELL)</a></li>
<li><a href="#externe-validierungsmodule-plugins">Externe Validierungsmodule (Plugins)</a></li>
</ul>
</li>
<li>
Expand All @@ -29,6 +34,7 @@
</li>
<li><a href="#verwendung">Verwendung</a></li>
<li><a href="#lizenz">Lizenz</a></li>
<li><a href="#beiträge-zum-projekt-und-danksagung">Beiträge zum Projekt und Danksagung</a></li>
<li><a href="#kontakt">Kontakt</a></li>
</ol>
</details>
Expand Down Expand Up @@ -66,17 +72,26 @@ Siehe [Release Notes](ReleaseNotes.md)

| **Modul** | **Version** |
|------------------------------------------------|-------------|
| E-Rezept | 2.4 |
| Elektronische Arbeitsunfähigkeitsbescheinigung | 0.9 |
| E-Rezept | 2.5 |
| Elektronische Arbeitsunfähigkeitsbescheinigung | 0.91 |
| FHIR Core | 1.0 |
| E-Rezept Abrechnungsdaten (experimentell) | 0.2 |
| E-Rezept Abrechnungsdaten (experimentell) | 0.3 |



### E-Rezept-Modul

Abweichend vom allgemeinen Prüfumfang verhält sich das E-Rezept-Modul wie folgt:
- Codes aus den CodeSystemen `http://fhir.de/CodeSystem/ifa/pzn` und `http://fhir.de/CodeSystem/ask` werden nicht validiert
- Folgende CodeSysteme werden nicht validiert:
- `http://fhir.de/CodeSystem/ifa/pzn`
- `http://fhir.de/CodeSystem/ask`
- `http://fhir.de/CodeSystem/bfarm/atc` (wird in _GEM_ERP_PR_Medication_ verwendet)
- `http://snomed.info/sct` (wird in _GEM_ERP_PR_Medication_ verwendet)
- `https://terminologieserver.bfarm.de/fhir/CodeSystem/arzneimittel-referenzdaten-pharmazeutisches-produkt` (wird in _GEM_ERP_PR_Medication_ verwendet)
- Folgende CodeSysteme werden validiert, führt aber zu einer Warnung im Falle der Nicht-Validität:
- `http://unitsofmeasure.org`
- Folgende ValueSets werden nicht validiert:
- `http://hl7.org/fhir/uv/ips/ValueSet/medicine-doseform` (wird in _GEM_ERP_PR_Medication_ verwendet)
- Fehler, die bei Validierung von `http://fhir.abda.de/eRezeptAbgabedaten/StructureDefinition/DAV-PR-ERP-AbgabedatenBundle|1.0.3` im Zusammenhang mit falschen Angaben bei `http://fhir.abda.de/Identifier/DAV-Herstellerschluessel` stehen, werden ignoriert und führen zum **validen** Ergebnis
- Instanzen mit unbekannten Profilen führen zum invaliden Ergebnis
- Instanzen mit unbekannten Extensions führen zum invaliden Ergebnis
Expand Down Expand Up @@ -104,6 +119,36 @@ Abweichend vom allgemeinen Prüfumfang verhält sich das eAU-Modul wie folgt:
- Instanzen mit unbekannten Profilen führen zum invaliden Ergebnis
- Instanzen mit unbekannten Extensions führen zum invaliden Ergebnis

Für folgende Profile erfolgen Instanz-datumsbasierte Auswahl der FHIR-Packages zur Validierung sowie Profilgültigkeitsprüfungen:

<table id="creation-date-elements">
<tr>
<th>Profil</th>
<th>Datenelement</th>
<th>Anmerkung</th>
</tr>
<tr>
<td>KBV_PR_EAU_Bundle</td>
<td>Bundle.entry.resource.where(meta.profile.contains('KBV_PR_EAU_Composition')).date</td>
<td>Ausstellungsdatum</td>
</tr>
<tr>
<td>KBV_PR_EAU_Composition</td>
<td>date</td>
<td>Ausstellungsdatum</td>
</tr>
<tr>
<td>KBV_PR_EAU_Storno_Bundle</td>
<td>Bundle.entry.resource.where(meta.profile.contains('KBV_PR_EAU_Composition')).date</td>
<td>Aktuelles Datum der Stornierung</td>
</tr>
<tr>
<td>KBV_PR_EAU_Storno_Composition</td>
<td>date</td>
<td>Aktuelles Datum der Stornierung</td>
</tr>
</table>

#### Anpassungen der Packages:
- Alle Packages enthalten Snapshots

Expand Down
29 changes: 29 additions & 0 deletions ReleaseNotes.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,35 @@

# Release Notes Gematik Referenzvalidator

## Release 2.6.0

### ERP module (version update to 2.5):

#### added
- integrated [de.gematik.erezept-patientenrechnung.r4 1.0.4](https://simplifier.net/packages/de.gematik.erezept-patientenrechnung.r4/1.0.4/~introduction) package (valid from 15.1.2025)
- integrated [de.gematik.erezept-workflow.r4 1.4.3](https://simplifier.net/packages/de.gematik.erezept-workflow.r4/1.4.3) package (valid from 15.1.2025). See current limitations in [E-Rezept-Modul section of README.md](README.md#e-rezept-modul)

#### changed
- validity period of [de.abda.erezeptabgabedatenpkv.1.2.0](https://simplifier.net/packages/de.abda.erezeptabgabedatenpkv/1.2.0) package extended till 30.6.2025 (cf. [Technische Anlage](https://www.abda.de/fileadmin/user_upload/assets/ehealth/PKV_Datenauschtausch/TA_DAV_PKV_004_20240801.pdf))

### EAU module (version update to 0.91):

#### added
- integrated [KBV Schlüsseltabelle S_KBV_DMP v1.06](https://applications.kbv.de/S_KBV_DMP_V1.06.xhtml) (valid from 1.10.2024)
- integrated [KBV Schlüsseltabelle S_KBV_PERSONENGRUPPE v1.03](https://applications.kbv.de/S_KBV_PERSONENGRUPPE_V1.03.xhtml) (valid from 1.4.2024)

#### changed
- EAU module performs selection of FHIR-packages based on the instance creation date (cf. [README.md](README.md#eau-modul))
- EAU module performs profile validity checks based on the instance creation date

#### fixed
- End of validity period for the _KBV_PR_EAU_Bundle|1.0.2_ profile (31.12.2023) (cf. [Technische_Anlage_eAU](https://update.kbv.de/ita-update/DigitaleMuster/eAU/KBV_ITA_VGEX_Technische_Anlage_eAU.pdf))

### Experimental ERPTA7 module (version update to 0.3):

#### added
- support for _GKVSV_PR_TA7_Rechnung_Bundle|1.4_ profile added (valid from 1.11.2024)

## Release 2.5.1

### fixed
Expand Down
2 changes: 1 addition & 1 deletion cli/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<parent>
<artifactId>referencevalidator</artifactId>
<groupId>de.gematik.refv</groupId>
<version>2.5.1</version>
<version>2.6.0</version>
</parent>
<properties>
<integrationtest.folder>${basedir}/target/test-classes/pluginloader-integration-test</integrationtest.folder>
Expand Down
6 changes: 3 additions & 3 deletions cli/src/test/resources/eau-test.xml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
<value value="urn:uuid:08b97c0c-6b65-4f33-a985-66ffd6fb2322" />
</identifier>
<type value="document" />
<timestamp value="2022-09-29T12:30:02Z" />
<timestamp value="2023-07-15T12:30:02Z" />
<entry>
<fullUrl value="http://pvs.praxis-topp-gluecklich.local/fhir/Composition/edb656ba-671c-40d7-9161-b8f8c2365297" />
<resource>
Expand Down Expand Up @@ -38,7 +38,7 @@
<subject>
<reference value="Patient/9774f67f-a238-4daf-b4e6-679deeef3811" />
</subject>
<date value="2022-09-29" />
<date value="2023-07-15" />
<author>
<reference value="Practitioner/20597e0e-cb2a-45b3-95f0-dc3dbdb617c3" />
<type value="Practitioner" />
Expand Down Expand Up @@ -327,7 +327,7 @@
<reference value="Patient/9774f67f-a238-4daf-b4e6-679deeef3811" />
</subject>
<onsetPeriod>
<end value="2022-10-15" />
<end value="2023-07-17" />
</onsetPeriod>
<asserter>
<reference value="Practitioner/20597e0e-cb2a-45b3-95f0-dc3dbdb617c3" />
Expand Down
2 changes: 1 addition & 1 deletion commons/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<parent>
<artifactId>referencevalidator</artifactId>
<groupId>de.gematik.refv</groupId>
<version>2.5.1</version>
<version>2.6.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;

import java.util.Collection;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.regex.Pattern;
Expand Down Expand Up @@ -135,14 +136,14 @@ private ValidationResult validateResource(String resourceBody, ValidationModuleR

// Assumption: each profile has at least one dependency list configured
if (StringUtils.isEmpty(creationDateLocator)) {
return validateWithoutConfiguredLocator(resourceBody, resourceProvider, profileForValidation, dependencyLists, allReferencedProfilesInResource);
return validateWithoutConfiguredLocator(resourceBody, resourceProvider, profileForValidation, dependencyLists, allReferencedProfilesInResource, configuration.getIgnoredValueSets());
}
else {
return validateUsingConfiguredLocator(resourceBody, resourceProvider, validationOptions, creationDateLocator, dependencyLists, profileForValidation, allReferencedProfilesInResource);
return validateUsingConfiguredLocator(resourceBody, resourceProvider, validationOptions, creationDateLocator, dependencyLists, profileForValidation, allReferencedProfilesInResource, configuration.getIgnoredValueSets());
}
}

private ValidationResult validateUsingConfiguredLocator(String resourceBody, ValidationModuleResourceProvider resourceProvider, ValidationOptions validationOptions, String creationDateLocator, DependencyListsWrapper dependencyLists, Profile profileForValidation, List<String> allReferencedProfilesInResource) {
private ValidationResult validateUsingConfiguredLocator(String resourceBody, ValidationModuleResourceProvider resourceProvider, ValidationOptions validationOptions, String creationDateLocator, DependencyListsWrapper dependencyLists, Profile profileForValidation, List<String> allReferencedProfilesInResource, Collection<String> ignoredValueSets) {
try {
var resourceCreationDateOptional = new ResourceCreationDateLocator(fhirContext).findCreationDateIn(resourceBody, creationDateLocator);

Expand All @@ -157,7 +158,7 @@ private ValidationResult validateUsingConfiguredLocator(String resourceBody, Val
var dependencyListOptional = dependencyLists.getDependencyListValidAt(resourceCreationDateOptional.get());
if (dependencyListOptional.isPresent())
// Use Case 2.2.1 Dependency list for the resource creation date is present
return validateUsingDependencyList(resourceBody, resourceProvider, dependencyListOptional.get(), profileForValidation, allReferencedProfilesInResource);
return validateUsingDependencyList(resourceBody, resourceProvider, dependencyListOptional.get(), profileForValidation, allReferencedProfilesInResource, ignoredValueSets);

// Use Case 2.2.2 No Dependency list is found for the creation date
if (isValidateProfileValidityPeriod(validationOptions)) {
Expand All @@ -167,7 +168,7 @@ private ValidationResult validateUsingConfiguredLocator(String resourceBody, Val
}

// Use Case 2.2.2.2 ValidityPeriodChek is turned off -> use latest dependencies
var result = validateUsingDependencyList(resourceBody, resourceProvider, dependencyLists.getLatestDependencyList(), profileForValidation, allReferencedProfilesInResource);
var result = validateUsingDependencyList(resourceBody, resourceProvider, dependencyLists.getLatestDependencyList(), profileForValidation, allReferencedProfilesInResource, ignoredValueSets);
addWarningAboutDeactivatedValidityPeriodCheckTo(result);
return result;

Expand All @@ -177,11 +178,11 @@ private ValidationResult validateUsingConfiguredLocator(String resourceBody, Val
}
}

private ValidationResult validateWithoutConfiguredLocator(String resourceBody, ValidationModuleResourceProvider resourceProvider, Profile profileForValidation, DependencyListsWrapper dependencyLists, List<String> allReferencedProfilesInResource) {
private ValidationResult validateWithoutConfiguredLocator(String resourceBody, ValidationModuleResourceProvider resourceProvider, Profile profileForValidation, DependencyListsWrapper dependencyLists, List<String> allReferencedProfilesInResource, Collection<String> ignoredValueSets) {
ValidationResult result;
log.debug("No creation date locator expression is configured for the profile {}. Using the latest package dependencies available...", profileForValidation);
var dependencyList = dependencyLists.getLatestDependencyList();
result = validateUsingDependencyList(resourceBody, resourceProvider, dependencyList, profileForValidation, allReferencedProfilesInResource);
result = validateUsingDependencyList(resourceBody, resourceProvider, dependencyList, profileForValidation, allReferencedProfilesInResource, ignoredValueSets);
return result;
}

Expand Down Expand Up @@ -216,7 +217,7 @@ private void addWarningAboutDeactivatedValidityPeriodCheckTo(ValidationResult re
result.getValidationMessages().add(m);
}

private ValidationResult validateUsingDependencyList(String resourceBody, ValidationModuleResourceProvider resourceProvider, DependencyList dependencyList, Profile profileForValidation, List<String> allReferencedProfilesInResource) {
private ValidationResult validateUsingDependencyList(String resourceBody, ValidationModuleResourceProvider resourceProvider, DependencyList dependencyList, Profile profileForValidation, List<String> allReferencedProfilesInResource, Collection<String> ignoredValueSets) {
log.debug("Applying dependency list: {}", dependencyList);
var fhirValidator = hapiFhirValidatorCache.computeIfAbsent(dependencyList, k ->
hapiFhirValidatorFactory.createInstance(
Expand All @@ -232,7 +233,7 @@ private ValidationResult validateUsingDependencyList(String resourceBody, Valida

log.debug("Pre-Transformation ValidationResult: Valid: {}, Messages: {}", intermediateResult.isSuccessful(), intermediateResult.getMessages());

var filteredMessages = severityLevelTransformator.applyTransformations(intermediateResult.getMessages(), dependencyList.getValidationMessageTransformations());
var filteredMessages = severityLevelTransformator.applyTransformations(intermediateResult.getMessages(), dependencyList.getValidationMessageTransformations(), ignoredValueSets);

if(!isValidationProfileReferencedInTheResource) {
SingleValidationMessage m = new SingleValidationMessage();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,25 +19,34 @@
import ca.uhn.fhir.validation.SingleValidationMessage;
import de.gematik.refv.commons.configuration.ValidationMessageTransformation;
import de.gematik.refv.commons.validation.support.IgnoreCodeSystemValidationSupport;
import org.apache.commons.lang3.StringUtils;
import lombok.NonNull;
import org.apache.commons.lang3.StringUtils;
import org.hl7.fhir.utilities.i18n.I18nConstants;

import java.util.Collection;
import java.util.LinkedList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

class SeverityLevelTransformer {

public List<SingleValidationMessage> applyTransformations(
Collection<SingleValidationMessage> input,
@NonNull
Collection<ValidationMessageTransformation> transformations
) {
return applyTransformations(input, transformations, List.of());
}

public List<SingleValidationMessage> applyTransformations(
List<SingleValidationMessage> input,
Collection<SingleValidationMessage> input,
@NonNull
List<ValidationMessageTransformation> transformations
Collection<ValidationMessageTransformation> transformations,
Collection<String> ignoredValueSets
) {
LinkedList<SingleValidationMessage> transformedMessages = new LinkedList<>(input);
escalateUnresolvedValueSetsToError(transformedMessages);
escalateUnresolvedValueSetsToError(transformedMessages, ignoredValueSets);
setIgnoredCodeSystemsToInformation(transformedMessages);

for (SingleValidationMessage message:
Expand Down Expand Up @@ -73,11 +82,24 @@ private void setIgnoredCodeSystemsToInformation(LinkedList<SingleValidationMessa
}
}

private void escalateUnresolvedValueSetsToError(LinkedList<SingleValidationMessage> messages) {
public static String extractValueSetUrl(String message) {
String urlPattern = "ValueSet ([^\\s]+) not found by validator";
Pattern pattern = Pattern.compile(urlPattern);
Matcher matcher = pattern.matcher(message);

if (matcher.find()) {
return matcher.group(1);
}
return null;
}

private void escalateUnresolvedValueSetsToError(LinkedList<SingleValidationMessage> messages, Collection<String> ignoredValueSets) {
for (SingleValidationMessage message:
messages) {
if(I18nConstants.TERMINOLOGY_TX_VALUESET_NOTFOUND.equals(message.getMessageId())) {
message.setSeverity(ResultSeverityEnum.ERROR);
String valueSetUrl = extractValueSetUrl(message.getMessage());
if(!ignoredValueSets.contains(valueSetUrl))
message.setSeverity(ResultSeverityEnum.ERROR);
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -134,18 +134,36 @@ void testTransformationIsNotPerformedOnMatchingLocatorStringButNonMatchingMessag
}

@Test
void testNotFoundValueSetsRuleWorks() {
void testUndefinedValueSetsEscalatedToErrors() {
var m1 = new SingleValidationMessage();
m1.setSeverity(ResultSeverityEnum.WARNING);
m1.setMessage("ValueSet https://fhir.kbv.de/ValueSet/KBV_VS_SFHIR_KBV_STATUSKENNZEICHEN not found by validator");
m1.setMessageId(I18nConstants.TERMINOLOGY_TX_VALUESET_NOTFOUND);

var inputMessages = List.of(m1);

var transformedMessages = engine.applyTransformations(inputMessages, new LinkedList<>());
Assertions.assertEquals(inputMessages.size(), transformedMessages.size());
Assertions.assertTrue(transformedMessages.stream().allMatch(m -> m.getSeverity().equals(ResultSeverityEnum.ERROR)));
}

@Test
void testUndefinedButIgnoredValueSetsAreNotEscalated() {
String ignoredValueSetUrl = "https://ignoredValueSet";
SeverityLevelTransformer engine = new SeverityLevelTransformer();

var m1 = new SingleValidationMessage();
m1.setSeverity(ResultSeverityEnum.WARNING);
m1.setMessage("ValueSet " + ignoredValueSetUrl + " not found by validator");
m1.setMessageId(I18nConstants.TERMINOLOGY_TX_VALUESET_NOTFOUND);

var inputMessages = List.of(m1);

var transformedMessages = engine.applyTransformations(inputMessages, new LinkedList<>(), List.of(ignoredValueSetUrl));
Assertions.assertEquals(inputMessages.size(), transformedMessages.size());
Assertions.assertTrue(transformedMessages.stream().allMatch(m -> m.getSeverity().equals(ResultSeverityEnum.WARNING)), "Undefined but ignored value sets still produce error message");
}

@Test
void testCodeSystemIsIgnoredRuleWorks() {
var m1 = new SingleValidationMessage();
Expand Down
2 changes: 1 addition & 1 deletion core/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<parent>
<artifactId>referencevalidator</artifactId>
<groupId>de.gematik.refv</groupId>
<version>2.5.1</version>
<version>2.6.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>

Expand Down
Loading

0 comments on commit ac258f3

Please sign in to comment.