diff --git a/hapi-fhir-validation/pom.xml b/hapi-fhir-validation/pom.xml index 3a7742e2efd..35bdfa907a3 100644 --- a/hapi-fhir-validation/pom.xml +++ b/hapi-fhir-validation/pom.xml @@ -9,9 +9,11 @@ ../hapi-deployable-pom/pom.xml + fi.kela.kanta.phr + hapi-fhir-validation bundle - 3.6.4-PHRFIX + 3.6.5-PHRFIX HAPI FHIR - Validation diff --git a/hapi-fhir-validation/src/main/java/org/hl7/fhir/r4/validation/DefaultEnableWhenEvaluator.java b/hapi-fhir-validation/src/main/java/org/hl7/fhir/r4/validation/DefaultEnableWhenEvaluator.java index 9588fa0373c..06c9f18d792 100644 --- a/hapi-fhir-validation/src/main/java/org/hl7/fhir/r4/validation/DefaultEnableWhenEvaluator.java +++ b/hapi-fhir-validation/src/main/java/org/hl7/fhir/r4/validation/DefaultEnableWhenEvaluator.java @@ -196,6 +196,7 @@ public class DefaultEnableWhenEvaluator implements IEnableWhenEvaluator { } return true; } + private List findSubItems(Element item) { List results = item.getChildren(ITEM_ELEMENT) .stream() @@ -212,7 +213,5 @@ public class DefaultEnableWhenEvaluator implements IEnableWhenEvaluator { } return false; } - - } diff --git a/hapi-fhir-validation/src/main/java/org/hl7/fhir/r4/validation/InstanceValidator.java b/hapi-fhir-validation/src/main/java/org/hl7/fhir/r4/validation/InstanceValidator.java index 101da940c23..24c32900f17 100644 --- a/hapi-fhir-validation/src/main/java/org/hl7/fhir/r4/validation/InstanceValidator.java +++ b/hapi-fhir-validation/src/main/java/org/hl7/fhir/r4/validation/InstanceValidator.java @@ -2640,8 +2640,12 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat element.getNamedChildren("answer", answers); if (inProgress) warning(errors, IssueType.REQUIRED, element.line(), element.col(), stack.getLiteralPath(), isAnswerRequirementFulfilled(qItem, answers), "No response answer found for required item "+qItem.getLinkId()); - else + else if(myEnableWhenEvaluator.isQuestionEnabled(qItem, questionnaireResponseRoot)) rule(errors, IssueType.REQUIRED, element.line(), element.col(), stack.getLiteralPath(), isAnswerRequirementFulfilled(qItem, answers), "No response answer found for required item "+qItem.getLinkId()); + else if (!answers.isEmpty()) // items without answers should be allowed, but not items with answers to questions that are disabled + rule(errors, IssueType.INVALID, element.line(), element.col(), stack.getLiteralPath(), !isAnswerRequirementFulfilled(qItem, answers), "Item has answer, even though it is not enabled "+qItem.getLinkId()); + + if (answers.size() > 1) rule(errors, IssueType.INVALID, answers.get(1).line(), answers.get(1).col(), stack.getLiteralPath(), qItem.getRepeats(), "Only one response answer item with this linkId allowed"); @@ -2785,8 +2789,8 @@ private boolean isAnswerRequirementFulfilled(QuestionnaireItemComponent qItem, L // ok, now we have a list of known items, grouped by linkId. We"ve made an error for anything out of order for (QuestionnaireItemComponent qItem : qItems) { List mapItem = map.get(qItem.getLinkId()); - if (mapItem != null){ - rule(errors, IssueType.INVALID, element.line(), element.col(), stack.getLiteralPath(), myEnableWhenEvaluator.isQuestionEnabled(qItem, questionnaireResponseRoot), "Item has answer, even though it is not enabled "+qItem.getLinkId()); + if (mapItem != null) { + //rule(errors, IssueType.INVALID, element.line(), element.col(), stack.getLiteralPath(), myEnableWhenEvaluator.isQuestionEnabled(qItem, questionnaireResponseRoot), "Item has answer, even though it is not enabled "+qItem.getLinkId()); validateQuestionannaireResponseItem(qsrc, qItem, errors, mapItem, stack, inProgress, questionnaireResponseRoot); } else { //item is missing, is the question enabled? @@ -2796,6 +2800,7 @@ private boolean isAnswerRequirementFulfilled(QuestionnaireItemComponent qItem, L } } } + private String misplacedItemError(QuestionnaireItemComponent qItem) { return qItem.hasLinkId() ? diff --git a/hapi-fhir-validation/src/test/java/org/hl7/fhir/dstu3/hapi/validation/QuestionnaireResponseValidatorDstu3Test.java b/hapi-fhir-validation/src/test/java/org/hl7/fhir/dstu3/hapi/validation/QuestionnaireResponseValidatorDstu3Test.java index e1ffa326572..ad36908620d 100644 --- a/hapi-fhir-validation/src/test/java/org/hl7/fhir/dstu3/hapi/validation/QuestionnaireResponseValidatorDstu3Test.java +++ b/hapi-fhir-validation/src/test/java/org/hl7/fhir/dstu3/hapi/validation/QuestionnaireResponseValidatorDstu3Test.java @@ -351,23 +351,18 @@ public class QuestionnaireResponseValidatorDstu3Test { public void testRequiredQuestionWithEnableWhenHidesQuestionHasAnswerTrue() { Questionnaire q = new Questionnaire(); - q.addItem().setLinkId("link0").setRequired(true).setType(QuestionnaireItemType.STRING); + q.addItem().setLinkId("link0").setRequired(false).setType(QuestionnaireItemType.STRING); // create the questionnaire QuestionnaireItemComponent item1 = new QuestionnaireItemComponent(); - item1.setLinkId("link1").setRequired(true); + item1.setLinkId("link1").setRequired(true).addEnableWhen().setQuestion("link0").setHasAnswer(true); q.addItem(item1); - QuestionnaireItemEnableWhenComponent enable = new QuestionnaireItemEnableWhenComponent(); - item1.addEnableWhen(enable); - enable.setQuestion("link0"); - enable.setHasAnswer(true); - - + QuestionnaireResponse qa = new QuestionnaireResponse(); qa.setStatus(QuestionnaireResponseStatus.COMPLETED); qa.getQuestionnaire().setReference(QUESTIONNAIRE_URL); - + String reference = qa.getQuestionnaire().getReference(); when(myValSupport.fetchResource(any(FhirContext.class), eq(Questionnaire.class), eq(reference))).thenReturn(q); ValidationResult errors = myVal.validateWithResult(qa); @@ -531,6 +526,50 @@ public class QuestionnaireResponseValidatorDstu3Test { assertThat(errors.toString(), Matchers.not(containsString("No issues"))); } + @Test + public void testGivenQuestionIsNotEnabledWithEnableWhenButHasItemsWithoutAnswersAreOk() throws Exception { + Questionnaire q = new Questionnaire(); + q.addItem().setLinkId("link0").setRequired(false).setType(QuestionnaireItemType.STRING); + q.addItem().setLinkId("link2").setRequired(false).setType(QuestionnaireItemType.STRING).addEnableWhen().setQuestion("link0").setHasAnswer(true); + + QuestionnaireResponse qr = new QuestionnaireResponse(); + qr.setStatus(QuestionnaireResponseStatus.COMPLETED); + qr.getQuestionnaire().setReference(QUESTIONNAIRE_URL); + + qr.addItem().setLinkId("link2"); + + String reference = qr.getQuestionnaire().getReference(); + when(myValSupport.fetchResource(any(FhirContext.class), eq(Questionnaire.class), eq(reference))).thenReturn(q); + + ValidationResult errors = myVal.validateWithResult(qr); + + assertThat(errors.toString(), containsString("No issues")); + } + + @Test + public void testGivenQuestionIsNotEnabledWithEnableWhenButHasItemsWithoutAnswersAreOk2() throws Exception { + Questionnaire q = new Questionnaire(); + q.addItem().setLinkId("link0").setRequired(false).setType(QuestionnaireItemType.STRING); + q.addItem().setLinkId("link1").setRequired(false).setType(QuestionnaireItemType.STRING); + q.addItem().setLinkId("link2").setRequired(true).setType(QuestionnaireItemType.STRING).addEnableWhen().setQuestion("link0").setHasAnswer(true); + + QuestionnaireResponse qr = new QuestionnaireResponse(); + qr.setStatus(QuestionnaireResponseStatus.COMPLETED); + qr.getQuestionnaire().setReference(QUESTIONNAIRE_URL); + qr.addItem().setLinkId("link0"); + + qr.addItem().setLinkId("link1").addAnswer().setValue(new StringType("Answer")); + + qr.addItem().setLinkId("link2"); + + String reference = qr.getQuestionnaire().getReference(); + when(myValSupport.fetchResource(any(FhirContext.class), eq(Questionnaire.class), eq(reference))).thenReturn(q); + + ValidationResult errors = myVal.validateWithResult(qr); + + assertThat(errors.toString(), containsString("No issues")); + } + @Test public void testGivenQuestionnaireResponseHasSiblingItemsWhenTheyShouldBeChildItems() throws Exception { Questionnaire q = new Questionnaire();