diff --git a/android/engine/src/main/java/org/smartregister/fhircore/engine/configuration/PdfConfig.kt b/android/engine/src/main/java/org/smartregister/fhircore/engine/configuration/PdfConfig.kt index d778727a04..b17e97f247 100644 --- a/android/engine/src/main/java/org/smartregister/fhircore/engine/configuration/PdfConfig.kt +++ b/android/engine/src/main/java/org/smartregister/fhircore/engine/configuration/PdfConfig.kt @@ -19,7 +19,6 @@ package org.smartregister.fhircore.engine.configuration import android.os.Parcelable import kotlinx.parcelize.Parcelize import kotlinx.serialization.Serializable -import org.hl7.fhir.r4.model.ResourceType import org.smartregister.fhircore.engine.util.extension.interpolate @Serializable @@ -29,7 +28,7 @@ data class PdfConfig( val pdfTitleSuffix: String? = null, val pdfStructureReference: String? = null, val subjectReference: String? = null, - val questionnaireReferences: List = emptyList() + val questionnaireReferences: List = emptyList(), ) : java.io.Serializable, Parcelable { fun interpolate(computedValuesMap: Map) = diff --git a/android/engine/src/main/java/org/smartregister/fhircore/engine/pdf/HtmlPopulator.kt b/android/engine/src/main/java/org/smartregister/fhircore/engine/pdf/HtmlPopulator.kt index 4d51b15d18..f85d38b9f2 100644 --- a/android/engine/src/main/java/org/smartregister/fhircore/engine/pdf/HtmlPopulator.kt +++ b/android/engine/src/main/java/org/smartregister/fhircore/engine/pdf/HtmlPopulator.kt @@ -16,31 +16,33 @@ package org.smartregister.fhircore.engine.pdf +import java.util.Date import java.util.regex.Matcher import java.util.regex.Pattern import org.hl7.fhir.r4.model.BaseDateTimeType import org.hl7.fhir.r4.model.QuestionnaireResponse -import org.smartregister.fhircore.engine.util.extension.allItems import org.hl7.fhir.r4.model.QuestionnaireResponse.QuestionnaireResponseItemAnswerComponent +import org.smartregister.fhircore.engine.util.extension.allItems import org.smartregister.fhircore.engine.util.extension.extractLogicalIdUuid import org.smartregister.fhircore.engine.util.extension.formatDate import org.smartregister.fhircore.engine.util.extension.makeItReadable import org.smartregister.fhircore.engine.util.extension.valueToString -import java.util.Date /** * HtmlPopulator class is responsible for processing an HTML template by replacing custom tags with * data from QuestionnaireResponses. The class uses various regex patterns to find and replace - * custom tags such as @is-not-empty, @answer-as-list, @answer, @submitted-date, @contains, and - * @is-questionnaire-submitted. + * custom tags such as @is-not-empty, @answer-as-list, @answer, @submitted-date, @contains, + * and @is-questionnaire-submitted. * - * @property questionnaireResponses The QuestionnaireResponses object containing data for replacement. + * @property questionnaireResponses The QuestionnaireResponses object containing data for + * replacement. */ class HtmlPopulator( questionnaireResponses: List, ) { // Store answers as key-value pairs with link-id as key - private val answerMap: MutableMap> = mutableMapOf() + private val answerMap: MutableMap> = + mutableMapOf() // Store submitted-date of a questionnaire response with link-id as key private val submittedDateMap: MutableMap = mutableMapOf() @@ -51,10 +53,11 @@ class HtmlPopulator( init { questionnaireResponses.forEach { questionnaireResponse -> val questionnaireId = questionnaireResponse.questionnaire.extractLogicalIdUuid() - val answerMap = questionnaireResponse.allItems.associateBy( - keySelector = { "$questionnaireId/${it.linkId}" }, - valueTransform = { it.answer }, - ) + val answerMap = + questionnaireResponse.allItems.associateBy( + keySelector = { "$questionnaireId/${it.linkId}" }, + valueTransform = { it.answer }, + ) this.answerMap.putAll(answerMap) this.submittedDateMap[questionnaireId] = questionnaireResponse.meta.lastUpdated ?: Date() this.questionnaireIds.add(questionnaireId) @@ -141,8 +144,7 @@ class HtmlPopulator( private fun processAnswerAsList(i: Int, html: StringBuilder, matcher: Matcher) { val linkId = matcher.group(1) val answerAsList = - answerMap.getOrDefault(linkId, listOf()).joinToString(separator = "") { - answer -> + answerMap.getOrDefault(linkId, listOf()).joinToString(separator = "") { answer -> "
  • ${answer.value.valueToString()}
  • " } html.replace(i, matcher.end() + i, answerAsList) @@ -160,8 +162,9 @@ class HtmlPopulator( val dateFormat = matcher.group(2) val answer = answerMap.getOrDefault(linkId, listOf()).joinToString { answer -> - if (dateFormat == null) answer.value.valueToString() - else answer.value.valueToString(dateFormat) + if (dateFormat == null) { + answer.value.valueToString() + } else answer.value.valueToString(dateFormat) } html.replace(i, matcher.end() + i, answer) } @@ -220,8 +223,9 @@ class HtmlPopulator( } /** - * Processes the @is-questionnaire-submitted tag by checking if the corresponding [QuestionnaireResponse] exists. - * Replaces the tag with the content if the indicator is true, otherwise removes the tag. + * Processes the @is-questionnaire-submitted tag by checking if the corresponding + * [QuestionnaireResponse] exists. Replaces the tag with the content if the indicator is true, + * otherwise removes the tag. * * @param i The starting index of the tag in the HTML. * @param html The StringBuilder containing the HTML. @@ -244,10 +248,13 @@ class HtmlPopulator( Pattern.compile("@is-not-empty\\('([^']+)'\\)((?s).*?)@is-not-empty\\('\\1'\\)") private val answerAsListPattern = Pattern.compile("@answer-as-list\\('([^']+)'\\)") private val answerPattern = Pattern.compile("@answer\\('([^']+)'(?:,'([^']+)')?\\)") - private val submittedDatePattern = Pattern.compile("@submitted-date\\('([^']+)'(?:,'([^']+)')?\\)") + private val submittedDatePattern = + Pattern.compile("@submitted-date\\('([^']+)'(?:,'([^']+)')?\\)") private val containsPattern = Pattern.compile("@contains\\('([^']+)','([^']+)'\\)((?s).*?)@contains\\('\\1'\\)") private val isQuestionnaireSubmittedPattern = - Pattern.compile("@is-questionnaire-submitted\\('([^']+)'\\)((?s).*?)@is-questionnaire-submitted\\('\\1'\\)") + Pattern.compile( + "@is-questionnaire-submitted\\('([^']+)'\\)((?s).*?)@is-questionnaire-submitted\\('\\1'\\)", + ) } } diff --git a/android/engine/src/test/java/org/smartregister/fhircore/engine/pdf/HtmlPopulatorTest.kt b/android/engine/src/test/java/org/smartregister/fhircore/engine/pdf/HtmlPopulatorTest.kt index 74b6ba801c..df51ac3af6 100644 --- a/android/engine/src/test/java/org/smartregister/fhircore/engine/pdf/HtmlPopulatorTest.kt +++ b/android/engine/src/test/java/org/smartregister/fhircore/engine/pdf/HtmlPopulatorTest.kt @@ -40,6 +40,7 @@ class HtmlPopulatorTest { listOf( QuestionnaireResponse().apply { id = "1234" + questionnaire = "Questionnaire/1234" addItem().apply { linkId = "link-a" answer = buildList { @@ -50,7 +51,7 @@ class HtmlPopulatorTest { ) } } - } + }, ) val htmlPopulator = HtmlPopulator(questionnaireResponses) val populatedHtml = htmlPopulator.populateHtml(html) @@ -64,11 +65,12 @@ class HtmlPopulatorTest { listOf( QuestionnaireResponse().apply { id = "1234" + questionnaire = "Questionnaire/1234" addItem().apply { linkId = "link-a" answer = emptyList() } - } + }, ) val htmlPopulator = HtmlPopulator(questionnaireResponses) val populatedHtml = htmlPopulator.populateHtml(html) @@ -82,7 +84,9 @@ class HtmlPopulatorTest { listOf( QuestionnaireResponse().apply { id = "1234" - addItem().apply { linkId = "link-a" } } + questionnaire = "Questionnaire/1234" + addItem().apply { linkId = "link-a" } + }, ) val htmlPopulator = HtmlPopulator(questionnaireResponses) val populatedHtml = htmlPopulator.populateHtml(html) @@ -92,7 +96,13 @@ class HtmlPopulatorTest { @Test fun testIsNotEmptyShouldHideContentWhenLinkIdNotExistInQR() { val html = "@is-not-empty('1234/link-a')

    Text

    @is-not-empty('1234/link-a')" - val questionnaireResponses = listOf(QuestionnaireResponse().apply { id = "1234" }) + val questionnaireResponses = + listOf( + QuestionnaireResponse().apply { + id = "1234" + questionnaire = "Questionnaire/1234" + }, + ) val htmlPopulator = HtmlPopulator(questionnaireResponses) val populatedHtml = htmlPopulator.populateHtml(html) Assert.assertEquals("", populatedHtml) @@ -101,16 +111,31 @@ class HtmlPopulatorTest { @Test fun testIsNotEmptyShouldShowMalformedTagAndContentIfLinkIdOfBothTagDoesNotMatch() { val html = "@is-not-empty('1234/link-a')

    Text

    @is-not-empty('1234/link-b')" - val questionnaireResponses = listOf(QuestionnaireResponse().apply { id = "1234" }) + val questionnaireResponses = + listOf( + QuestionnaireResponse().apply { + id = "1234" + questionnaire = "Questionnaire/1234" + }, + ) val htmlPopulator = HtmlPopulator(questionnaireResponses) val populatedHtml = htmlPopulator.populateHtml(html) - Assert.assertEquals("@is-not-empty('1234/link-a')

    Text

    @is-not-empty('1234/link-b')", populatedHtml) + Assert.assertEquals( + "@is-not-empty('1234/link-a')

    Text

    @is-not-empty('1234/link-b')", + populatedHtml, + ) } @Test fun testIsNotEmptyShouldShowMalformedTagAndContentIfOnly1TagExist() { val html = "@is-not-empty('1234/link-a')

    Text

    " - val questionnaireResponses = listOf(QuestionnaireResponse().apply { id = "1234" }) + val questionnaireResponses = + listOf( + QuestionnaireResponse().apply { + id = "1234" + questionnaire = "Questionnaire/1234" + }, + ) val htmlPopulator = HtmlPopulator(questionnaireResponses) val populatedHtml = htmlPopulator.populateHtml(html) Assert.assertEquals("@is-not-empty('1234/link-a')

    Text

    ", populatedHtml) @@ -118,21 +143,25 @@ class HtmlPopulatorTest { @Test fun testIsNotEmptyShouldShowContentAndNestedMalformedTagIfAnswerOfRootTagExist() { - val html = "@is-not-empty('1234/link-a')@is-not-empty('1234/link-b')

    Text

    @is-not-empty('1234/link-a')" + val html = + "@is-not-empty('1234/link-a')@is-not-empty('1234/link-b')

    Text

    @is-not-empty('1234/link-a')" val questionnaireResponses = - listOf(QuestionnaireResponse().apply { + listOf( + QuestionnaireResponse().apply { id = "1234" - addItem().apply { - linkId = "link-a" - answer = buildList { - add( - QuestionnaireResponseItemAnswerComponent().apply { - value = Coding("system 1", "code 1", "display 1") - }, - ) + questionnaire = "Questionnaire/1234" + addItem().apply { + linkId = "link-a" + answer = buildList { + add( + QuestionnaireResponseItemAnswerComponent().apply { + value = Coding("system 1", "code 1", "display 1") + }, + ) + } } - } - }) + }, + ) val htmlPopulator = HtmlPopulator(questionnaireResponses) val populatedHtml = htmlPopulator.populateHtml(html) Assert.assertEquals("@is-not-empty('1234/link-b')

    Text

    ", populatedHtml) @@ -140,11 +169,16 @@ class HtmlPopulatorTest { @Test fun testIsNotEmptyShouldHideContentAndNestedMalformedTagIfAnswerOfRootTagIsNotExist() { - val html = "@is-not-empty('1234/link-a')@is-not-empty('1234/link-b')

    Text

    @is-not-empty('1234/link-a')" + val html = + "@is-not-empty('1234/link-a')@is-not-empty('1234/link-b')

    Text

    @is-not-empty('1234/link-a')" val questionnaireResponses = - listOf(QuestionnaireResponse().apply { + listOf( + QuestionnaireResponse().apply { id = "1234" - addItem().apply { linkId = "link-a" } }) + questionnaire = "Questionnaire/1234" + addItem().apply { linkId = "link-a" } + }, + ) val htmlPopulator = HtmlPopulator(questionnaireResponses) val populatedHtml = htmlPopulator.populateHtml(html) Assert.assertEquals("", populatedHtml) @@ -152,15 +186,19 @@ class HtmlPopulatorTest { @Test fun testIsNotEmptyShouldHideContentAndNestedMalformedTagIfAnswerOfRootTagIsEmpty() { - val html = "@is-not-empty('1234/link-a')@is-not-empty('1234/link-b')

    Text

    @is-not-empty('1234/link-a')" + val html = + "@is-not-empty('1234/link-a')@is-not-empty('1234/link-b')

    Text

    @is-not-empty('1234/link-a')" val questionnaireResponses = - listOf(QuestionnaireResponse().apply { + listOf( + QuestionnaireResponse().apply { id = "1234" - addItem().apply { - linkId = "link-a" - answer = emptyList() - } - }) + questionnaire = "Questionnaire/1234" + addItem().apply { + linkId = "link-a" + answer = emptyList() + } + }, + ) val htmlPopulator = HtmlPopulator(questionnaireResponses) val populatedHtml = htmlPopulator.populateHtml(html) Assert.assertEquals("", populatedHtml) @@ -170,19 +208,22 @@ class HtmlPopulatorTest { fun testIsNotEmptyShouldShowEmptyContentIfAnswerExist() { val html = "@is-not-empty('1234/link-a')@is-not-empty('1234/link-a')" val questionnaireResponses = - listOf(QuestionnaireResponse().apply { + listOf( + QuestionnaireResponse().apply { id = "1234" - addItem().apply { - linkId = "link-a" - answer = buildList { - add( - QuestionnaireResponseItemAnswerComponent().apply { - value = Coding("system 1", "code 1", "display 1") - }, - ) + questionnaire = "Questionnaire/1234" + addItem().apply { + linkId = "link-a" + answer = buildList { + add( + QuestionnaireResponseItemAnswerComponent().apply { + value = Coding("system 1", "code 1", "display 1") + }, + ) + } } - } - }) + }, + ) val htmlPopulator = HtmlPopulator(questionnaireResponses) val populatedHtml = htmlPopulator.populateHtml(html) Assert.assertEquals("", populatedHtml) @@ -192,24 +233,27 @@ class HtmlPopulatorTest { fun testProcessAnswerAsListShouldShowAnswerAsListWhenAnswerExistInQR() { val html = "
      @answer-as-list('1234/link-a')
    " val questionnaireResponses = - listOf(QuestionnaireResponse().apply { + listOf( + QuestionnaireResponse().apply { id = "1234" - addItem().apply { - linkId = "link-a" - answer = buildList { - add( - QuestionnaireResponseItemAnswerComponent().apply { - value = Coding("system 1", "code 1", "display 1") - }, - ) - add( - QuestionnaireResponseItemAnswerComponent().apply { - value = Coding("system 2", "code 2", "display 2") - }, - ) + questionnaire = "Questionnaire/1234" + addItem().apply { + linkId = "link-a" + answer = buildList { + add( + QuestionnaireResponseItemAnswerComponent().apply { + value = Coding("system 1", "code 1", "display 1") + }, + ) + add( + QuestionnaireResponseItemAnswerComponent().apply { + value = Coding("system 2", "code 2", "display 2") + }, + ) + } } - } - }) + }, + ) val htmlPopulator = HtmlPopulator(questionnaireResponses) val populatedHtml = htmlPopulator.populateHtml(html) Assert.assertEquals("
    • display 1
    • display 2
    ", populatedHtml) @@ -219,9 +263,13 @@ class HtmlPopulatorTest { fun testProcessAnswerAsListShouldShowEmptyAnswerAsListWhenAnswerNotExistInQR() { val html = "
      @answer-as-list('1234/link-a')
    " val questionnaireResponses = - listOf(QuestionnaireResponse().apply { + listOf( + QuestionnaireResponse().apply { id = "1234" - addItem().apply { linkId = "link-a" } }) + questionnaire = "Questionnaire/1234" + addItem().apply { linkId = "link-a" } + }, + ) val htmlPopulator = HtmlPopulator(questionnaireResponses) val populatedHtml = htmlPopulator.populateHtml(html) Assert.assertEquals("
      ", populatedHtml) @@ -230,7 +278,13 @@ class HtmlPopulatorTest { @Test fun testProcessAnswerAsListShouldShowEmptyAnswerAsListWhenLinkIdNotExistInQR() { val html = "
        @answer-as-list('1234/link-a')
      " - val questionnaireResponses = listOf(QuestionnaireResponse().apply { id = "1234" }) + val questionnaireResponses = + listOf( + QuestionnaireResponse().apply { + id = "1234" + questionnaire = "Questionnaire/1234" + }, + ) val htmlPopulator = HtmlPopulator(questionnaireResponses) val populatedHtml = htmlPopulator.populateHtml(html) Assert.assertEquals("
        ", populatedHtml) @@ -240,17 +294,20 @@ class HtmlPopulatorTest { fun testProcessAnswerShouldShowAnswerWhenAnswerExistInQR() { val html = "

        @answer('1234/link-a')

        " val questionnaireResponses = - listOf(QuestionnaireResponse().apply { + listOf( + QuestionnaireResponse().apply { id = "1234" - addItem().apply { - linkId = "link-a" - answer = buildList { - add( - QuestionnaireResponseItemAnswerComponent().apply { value = StringType("string 1") }, - ) + questionnaire = "Questionnaire/1234" + addItem().apply { + linkId = "link-a" + answer = buildList { + add( + QuestionnaireResponseItemAnswerComponent().apply { value = StringType("string 1") }, + ) + } } - } - }) + }, + ) val htmlPopulator = HtmlPopulator(questionnaireResponses) val populatedHtml = htmlPopulator.populateHtml(html) Assert.assertEquals("

        string 1

        ", populatedHtml) @@ -260,9 +317,13 @@ class HtmlPopulatorTest { fun testProcessAnswerShouldShowEmptyAnswerWhenAnswerNotExistInQR() { val html = "

        @answer('1234/link-a')

        " val questionnaireResponses = - listOf(QuestionnaireResponse().apply { + listOf( + QuestionnaireResponse().apply { id = "1234" - addItem().apply { linkId = "link-a" } }) + questionnaire = "Questionnaire/1234" + addItem().apply { linkId = "link-a" } + }, + ) val htmlPopulator = HtmlPopulator(questionnaireResponses) val populatedHtml = htmlPopulator.populateHtml(html) Assert.assertEquals("

        ", populatedHtml) @@ -271,7 +332,13 @@ class HtmlPopulatorTest { @Test fun testProcessAnswerShouldShowEmptyAnswerWhenLinkIdNotExistInQR() { val html = "

        @answer('1234/link-a')

        " - val questionnaireResponses = listOf(QuestionnaireResponse().apply { id = "1234" }) + val questionnaireResponses = + listOf( + QuestionnaireResponse().apply { + id = "1234" + questionnaire = "Questionnaire/1234" + }, + ) val htmlPopulator = HtmlPopulator(questionnaireResponses) val populatedHtml = htmlPopulator.populateHtml(html) Assert.assertEquals("

        ", populatedHtml) @@ -283,19 +350,22 @@ class HtmlPopulatorTest { val specificDate: Date = calendar.time val html = "

        @answer('1234/link-a')

        " val questionnaireResponses = - listOf(QuestionnaireResponse().apply { + listOf( + QuestionnaireResponse().apply { id = "1234" - addItem().apply { - linkId = "link-a" - answer = buildList { - add( - QuestionnaireResponseItemAnswerComponent().apply { - value = DateTimeType(specificDate) - }, - ) + questionnaire = "Questionnaire/1234" + addItem().apply { + linkId = "link-a" + answer = buildList { + add( + QuestionnaireResponseItemAnswerComponent().apply { + value = DateTimeType(specificDate) + }, + ) + } } - } - }) + }, + ) val htmlPopulator = HtmlPopulator(questionnaireResponses) val populatedHtml = htmlPopulator.populateHtml(html) Assert.assertEquals("

        14-May-2024

        ", populatedHtml) @@ -307,19 +377,22 @@ class HtmlPopulatorTest { val specificDate: Date = calendar.time val html = "

        @answer('1234/link-a','MMMM d, yyyy')

        " val questionnaireResponses = - listOf(QuestionnaireResponse().apply { + listOf( + QuestionnaireResponse().apply { id = "1234" - addItem().apply { - linkId = "link-a" - answer = buildList { - add( - QuestionnaireResponseItemAnswerComponent().apply { - value = DateTimeType(specificDate) - }, - ) + questionnaire = "Questionnaire/1234" + addItem().apply { + linkId = "link-a" + answer = buildList { + add( + QuestionnaireResponseItemAnswerComponent().apply { + value = DateTimeType(specificDate) + }, + ) + } } - } - }) + }, + ) val htmlPopulator = HtmlPopulator(questionnaireResponses) val populatedHtml = htmlPopulator.populateHtml(html) Assert.assertEquals("

        May 14, 2024

        ", populatedHtml) @@ -331,9 +404,13 @@ class HtmlPopulatorTest { val specificDate: Date = calendar.time val html = "

        @submitted-date('1234')

        " val questionnaireResponses = - listOf(QuestionnaireResponse().apply { + listOf( + QuestionnaireResponse().apply { id = "1234" - meta = Meta().apply { lastUpdated = specificDate } }) + questionnaire = "Questionnaire/1234" + meta = Meta().apply { lastUpdated = specificDate } + }, + ) val htmlPopulator = HtmlPopulator(questionnaireResponses) val populatedHtml = htmlPopulator.populateHtml(html) Assert.assertEquals("

        14-May-2024

        ", populatedHtml) @@ -345,9 +422,13 @@ class HtmlPopulatorTest { val specificDate: Date = calendar.time val html = "

        @submitted-date('1234','MMMM d, yyyy')

        " val questionnaireResponses = - listOf(QuestionnaireResponse().apply { + listOf( + QuestionnaireResponse().apply { id = "1234" - meta = Meta().apply { lastUpdated = specificDate } }) + questionnaire = "Questionnaire/1234" + meta = Meta().apply { lastUpdated = specificDate } + }, + ) val htmlPopulator = HtmlPopulator(questionnaireResponses) val populatedHtml = htmlPopulator.populateHtml(html) Assert.assertEquals("

        May 14, 2024

        ", populatedHtml) @@ -357,24 +438,27 @@ class HtmlPopulatorTest { fun testProcessContainsShouldShowContentWhenIndicatorCodeMatchesWithAnswerOfTypeCoding() { val html = "@contains('1234/link-a','code 2')

        Text

        @contains('1234/link-a')" val questionnaireResponses = - listOf(QuestionnaireResponse().apply { + listOf( + QuestionnaireResponse().apply { id = "1234" - addItem().apply { - linkId = "link-a" - answer = buildList { - add( - QuestionnaireResponseItemAnswerComponent().apply { - value = Coding("system 1", "code 1", "display 1") - }, - ) - add( - QuestionnaireResponseItemAnswerComponent().apply { - value = Coding("system 2", "code 2", "display 2") - }, - ) + questionnaire = "Questionnaire/1234" + addItem().apply { + linkId = "link-a" + answer = buildList { + add( + QuestionnaireResponseItemAnswerComponent().apply { + value = Coding("system 1", "code 1", "display 1") + }, + ) + add( + QuestionnaireResponseItemAnswerComponent().apply { + value = Coding("system 2", "code 2", "display 2") + }, + ) + } } - } - }) + }, + ) val htmlPopulator = HtmlPopulator(questionnaireResponses) val populatedHtml = htmlPopulator.populateHtml(html) Assert.assertEquals("

        Text

        ", populatedHtml) @@ -384,24 +468,27 @@ class HtmlPopulatorTest { fun testProcessContainsShouldHideContentWhenIndicatorCodeDoesNotMatchWithAnswerOfTypeCoding() { val html = "@contains('1234/link-a','code 3')

        Text

        @contains('1234/link-a')" val questionnaireResponses = - listOf(QuestionnaireResponse().apply { + listOf( + QuestionnaireResponse().apply { id = "1234" - addItem().apply { - linkId = "link-a" - answer = buildList { - add( - QuestionnaireResponseItemAnswerComponent().apply { - value = Coding("system 1", "code 1", "display 1") - }, - ) - add( - QuestionnaireResponseItemAnswerComponent().apply { - value = Coding("system 2", "code 2", "display 2") - }, - ) + questionnaire = "Questionnaire/1234" + addItem().apply { + linkId = "link-a" + answer = buildList { + add( + QuestionnaireResponseItemAnswerComponent().apply { + value = Coding("system 1", "code 1", "display 1") + }, + ) + add( + QuestionnaireResponseItemAnswerComponent().apply { + value = Coding("system 2", "code 2", "display 2") + }, + ) + } } - } - }) + }, + ) val htmlPopulator = HtmlPopulator(questionnaireResponses) val populatedHtml = htmlPopulator.populateHtml(html) Assert.assertEquals("", populatedHtml) @@ -411,17 +498,22 @@ class HtmlPopulatorTest { fun testProcessContainsShouldShowContentWhenIndicatorStringIsContainedInAnswerOfTypeString() { val html = "@contains('1234/link-a','basket')

        Text

        @contains('1234/link-a')" val questionnaireResponses = - listOf(QuestionnaireResponse().apply { + listOf( + QuestionnaireResponse().apply { id = "1234" - addItem().apply { - linkId = "link-a" - answer = buildList { - add( - QuestionnaireResponseItemAnswerComponent().apply { value = StringType("basketball") }, - ) + questionnaire = "Questionnaire/1234" + addItem().apply { + linkId = "link-a" + answer = buildList { + add( + QuestionnaireResponseItemAnswerComponent().apply { + value = StringType("basketball") + }, + ) + } } - } - }) + }, + ) val htmlPopulator = HtmlPopulator(questionnaireResponses) val populatedHtml = htmlPopulator.populateHtml(html) Assert.assertEquals("

        Text

        ", populatedHtml) @@ -431,17 +523,20 @@ class HtmlPopulatorTest { fun testProcessContainsShouldShowContentWhenIndicatorIntegerMatchesAnswerOfTypeInteger() { val html = "@contains('1234/link-a','10')

        Text

        @contains('1234/link-a')" val questionnaireResponses = - listOf(QuestionnaireResponse().apply { + listOf( + QuestionnaireResponse().apply { id = "1234" - addItem().apply { - linkId = "link-a" - answer = buildList { - add( - QuestionnaireResponseItemAnswerComponent().apply { value = IntegerType("10") }, - ) + questionnaire = "Questionnaire/1234" + addItem().apply { + linkId = "link-a" + answer = buildList { + add( + QuestionnaireResponseItemAnswerComponent().apply { value = IntegerType("10") }, + ) + } } - } - }) + }, + ) val htmlPopulator = HtmlPopulator(questionnaireResponses) val populatedHtml = htmlPopulator.populateHtml(html) Assert.assertEquals("

        Text

        ", populatedHtml) @@ -451,17 +546,20 @@ class HtmlPopulatorTest { fun testProcessContainsShouldShowContentWhenIndicatorDecimalMatchesAnswerOfTypeDecimal() { val html = "@contains('1234/link-a','1.5')

        Text

        @contains('1234/link-a')" val questionnaireResponses = - listOf(QuestionnaireResponse().apply { + listOf( + QuestionnaireResponse().apply { id = "1234" - addItem().apply { - linkId = "link-a" - answer = buildList { - add( - QuestionnaireResponseItemAnswerComponent().apply { value = DecimalType("1.5") }, - ) + questionnaire = "Questionnaire/1234" + addItem().apply { + linkId = "link-a" + answer = buildList { + add( + QuestionnaireResponseItemAnswerComponent().apply { value = DecimalType("1.5") }, + ) + } } - } - }) + }, + ) val htmlPopulator = HtmlPopulator(questionnaireResponses) val populatedHtml = htmlPopulator.populateHtml(html) Assert.assertEquals("

        Text

        ", populatedHtml) @@ -471,17 +569,20 @@ class HtmlPopulatorTest { fun testProcessContainsShouldShowContentWhenIndicatorBooleanMatchesAnswerOfTypeBoolean() { val html = "@contains('1234/link-a','true')

        Text

        @contains('1234/link-a')" val questionnaireResponses = - listOf(QuestionnaireResponse().apply { + listOf( + QuestionnaireResponse().apply { id = "1234" - addItem().apply { - linkId = "link-a" - answer = buildList { - add( - QuestionnaireResponseItemAnswerComponent().apply { value = BooleanType("true") }, - ) + questionnaire = "Questionnaire/1234" + addItem().apply { + linkId = "link-a" + answer = buildList { + add( + QuestionnaireResponseItemAnswerComponent().apply { value = BooleanType("true") }, + ) + } } - } - }) + }, + ) val htmlPopulator = HtmlPopulator(questionnaireResponses) val populatedHtml = htmlPopulator.populateHtml(html) Assert.assertEquals("

        Text

        ", populatedHtml) @@ -491,19 +592,22 @@ class HtmlPopulatorTest { fun testProcessContainsShouldShowContentWhenIndicatorQuantityMatchesAnswerOfTypeQuantity() { val html = "@contains('1234/link-a','3 years')

        Text

        @contains('1234/link-a')" val questionnaireResponses = - listOf(QuestionnaireResponse().apply { + listOf( + QuestionnaireResponse().apply { id = "1234" - addItem().apply { - linkId = "link-a" - answer = buildList { - add( - QuestionnaireResponseItemAnswerComponent().apply { - value = Quantity(null, 3, "system", "years", "years") - }, - ) + questionnaire = "Questionnaire/1234" + addItem().apply { + linkId = "link-a" + answer = buildList { + add( + QuestionnaireResponseItemAnswerComponent().apply { + value = Quantity(null, 3, "system", "years", "years") + }, + ) + } } - } - }) + }, + ) val htmlPopulator = HtmlPopulator(questionnaireResponses) val populatedHtml = htmlPopulator.populateHtml(html) Assert.assertEquals("

        Text

        ", populatedHtml) @@ -515,19 +619,22 @@ class HtmlPopulatorTest { val calendar = Calendar.getInstance().apply { set(2024, Calendar.MAY, 14) } val specificDate: Date = calendar.time val questionnaireResponses = - listOf(QuestionnaireResponse().apply { + listOf( + QuestionnaireResponse().apply { id = "1234" - addItem().apply { - linkId = "link-a" - answer = buildList { - add( - QuestionnaireResponseItemAnswerComponent().apply { - value = DateTimeType(specificDate) - }, - ) + questionnaire = "Questionnaire/1234" + addItem().apply { + linkId = "link-a" + answer = buildList { + add( + QuestionnaireResponseItemAnswerComponent().apply { + value = DateTimeType(specificDate) + }, + ) + } } - } - }) + }, + ) val htmlPopulator = HtmlPopulator(questionnaireResponses) val populatedHtml = htmlPopulator.populateHtml(html) Assert.assertEquals("

        Text

        ", populatedHtml) @@ -535,12 +642,15 @@ class HtmlPopulatorTest { @Test fun testProcessIsQuestionnaireSubmittedShouldShowContentWhenTheRelatedQuestionnaireResponseExists() { - val html = "@is-questionnaire-submitted('q-1234')

        Text

        @is-questionnaire-submitted('q-1234')" + val html = + "@is-questionnaire-submitted('q-1234')

        Text

        @is-questionnaire-submitted('q-1234')" val questionnaireResponses = - listOf(QuestionnaireResponse().apply { + listOf( + QuestionnaireResponse().apply { id = "1234" questionnaire = "Questionnaire/q-1234" - }) + }, + ) val htmlPopulator = HtmlPopulator(questionnaireResponses) val populatedHtml = htmlPopulator.populateHtml(html) Assert.assertEquals("

        Text

        ", populatedHtml) @@ -548,7 +658,8 @@ class HtmlPopulatorTest { @Test fun testProcessIsQuestionnaireSubmittedShouldNotShowContentWhenTheRelatedQuestionnaireResponseDoesNotExists() { - val html = "@is-questionnaire-submitted('q-1234')

        Text

        @is-questionnaire-submitted('q-1234')" + val html = + "@is-questionnaire-submitted('q-1234')

        Text

        @is-questionnaire-submitted('q-1234')" val questionnaireResponses = listOf() val htmlPopulator = HtmlPopulator(questionnaireResponses) val populatedHtml = htmlPopulator.populateHtml(html) diff --git a/android/quest/src/main/java/org/smartregister/fhircore/quest/ui/pdf/PdfLauncherFragment.kt b/android/quest/src/main/java/org/smartregister/fhircore/quest/ui/pdf/PdfLauncherFragment.kt index be76c869da..e5d706f92b 100644 --- a/android/quest/src/main/java/org/smartregister/fhircore/quest/ui/pdf/PdfLauncherFragment.kt +++ b/android/quest/src/main/java/org/smartregister/fhircore/quest/ui/pdf/PdfLauncherFragment.kt @@ -38,8 +38,8 @@ import org.smartregister.fhircore.engine.util.extension.extractLogicalIdUuid /** * A fragment for generating and displaying a PDF based on a questionnaire response. * - * This fragment uses the provided [PdfConfig] to retrieve a questionnaire response, - * populate an HTML template with the response data, and generate a PDF. + * This fragment uses the provided [PdfConfig] to retrieve a questionnaire response, populate an + * HTML template with the response data, and generate a PDF. */ @AndroidEntryPoint class PdfLauncherFragment : DialogFragment() { @@ -55,10 +55,12 @@ class PdfLauncherFragment : DialogFragment() { val pdfConfig = getPdfConfig() val pdfStructureId = pdfConfig.pdfStructureReference!!.extractLogicalIdUuid() - val pdfTitle = StringBuilder().append(pdfConfig.pdfTitle ?: getString(R.string.default_html_title)) + val pdfTitle = + StringBuilder().append(pdfConfig.pdfTitle ?: getString(R.string.default_html_title)) val pdfTitleSuffix = pdfConfig.pdfTitleSuffix val subjectReference = pdfConfig.subjectReference!! - val questionnaireIds = pdfConfig.questionnaireReferences.map { it.extractLogicalIdUuid() } ?: emptyList() + val questionnaireIds = + pdfConfig.questionnaireReferences.map { it.extractLogicalIdUuid() } ?: emptyList() lifecycleScope.launch(Dispatchers.IO) { val questionnaireResponses = diff --git a/android/quest/src/main/java/org/smartregister/fhircore/quest/ui/pdf/PdfLauncherViewModel.kt b/android/quest/src/main/java/org/smartregister/fhircore/quest/ui/pdf/PdfLauncherViewModel.kt index b5f3384c6a..a424d02c17 100644 --- a/android/quest/src/main/java/org/smartregister/fhircore/quest/ui/pdf/PdfLauncherViewModel.kt +++ b/android/quest/src/main/java/org/smartregister/fhircore/quest/ui/pdf/PdfLauncherViewModel.kt @@ -51,8 +51,7 @@ constructor( questionnaireId: String, subjectReference: String, ): QuestionnaireResponse? { - val searchQuery = - createQuestionnaireResponseSearchQuery(questionnaireId, subjectReference) + val searchQuery = createQuestionnaireResponseSearchQuery(questionnaireId, subjectReference) return defaultRepository.search(searchQuery).firstOrNull() } diff --git a/android/quest/src/main/java/org/smartregister/fhircore/quest/util/extensions/ConfigExtensions.kt b/android/quest/src/main/java/org/smartregister/fhircore/quest/util/extensions/ConfigExtensions.kt index f503c09d1a..bf0e893a23 100644 --- a/android/quest/src/main/java/org/smartregister/fhircore/quest/util/extensions/ConfigExtensions.kt +++ b/android/quest/src/main/java/org/smartregister/fhircore/quest/util/extensions/ConfigExtensions.kt @@ -225,10 +225,10 @@ fun ActionConfig.handleClickEvent( navController.navigate(MainNavigationScreen.LocationSelector.route, args) } ApplicationWorkflow.LAUNCH_PDF_GENERATION -> { - val pdfConfig = actionConfig.pdfConfig ?: return - val interpolatedPdfConfig = pdfConfig.interpolate(computedValuesMap) - val appCompatActivity = (navController.context as AppCompatActivity) - PdfLauncherFragment.launch(appCompatActivity, interpolatedPdfConfig.encodeJson()) + val pdfConfig = actionConfig.pdfConfig ?: return + val interpolatedPdfConfig = pdfConfig.interpolate(computedValuesMap) + val appCompatActivity = (navController.context as AppCompatActivity) + PdfLauncherFragment.launch(appCompatActivity, interpolatedPdfConfig.encodeJson()) } else -> return } diff --git a/android/quest/src/test/java/org/smartregister/fhircore/quest/ui/pdf/PdfLauncherFragmentTest.kt b/android/quest/src/test/java/org/smartregister/fhircore/quest/ui/pdf/PdfLauncherFragmentTest.kt index ec95efe3b3..1ece8ddbb3 100644 --- a/android/quest/src/test/java/org/smartregister/fhircore/quest/ui/pdf/PdfLauncherFragmentTest.kt +++ b/android/quest/src/test/java/org/smartregister/fhircore/quest/ui/pdf/PdfLauncherFragmentTest.kt @@ -27,7 +27,6 @@ import io.mockk.verify import kotlinx.coroutines.runBlocking import org.hl7.fhir.r4.model.Binary import org.hl7.fhir.r4.model.QuestionnaireResponse -import org.hl7.fhir.r4.model.ResourceType import org.junit.Before import org.junit.Rule import org.junit.Test @@ -61,19 +60,17 @@ class PdfLauncherFragmentTest : RobolectricTest() { coEvery { pdfLauncherViewModel.retrieveBinary(any()) } returns htmlBinary val pdfConfig = - PdfConfig( + PdfConfig( pdfTitle = "title", pdfTitleSuffix = "suffix", pdfStructureReference = "Binary/id", subjectReference = "Patient/id", - questionnaireReferences = listOf("QuestionnaireResponse/id") + questionnaireReferences = listOf("QuestionnaireResponse/id"), ) .encodeJson() val fragmentArgs = - Bundle().apply { - putString(PdfLauncherFragment.EXTRA_PDF_CONFIG_KEY, pdfConfig) - } + Bundle().apply { putString(PdfLauncherFragment.EXTRA_PDF_CONFIG_KEY, pdfConfig) } val activity = Robolectric.buildActivity(HiltTestActivity::class.java).create().resume().get() @@ -102,17 +99,15 @@ class PdfLauncherFragmentTest : RobolectricTest() { val pdfConfig = PdfConfig( pdfTitle = "title", - pdfTitleSuffix = "suffix", + pdfTitleSuffix = "suffix", pdfStructureReference = "Binary/id", subjectReference = "Patient/id", - questionnaireReferences = listOf("QuestionnaireResponse/id") + questionnaireReferences = listOf("QuestionnaireResponse/id"), ) .encodeJson() val fragmentArgs = - Bundle().apply { - putString(PdfLauncherFragment.EXTRA_PDF_CONFIG_KEY, pdfConfig) - } + Bundle().apply { putString(PdfLauncherFragment.EXTRA_PDF_CONFIG_KEY, pdfConfig) } val activity = Robolectric.buildActivity(HiltTestActivity::class.java).create().resume().get() @@ -144,14 +139,12 @@ class PdfLauncherFragmentTest : RobolectricTest() { pdfTitleSuffix = "suffix", pdfStructureReference = "Binary/id", subjectReference = "Patient/id", - questionnaireReferences = listOf("QuestionnaireResponse/id") + questionnaireReferences = listOf("QuestionnaireResponse/id"), ) .encodeJson() val fragmentArgs = - Bundle().apply { - putString(PdfLauncherFragment.EXTRA_PDF_CONFIG_KEY, pdfConfig) - } + Bundle().apply { putString(PdfLauncherFragment.EXTRA_PDF_CONFIG_KEY, pdfConfig) } val activity = Robolectric.buildActivity(HiltTestActivity::class.java).create().resume().get() @@ -183,14 +176,12 @@ class PdfLauncherFragmentTest : RobolectricTest() { pdfTitleSuffix = "suffix", pdfStructureReference = "Binary/id", subjectReference = "Patient/id", - questionnaireReferences = listOf("QuestionnaireResponse/id") + questionnaireReferences = listOf("QuestionnaireResponse/id"), ) .encodeJson() val fragmentArgs = - Bundle().apply { - putString(PdfLauncherFragment.EXTRA_PDF_CONFIG_KEY, pdfConfig) - } + Bundle().apply { putString(PdfLauncherFragment.EXTRA_PDF_CONFIG_KEY, pdfConfig) } val activity = Robolectric.buildActivity(HiltTestActivity::class.java).create().resume().get()