diff --git a/android/engine/src/main/java/org/smartregister/fhircore/engine/configuration/register/RegisterConfiguration.kt b/android/engine/src/main/java/org/smartregister/fhircore/engine/configuration/register/RegisterConfiguration.kt index 82c325c7bc..5f89284a1d 100644 --- a/android/engine/src/main/java/org/smartregister/fhircore/engine/configuration/register/RegisterConfiguration.kt +++ b/android/engine/src/main/java/org/smartregister/fhircore/engine/configuration/register/RegisterConfiguration.kt @@ -45,5 +45,6 @@ data class RegisterConfiguration( ), val configRules: List? = null, val registerFilter: RegisterFilterConfig? = null, + val filterDataByRelatedEntityLocation: Boolean = false, val topScreenSection: TopScreenSectionConfig? = null, ) : Configuration() diff --git a/android/engine/src/main/java/org/smartregister/fhircore/engine/data/local/DefaultRepository.kt b/android/engine/src/main/java/org/smartregister/fhircore/engine/data/local/DefaultRepository.kt index 8d11dd1f83..6a2bbf0fe8 100644 --- a/android/engine/src/main/java/org/smartregister/fhircore/engine/data/local/DefaultRepository.kt +++ b/android/engine/src/main/java/org/smartregister/fhircore/engine/data/local/DefaultRepository.kt @@ -16,7 +16,9 @@ package org.smartregister.fhircore.engine.data.local +import android.content.Context import androidx.annotation.VisibleForTesting +import androidx.compose.ui.state.ToggleableState import ca.uhn.fhir.context.FhirContext import ca.uhn.fhir.parser.IParser import ca.uhn.fhir.rest.gclient.DateClientParam @@ -39,34 +41,40 @@ import com.jayway.jsonpath.Configuration import com.jayway.jsonpath.JsonPath import com.jayway.jsonpath.Option import com.jayway.jsonpath.PathNotFoundException +import dagger.hilt.android.qualifiers.ApplicationContext import java.util.LinkedList import java.util.UUID import javax.inject.Inject +import kotlinx.coroutines.flow.firstOrNull +import kotlinx.coroutines.runBlocking import kotlinx.coroutines.withContext import kotlinx.serialization.json.JsonArray import kotlinx.serialization.json.JsonElement +import kotlinx.serialization.json.JsonNull import kotlinx.serialization.json.JsonObject import kotlinx.serialization.json.JsonPrimitive import kotlinx.serialization.json.jsonArray import kotlinx.serialization.json.jsonObject import kotlinx.serialization.json.jsonPrimitive import org.hl7.fhir.instance.model.api.IBaseResource -import org.hl7.fhir.r4.model.Condition -import org.hl7.fhir.r4.model.DataRequirement +import org.hl7.fhir.r4.model.Coding import org.hl7.fhir.r4.model.Enumerations import org.hl7.fhir.r4.model.Group import org.hl7.fhir.r4.model.IdType +import org.hl7.fhir.r4.model.Location import org.hl7.fhir.r4.model.Patient import org.hl7.fhir.r4.model.Reference import org.hl7.fhir.r4.model.RelatedPerson import org.hl7.fhir.r4.model.Resource import org.hl7.fhir.r4.model.ResourceType +import org.smartregister.fhircore.engine.R import org.smartregister.fhircore.engine.configuration.ConfigurationRegistry import org.smartregister.fhircore.engine.configuration.app.ConfigService import org.smartregister.fhircore.engine.configuration.event.EventWorkflow import org.smartregister.fhircore.engine.configuration.profile.ManagingEntityConfig import org.smartregister.fhircore.engine.configuration.register.ActiveResourceFilterConfig import org.smartregister.fhircore.engine.data.local.register.RegisterRepository +import org.smartregister.fhircore.engine.datastore.syncLocationIdsProtoStore import org.smartregister.fhircore.engine.domain.model.Code import org.smartregister.fhircore.engine.domain.model.DataQuery import org.smartregister.fhircore.engine.domain.model.FhirResourceConfig @@ -103,6 +111,7 @@ constructor( open val configRulesExecutor: ConfigRulesExecutor, open val fhirPathDataExtractor: FhirPathDataExtractor, open val parser: IParser, + @ApplicationContext open val context: Context, ) { suspend inline fun loadResource(resourceId: String): T? { @@ -140,20 +149,6 @@ constructor( .map { it.resource } } - suspend fun searchCondition(dataRequirement: DataRequirement) = - when (dataRequirement.type) { - Enumerations.ResourceType.CONDITION.toCode() -> - fhirEngine - .search { - dataRequirement.codeFilter.forEach { - filter(TokenClientParam(it.path), { value = of(it.codeFirstRep) }) - } - // TODO handle date filter - } - .map { it.resource } - else -> listOf() - } - suspend inline fun search(search: Search) = fhirEngine.search(search).map { it.resource } @@ -850,10 +845,10 @@ constructor( ): List { val resourceFilterExpressionForCurrentResourceType = resourceFilterExpressions?.firstOrNull { - !resources.isNullOrEmpty() && (resources[0].resourceType == it.resourceType) + resources.isNotEmpty() && (resources[0].resourceType == it.resourceType) } return with(resourceFilterExpressionForCurrentResourceType) { - if ((this == null) || conditionalFhirPathExpressions.isNullOrEmpty()) { + if ((this == null) || conditionalFhirPathExpressions.isEmpty()) { resources } else { resources.filter { resource -> @@ -873,7 +868,7 @@ constructor( @VisibleForTesting suspend fun closeResource(resource: Resource, eventWorkflow: EventWorkflow) { - var conf: Configuration = + val conf: Configuration = Configuration.defaultConfiguration().apply { addOptions(Option.DEFAULT_PATH_LEAF_TO_NULL) } val jsonParse = JsonPath.using(conf).parse(resource.encodeResourceToString()) @@ -890,7 +885,7 @@ constructor( // Expression stars with '$' (JSONPath) or ResourceType like in FHIRPath if ( updateExpression.jsonPathExpression.startsWith("\$") && - updateExpression.value != null + updateExpression.value != JsonNull ) { set(updateExpression.jsonPathExpression, updateValue) } @@ -898,7 +893,7 @@ constructor( updateExpression.jsonPathExpression.startsWith( resource.resourceType.name, ignoreCase = true, - ) && updateExpression.value != null + ) && updateExpression.value != JsonNull ) { set( updateExpression.jsonPathExpression.replace( @@ -966,6 +961,7 @@ constructor( } suspend fun searchResourcesRecursively( + filterByRelatedEntityLocationMetaTag: Boolean, filterActiveResources: List?, fhirResourceConfig: FhirResourceConfig, secondaryResourceConfigs: List?, @@ -984,6 +980,10 @@ constructor( sortData = true, configComputedRuleValues = configComputedRuleValues, ) + applyFilterByRelatedEntityLocationMetaTag( + baseResourceConfig.resource, + filterByRelatedEntityLocationMetaTag, + ) if (currentPage != null && pageSize != null) { count = pageSize from = currentPage * pageSize @@ -1046,12 +1046,56 @@ constructor( filterActiveResources = filterActiveResources, secondaryResourceConfigs = null, configRules = null, + filterByRelatedEntityLocationMetaTag = false, ), ) } return secondaryRepositoryResourceDataLinkedList } + suspend fun Search.applyFilterByRelatedEntityLocationMetaTag( + baseResourceType: ResourceType, + filterByRelatedEntityLocation: Boolean, + ) { + runBlocking { + if (filterByRelatedEntityLocation) { + val system = context.getString(R.string.sync_strategy_related_entity_location_system) + val display = context.getString(R.string.sync_strategy_related_entity_location_display) + val locationIds = + context.syncLocationIdsProtoStore.data + .firstOrNull() + ?.filter { it.toggleableState == ToggleableState.On } + ?.map { it.locationId } + .takeIf { !it.isNullOrEmpty() } + val filters = + if (baseResourceType == ResourceType.Location) { // E.g where _id=uuid1,uuid2 + locationIds?.map { + val apply: TokenParamFilterCriterion.() -> Unit = { value = of(it) } + apply + } + } else { + locationIds?.map { code -> // The RelatedEntityLocation is retrieved from meta tag + val apply: TokenParamFilterCriterion.() -> Unit = { + value = of(Coding(system, code, display)) + } + apply + } + } + + if (!filters.isNullOrEmpty()) { + this@applyFilterByRelatedEntityLocationMetaTag.filter( + if (baseResourceType == ResourceType.Location) { + Location.RES_ID + } else { + TokenClientParam(TAG) + }, + *filters.toTypedArray(), + ) + } + } + } + } + /** * A wrapper data class to hold search results. All related resources are flattened into one Map * including the nested related resources as required by the Rules Engine facts. @@ -1065,7 +1109,6 @@ constructor( const val SNOMED_SYSTEM = "http://hl7.org/fhir/R4B/valueset-condition-clinical.html" const val PATIENT_CONDITION_RESOLVED_CODE = "resolved" const val PATIENT_CONDITION_RESOLVED_DISPLAY = "Resolved" - const val PNC_CONDITION_TO_CLOSE_RESOURCE_ID = "pncConditionToClose" - const val SICK_CHILD_CONDITION_TO_CLOSE_RESOURCE_ID = "sickChildConditionToClose" + const val TAG = "_tag" } } diff --git a/android/engine/src/main/java/org/smartregister/fhircore/engine/data/local/register/RegisterRepository.kt b/android/engine/src/main/java/org/smartregister/fhircore/engine/data/local/register/RegisterRepository.kt index a94393f984..23577d7520 100644 --- a/android/engine/src/main/java/org/smartregister/fhircore/engine/data/local/register/RegisterRepository.kt +++ b/android/engine/src/main/java/org/smartregister/fhircore/engine/data/local/register/RegisterRepository.kt @@ -16,9 +16,11 @@ package org.smartregister.fhircore.engine.data.local.register +import android.content.Context import ca.uhn.fhir.parser.IParser import com.google.android.fhir.FhirEngine import com.google.android.fhir.search.Search +import dagger.hilt.android.qualifiers.ApplicationContext import javax.inject.Inject import kotlinx.coroutines.withContext import org.hl7.fhir.r4.model.Resource @@ -51,6 +53,7 @@ constructor( override val configRulesExecutor: ConfigRulesExecutor, override val fhirPathDataExtractor: FhirPathDataExtractor, override val parser: IParser, + @ApplicationContext override val context: Context, ) : Repository, DefaultRepository( @@ -62,6 +65,7 @@ constructor( configRulesExecutor = configRulesExecutor, fhirPathDataExtractor = fhirPathDataExtractor, parser = parser, + context = context, ) { override suspend fun loadRegisterData( @@ -72,6 +76,8 @@ constructor( ): List { val registerConfiguration = retrieveRegisterConfiguration(registerId, paramsMap) return searchResourcesRecursively( + filterByRelatedEntityLocationMetaTag = + registerConfiguration.filterDataByRelatedEntityLocation, filterActiveResources = registerConfiguration.activeResourceFilters, fhirResourceConfig = fhirResourceConfig ?: registerConfiguration.fhirResource, secondaryResourceConfigs = registerConfiguration.secondaryResources, @@ -91,6 +97,7 @@ constructor( val fhirResource = fhirResourceConfig ?: registerConfiguration.fhirResource val baseResourceConfig = fhirResource.baseResource val configComputedRuleValues = registerConfiguration.configRules.configRulesComputedValues() + val filterByRelatedEntityLocation = registerConfiguration.filterDataByRelatedEntityLocation val search = Search(baseResourceConfig.resource).apply { applyConfiguredSortAndFilters( @@ -99,6 +106,10 @@ constructor( filterActiveResources = registerConfiguration.activeResourceFilters, configComputedRuleValues = configComputedRuleValues, ) + applyFilterByRelatedEntityLocationMetaTag( + baseResourceType = baseResourceConfig.resource, + filterByRelatedEntityLocation = filterByRelatedEntityLocation, + ) } return search.count( onFailure = { diff --git a/android/engine/src/main/java/org/smartregister/fhircore/engine/datastore/PreferenceDataStore.kt b/android/engine/src/main/java/org/smartregister/fhircore/engine/datastore/PreferenceDataStore.kt index c9e3d5f12f..8fc21ee943 100644 --- a/android/engine/src/main/java/org/smartregister/fhircore/engine/datastore/PreferenceDataStore.kt +++ b/android/engine/src/main/java/org/smartregister/fhircore/engine/datastore/PreferenceDataStore.kt @@ -54,7 +54,6 @@ class PreferenceDataStore @Inject constructor(@ApplicationContext val context: C companion object Keys { val APP_ID by lazy { stringPreferencesKey("appId") } val LANG by lazy { stringPreferencesKey("lang") } - val SYNC_LOCATION_IDS by lazy { stringPreferencesKey("syncLocationIds") } val MIGRATION_VERSION by lazy { intPreferencesKey("migrationVersion") } } } diff --git a/android/engine/src/main/java/org/smartregister/fhircore/engine/datastore/ProtoDataStore.kt b/android/engine/src/main/java/org/smartregister/fhircore/engine/datastore/ProtoDataStore.kt index ad3f3d2261..c18738afd3 100644 --- a/android/engine/src/main/java/org/smartregister/fhircore/engine/datastore/ProtoDataStore.kt +++ b/android/engine/src/main/java/org/smartregister/fhircore/engine/datastore/ProtoDataStore.kt @@ -41,8 +41,6 @@ private const val LOCATION_COORDINATES_DATASTORE_JSON = "location_coordinates.js private const val SYNC_LOCATION_IDS = "sync_location_ids.json" -private const val TAG = "Proto DataStore" - val Context.practitionerProtoStore: DataStore by dataStore( fileName = PRACTITIONER_DETAILS_DATASTORE_JSON, diff --git a/android/engine/src/test/java/org/smartregister/fhircore/engine/data/local/DefaultRepositoryTest.kt b/android/engine/src/test/java/org/smartregister/fhircore/engine/data/local/DefaultRepositoryTest.kt index c2bc83fb1e..2611105857 100644 --- a/android/engine/src/test/java/org/smartregister/fhircore/engine/data/local/DefaultRepositoryTest.kt +++ b/android/engine/src/test/java/org/smartregister/fhircore/engine/data/local/DefaultRepositoryTest.kt @@ -29,6 +29,7 @@ import com.google.gson.Gson import dagger.hilt.android.testing.BindValue import dagger.hilt.android.testing.HiltAndroidRule import dagger.hilt.android.testing.HiltAndroidTest +import dagger.hilt.android.testing.HiltTestApplication import io.mockk.coEvery import io.mockk.coVerify import io.mockk.every @@ -53,7 +54,6 @@ import org.hl7.fhir.r4.model.CodeableConcept import org.hl7.fhir.r4.model.Coding import org.hl7.fhir.r4.model.Condition import org.hl7.fhir.r4.model.ContactPoint -import org.hl7.fhir.r4.model.DataRequirement import org.hl7.fhir.r4.model.DateTimeType import org.hl7.fhir.r4.model.Enumerations import org.hl7.fhir.r4.model.Group @@ -122,6 +122,7 @@ class DefaultRepositoryTest : RobolectricTest() { spyk(AppConfigService(ApplicationProvider.getApplicationContext())) private val application = ApplicationProvider.getApplicationContext() private val configurationRegistry: ConfigurationRegistry = Faker.buildTestConfigurationRegistry() + private val context = ApplicationProvider.getApplicationContext() private lateinit var dispatcherProvider: DefaultDispatcherProvider private lateinit var sharedPreferenceHelper: SharedPreferencesHelper private lateinit var defaultRepository: DefaultRepository @@ -141,6 +142,7 @@ class DefaultRepositoryTest : RobolectricTest() { configRulesExecutor = configRulesExecutor, fhirPathDataExtractor = fhirPathDataExtractor, parser = parser, + context = context, ) } @@ -201,30 +203,6 @@ class DefaultRepositoryTest : RobolectricTest() { coVerify { fhirEngine.search(any()) } } - @Test - fun searchShouldReturn1ConditionGivenConditionTypeDataRequirement() = runTest { - val coding = Coding("https://system.co", "codi", "Condition code") - val condition = Condition().apply { code = CodeableConcept(coding) } - - fhirEngine.create(condition) - - runBlocking { - val actualPatients = - defaultRepository.searchCondition( - dataRequirement = - DataRequirement().apply { - type = Enumerations.ResourceType.CONDITION.toCode() - addCodeFilter( - DataRequirement.DataRequirementCodeFilterComponent() - .addCode(coding) - .setPath("code"), - ) - }, - ) - Assert.assertEquals(1, actualPatients.size) - } - } - @Test fun addOrUpdateShouldCallFhirEngineUpdateWhenResourceExists() { val patientId = "15672-9234" @@ -577,6 +555,7 @@ class DefaultRepositoryTest : RobolectricTest() { configRulesExecutor = mockk(), fhirPathDataExtractor = fhirPathDataExtractor, parser = parser, + context = context, ), ) coEvery { fhirEngine.search(any()) } returns @@ -654,6 +633,7 @@ class DefaultRepositoryTest : RobolectricTest() { configRulesExecutor = mockk(), fhirPathDataExtractor = fhirPathDataExtractor, parser = parser, + context = context, ), ) @@ -1250,9 +1230,9 @@ class DefaultRepositoryTest : RobolectricTest() { coVerify { fhirEngine.update(capture(conditionSlot)) } val capturedCode = conditionSlot.captured.clinicalStatus.coding.first() Assert.assertEquals("37793d31-def5-40bd-a2e3-fdaf5a0ddc53", conditionSlot.captured.id) - Assert.assertEquals(DefaultRepository.PATIENT_CONDITION_RESOLVED_CODE, capturedCode.code) - Assert.assertEquals(DefaultRepository.SNOMED_SYSTEM, capturedCode.system) - Assert.assertEquals(DefaultRepository.PATIENT_CONDITION_RESOLVED_DISPLAY, capturedCode.display) + Assert.assertEquals(PATIENT_CONDITION_RESOLVED_CODE, capturedCode.code) + Assert.assertEquals(SNOMED_SYSTEM, capturedCode.system) + Assert.assertEquals(PATIENT_CONDITION_RESOLVED_DISPLAY, capturedCode.display) } @Test @@ -1357,9 +1337,9 @@ class DefaultRepositoryTest : RobolectricTest() { coVerify { fhirEngine.update(capture(conditionSlot)) } val capturedCode = conditionSlot.captured.clinicalStatus.coding.first() Assert.assertEquals("37793d31-def5-40bd-a2e3-fdaf5a0ddc53", conditionSlot.captured.id) - Assert.assertEquals(DefaultRepository.PATIENT_CONDITION_RESOLVED_CODE, capturedCode.code) - Assert.assertEquals(DefaultRepository.SNOMED_SYSTEM, capturedCode.system) - Assert.assertEquals(DefaultRepository.PATIENT_CONDITION_RESOLVED_DISPLAY, capturedCode.display) + Assert.assertEquals(PATIENT_CONDITION_RESOLVED_CODE, capturedCode.code) + Assert.assertEquals(SNOMED_SYSTEM, capturedCode.system) + Assert.assertEquals(PATIENT_CONDITION_RESOLVED_DISPLAY, capturedCode.display) } // TODO Refactor/Remove after https://github.com/opensrp/fhircore/issues/2488 @@ -1424,9 +1404,9 @@ class DefaultRepositoryTest : RobolectricTest() { coVerify { fhirEngine.update(capture(conditionSlot)) } val capturedCode = conditionSlot.captured.clinicalStatus.coding.first() Assert.assertEquals("37793d31-def5-40bd-a2e3-fdaf5a0ddc53", conditionSlot.captured.id) - Assert.assertEquals(DefaultRepository.PATIENT_CONDITION_RESOLVED_CODE, capturedCode.code) - Assert.assertEquals(DefaultRepository.SNOMED_SYSTEM, capturedCode.system) - Assert.assertEquals(DefaultRepository.PATIENT_CONDITION_RESOLVED_DISPLAY, capturedCode.display) + Assert.assertEquals(PATIENT_CONDITION_RESOLVED_CODE, capturedCode.code) + Assert.assertEquals(SNOMED_SYSTEM, capturedCode.system) + Assert.assertEquals(PATIENT_CONDITION_RESOLVED_DISPLAY, capturedCode.display) } @Test diff --git a/android/engine/src/test/java/org/smartregister/fhircore/engine/data/local/register/RegisterRepositoryTest.kt b/android/engine/src/test/java/org/smartregister/fhircore/engine/data/local/register/RegisterRepositoryTest.kt index 3fb6e7a5f0..b30981020a 100644 --- a/android/engine/src/test/java/org/smartregister/fhircore/engine/data/local/register/RegisterRepositoryTest.kt +++ b/android/engine/src/test/java/org/smartregister/fhircore/engine/data/local/register/RegisterRepositoryTest.kt @@ -16,6 +16,9 @@ package org.smartregister.fhircore.engine.data.local.register +import android.app.Application +import androidx.compose.ui.state.ToggleableState +import androidx.test.core.app.ApplicationProvider import ca.uhn.fhir.parser.IParser import com.google.android.fhir.FhirEngine import com.google.android.fhir.logicalId @@ -32,9 +35,11 @@ import kotlin.time.Duration.Companion.seconds import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.test.runTest import org.hl7.fhir.r4.model.CarePlan +import org.hl7.fhir.r4.model.Coding import org.hl7.fhir.r4.model.Encounter import org.hl7.fhir.r4.model.Enumerations.DataType import org.hl7.fhir.r4.model.Group +import org.hl7.fhir.r4.model.Meta import org.hl7.fhir.r4.model.Observation import org.hl7.fhir.r4.model.Patient import org.hl7.fhir.r4.model.Reference @@ -43,23 +48,28 @@ import org.hl7.fhir.r4.model.ResourceType import org.hl7.fhir.r4.model.Task import org.junit.Assert import org.junit.Before +import org.junit.Ignore import org.junit.Rule import org.junit.Test import org.smartregister.fhircore.engine.app.fakes.Faker +import org.smartregister.fhircore.engine.configuration.ConfigType import org.smartregister.fhircore.engine.configuration.ConfigurationRegistry import org.smartregister.fhircore.engine.configuration.profile.ProfileConfiguration import org.smartregister.fhircore.engine.configuration.register.RegisterConfiguration +import org.smartregister.fhircore.engine.datastore.syncLocationIdsProtoStore import org.smartregister.fhircore.engine.domain.model.ActionParameter import org.smartregister.fhircore.engine.domain.model.ActionParameterType import org.smartregister.fhircore.engine.domain.model.CountResultConfig import org.smartregister.fhircore.engine.domain.model.FhirResourceConfig import org.smartregister.fhircore.engine.domain.model.RepositoryResourceData import org.smartregister.fhircore.engine.domain.model.ResourceConfig +import org.smartregister.fhircore.engine.domain.model.SyncLocationToggleableState import org.smartregister.fhircore.engine.robolectric.RobolectricTest import org.smartregister.fhircore.engine.rule.CoroutineTestRule import org.smartregister.fhircore.engine.rulesengine.RulesFactory import org.smartregister.fhircore.engine.util.DispatcherProvider import org.smartregister.fhircore.engine.util.extension.asReference +import org.smartregister.fhircore.engine.util.extension.encodeJson import org.smartregister.fhircore.engine.util.fhirpath.FhirPathDataExtractor private const val PATIENT_REGISTER = "patientRegister" @@ -112,6 +122,7 @@ class RegisterRepositoryTest : RobolectricTest() { configRulesExecutor = mockk(), fhirPathDataExtractor = fhirPathDataExtractor, parser = parser, + context = ApplicationProvider.getApplicationContext(), ), ) } @@ -445,6 +456,66 @@ class RegisterRepositoryTest : RobolectricTest() { ), ) + @Ignore("Check why group meta tag is not set ") + @Test + fun testLoadRegisterDataWithAfterFilterByRelatedEntityLocation() { + val locationId = "location1" + runTest(timeout = 90.seconds) { + val group1 = + createGroup("group1", active = true, members = listOf(patient)).apply { + meta = + Meta().apply { + addTag( + Coding( + "https://smartregister.org/related-entity-location-tag-id", + locationId, + "Related Entity Location", + ), + ) + } + } + val group2 = createGroup("group2", active = true, members = listOf(patient)) + val task = createTask("task1", null, patient.asReference()) + + // Replace Household Register configuration + val registerConfiguration = + configurationRegistry.retrieveConfiguration( + configType = ConfigType.Register, + configId = HOUSEHOLD_REGISTER_ID, + ) + configurationRegistry.configCacheMap.clear() + configurationRegistry.configsJsonMap[HOUSEHOLD_REGISTER_ID] = + registerConfiguration + .copy( + filterDataByRelatedEntityLocation = true, + fhirResource = + FhirResourceConfig(baseResource = ResourceConfig(resource = ResourceType.Group)), + ) + .encodeJson() + + // Set locations + ApplicationProvider.getApplicationContext() + .syncLocationIdsProtoStore + .updateData { listOf(SyncLocationToggleableState(locationId, ToggleableState.On)) } + + // Prepare resources + fhirEngine.run { + create(patient) + create(group1) + create(group2) + create(task) + } + + val result = registerRepository.loadRegisterData(0, HOUSEHOLD_REGISTER_ID) + + Assert.assertEquals(1, result.size) + + // Re-set register configuration + configurationRegistry.configsJsonMap[HOUSEHOLD_REGISTER_ID] = + registerConfiguration.encodeJson() + } + } + private fun createCarePlan(id: String, subject: Reference, encounter: Reference? = null) = CarePlan().apply { this.id = id diff --git a/android/engine/src/test/java/org/smartregister/fhircore/engine/task/FhirResourceExpireWorkerTest.kt b/android/engine/src/test/java/org/smartregister/fhircore/engine/task/FhirResourceExpireWorkerTest.kt index a2ae21c492..e6ce1dfe6b 100644 --- a/android/engine/src/test/java/org/smartregister/fhircore/engine/task/FhirResourceExpireWorkerTest.kt +++ b/android/engine/src/test/java/org/smartregister/fhircore/engine/task/FhirResourceExpireWorkerTest.kt @@ -119,6 +119,7 @@ class FhirResourceExpireWorkerTest : RobolectricTest() { configRulesExecutor = mockk(), fhirPathDataExtractor = mockk(), parser = parser, + context = ApplicationProvider.getApplicationContext(), ), ) diff --git a/android/geowidget/src/test/java/org/smartregister/fhircore/geowidget/screens/GeoWidgetViewModelTest.kt b/android/geowidget/src/test/java/org/smartregister/fhircore/geowidget/screens/GeoWidgetViewModelTest.kt index d1ed7d5e6f..c3e827ca4a 100644 --- a/android/geowidget/src/test/java/org/smartregister/fhircore/geowidget/screens/GeoWidgetViewModelTest.kt +++ b/android/geowidget/src/test/java/org/smartregister/fhircore/geowidget/screens/GeoWidgetViewModelTest.kt @@ -18,6 +18,7 @@ package org.smartregister.fhircore.geowidget.screens import android.os.Build import androidx.arch.core.executor.testing.InstantTaskExecutorRule +import androidx.test.core.app.ApplicationProvider import ca.uhn.fhir.parser.IParser import com.google.android.fhir.FhirEngine import dagger.hilt.android.testing.HiltAndroidRule @@ -95,14 +96,15 @@ class GeoWidgetViewModelTest { defaultRepository = spyk( DefaultRepository( - fhirEngine, - coroutinesTestRule.testDispatcherProvider, - sharedPreferencesHelper, - configurationRegistry, - configService, - configRulesExecutor, + fhirEngine = fhirEngine, + dispatcherProvider = coroutinesTestRule.testDispatcherProvider, + sharedPreferencesHelper = sharedPreferencesHelper, + configurationRegistry = configurationRegistry, + configService = configService, + configRulesExecutor = configRulesExecutor, fhirPathDataExtractor = fhirPathDataExtractor, parser = parser, + context = ApplicationProvider.getApplicationContext(), ), ) geoWidgetViewModel = spyk(GeoWidgetViewModel(coroutinesTestRule.testDispatcherProvider)) diff --git a/android/quest/src/main/java/org/smartregister/fhircore/quest/data/DataMigration.kt b/android/quest/src/main/java/org/smartregister/fhircore/quest/data/DataMigration.kt index 5f95b3a479..8807b5d3e6 100644 --- a/android/quest/src/main/java/org/smartregister/fhircore/quest/data/DataMigration.kt +++ b/android/quest/src/main/java/org/smartregister/fhircore/quest/data/DataMigration.kt @@ -156,6 +156,7 @@ constructor( val repositoryResourceDataList = defaultRepository .searchResourcesRecursively( + filterByRelatedEntityLocationMetaTag = false, filterActiveResources = null, fhirResourceConfig = migrationConfig.resourceConfig, configRules = null, diff --git a/android/quest/src/main/java/org/smartregister/fhircore/quest/data/report/measure/MeasureReportRepository.kt b/android/quest/src/main/java/org/smartregister/fhircore/quest/data/report/measure/MeasureReportRepository.kt index 8733abe6ce..de5361c601 100644 --- a/android/quest/src/main/java/org/smartregister/fhircore/quest/data/report/measure/MeasureReportRepository.kt +++ b/android/quest/src/main/java/org/smartregister/fhircore/quest/data/report/measure/MeasureReportRepository.kt @@ -16,12 +16,14 @@ package org.smartregister.fhircore.quest.data.report.measure +import android.content.Context import ca.uhn.fhir.parser.IParser import com.google.android.fhir.FhirEngine import com.google.android.fhir.knowledge.KnowledgeManager import com.google.android.fhir.logicalId import com.google.android.fhir.search.search import com.google.android.fhir.workflow.FhirOperator +import dagger.hilt.android.qualifiers.ApplicationContext import javax.inject.Inject import kotlinx.coroutines.withContext import org.hl7.fhir.exceptions.FHIRException @@ -33,7 +35,6 @@ import org.smartregister.fhircore.engine.configuration.ConfigurationRegistry import org.smartregister.fhircore.engine.configuration.app.ConfigService import org.smartregister.fhircore.engine.configuration.report.measure.ReportConfiguration import org.smartregister.fhircore.engine.data.local.DefaultRepository -import org.smartregister.fhircore.engine.data.local.register.RegisterRepository import org.smartregister.fhircore.engine.rulesengine.ConfigRulesExecutor import org.smartregister.fhircore.engine.util.DispatcherProvider import org.smartregister.fhircore.engine.util.SharedPreferencesHelper @@ -51,11 +52,11 @@ constructor( override val configurationRegistry: ConfigurationRegistry, override val configService: ConfigService, override val configRulesExecutor: ConfigRulesExecutor, - val registerRepository: RegisterRepository, private val fhirOperator: FhirOperator, private val knowledgeManager: KnowledgeManager, override val fhirPathDataExtractor: FhirPathDataExtractor, override val parser: IParser, + @ApplicationContext override val context: Context, ) : DefaultRepository( fhirEngine = fhirEngine, @@ -66,6 +67,7 @@ constructor( configRulesExecutor = configRulesExecutor, fhirPathDataExtractor = fhirPathDataExtractor, parser = parser, + context = context, ) { /** diff --git a/android/quest/src/main/java/org/smartregister/fhircore/quest/event/AppEvent.kt b/android/quest/src/main/java/org/smartregister/fhircore/quest/event/AppEvent.kt index 0a6e8de54d..ef04e7acac 100644 --- a/android/quest/src/main/java/org/smartregister/fhircore/quest/event/AppEvent.kt +++ b/android/quest/src/main/java/org/smartregister/fhircore/quest/event/AppEvent.kt @@ -21,4 +21,6 @@ import org.smartregister.fhircore.quest.ui.shared.models.QuestionnaireSubmission sealed class AppEvent { data class OnSubmitQuestionnaire(val questionnaireSubmission: QuestionnaireSubmission) : AppEvent() + + data object RefreshRegisterData : AppEvent() } diff --git a/android/quest/src/main/java/org/smartregister/fhircore/quest/ui/launcher/GeoWidgetLauncherViewModel.kt b/android/quest/src/main/java/org/smartregister/fhircore/quest/ui/launcher/GeoWidgetLauncherViewModel.kt index 82dad32074..1808310f5b 100644 --- a/android/quest/src/main/java/org/smartregister/fhircore/quest/ui/launcher/GeoWidgetLauncherViewModel.kt +++ b/android/quest/src/main/java/org/smartregister/fhircore/quest/ui/launcher/GeoWidgetLauncherViewModel.kt @@ -79,6 +79,7 @@ constructor( fhirResourceConfig = geoWidgetConfig.resourceConfig, configRules = null, secondaryResourceConfigs = null, + filterByRelatedEntityLocationMetaTag = false, ) repositoryResourceDataList.forEach { repositoryResourceData -> diff --git a/android/quest/src/main/java/org/smartregister/fhircore/quest/ui/main/AppMainActivity.kt b/android/quest/src/main/java/org/smartregister/fhircore/quest/ui/main/AppMainActivity.kt index 19fe388075..f7b1b91067 100644 --- a/android/quest/src/main/java/org/smartregister/fhircore/quest/ui/main/AppMainActivity.kt +++ b/android/quest/src/main/java/org/smartregister/fhircore/quest/ui/main/AppMainActivity.kt @@ -42,6 +42,7 @@ import java.time.Instant import javax.inject.Inject import kotlinx.coroutines.flow.firstOrNull import kotlinx.coroutines.launch +import kotlinx.coroutines.runBlocking import org.hl7.fhir.r4.model.IdType import org.hl7.fhir.r4.model.QuestionnaireResponse import org.smartregister.fhircore.engine.configuration.QuestionnaireConfig @@ -132,28 +133,26 @@ open class AppMainActivity : BaseMultiLanguageActivity(), QuestionnaireHandler, // Setup the drawer and schedule jobs appMainViewModel.run { - lifecycleScope.launch { - retrieveAppMainUiState() - if (isDeviceOnline()) { - // Do not schedule sync until location selected when strategy is RelatedEntityLocation - // Use applicationConfiguration.usePractitionerAssignedLocationOnSync to identify - // if we need to trigger sync based on assigned locations or not - if (applicationConfiguration.syncStrategy.contains(SyncStrategy.RelatedEntityLocation)) { - if ( - applicationConfiguration.usePractitionerAssignedLocationOnSync || - syncLocationIdsProtoStore.data.firstOrNull()?.isNotEmpty() == true - ) { - triggerSync() - } - } else { + retrieveAppMainUiState() + if (isDeviceOnline()) { + // Do not schedule sync until location selected when strategy is RelatedEntityLocation + // Use applicationConfiguration.usePractitionerAssignedLocationOnSync to identify + // if we need to trigger sync based on assigned locations or not + if (applicationConfiguration.syncStrategy.contains(SyncStrategy.RelatedEntityLocation)) { + if ( + applicationConfiguration.usePractitionerAssignedLocationOnSync || + runBlocking { syncLocationIdsProtoStore.data.firstOrNull() }?.isNotEmpty() == true + ) { triggerSync() } } else { - showToast( - getString(org.smartregister.fhircore.engine.R.string.sync_failed), - Toast.LENGTH_LONG, - ) + triggerSync() } + } else { + showToast( + getString(org.smartregister.fhircore.engine.R.string.sync_failed), + Toast.LENGTH_LONG, + ) } schedulePeriodicJobs() } diff --git a/android/quest/src/main/java/org/smartregister/fhircore/quest/ui/main/AppMainViewModel.kt b/android/quest/src/main/java/org/smartregister/fhircore/quest/ui/main/AppMainViewModel.kt index 2899523ebd..3d58722e11 100644 --- a/android/quest/src/main/java/org/smartregister/fhircore/quest/ui/main/AppMainViewModel.kt +++ b/android/quest/src/main/java/org/smartregister/fhircore/quest/ui/main/AppMainViewModel.kt @@ -16,7 +16,6 @@ package org.smartregister.fhircore.quest.ui.main -import android.content.Context import android.widget.Toast import androidx.compose.runtime.MutableState import androidx.compose.runtime.mutableStateMapOf @@ -25,7 +24,6 @@ import androidx.compose.runtime.snapshots.SnapshotStateMap import androidx.core.os.bundleOf import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope -import androidx.navigation.NavController import androidx.work.WorkManager import androidx.work.workDataOf import com.google.android.fhir.sync.CurrentSyncJobStatus @@ -39,24 +37,18 @@ import javax.inject.Inject import kotlin.time.Duration import kotlinx.coroutines.launch import kotlinx.coroutines.withContext -import org.hl7.fhir.r4.model.Enumerations import org.hl7.fhir.r4.model.QuestionnaireResponse -import org.hl7.fhir.r4.model.ResourceType import org.hl7.fhir.r4.model.Task import org.smartregister.fhircore.engine.R import org.smartregister.fhircore.engine.configuration.ConfigType import org.smartregister.fhircore.engine.configuration.ConfigurationRegistry -import org.smartregister.fhircore.engine.configuration.QuestionnaireConfig import org.smartregister.fhircore.engine.configuration.app.ApplicationConfiguration -import org.smartregister.fhircore.engine.configuration.geowidget.GeoWidgetConfiguration import org.smartregister.fhircore.engine.configuration.navigation.ICON_TYPE_REMOTE import org.smartregister.fhircore.engine.configuration.navigation.NavigationConfiguration import org.smartregister.fhircore.engine.configuration.navigation.NavigationMenuConfig import org.smartregister.fhircore.engine.configuration.report.measure.MeasureReportConfiguration import org.smartregister.fhircore.engine.configuration.workflow.ActionTrigger import org.smartregister.fhircore.engine.data.local.register.RegisterRepository -import org.smartregister.fhircore.engine.domain.model.ActionParameter -import org.smartregister.fhircore.engine.domain.model.ActionParameterType import org.smartregister.fhircore.engine.sync.SyncBroadcaster import org.smartregister.fhircore.engine.task.FhirCarePlanGenerator import org.smartregister.fhircore.engine.task.FhirCompleteCarePlanWorker @@ -78,7 +70,6 @@ import org.smartregister.fhircore.engine.util.extension.tryParse import org.smartregister.fhircore.quest.navigation.MainNavigationScreen import org.smartregister.fhircore.quest.navigation.NavigationArg import org.smartregister.fhircore.quest.ui.report.measure.worker.MeasureReportMonthPeriodWorker -import org.smartregister.fhircore.quest.ui.shared.QuestionnaireHandler import org.smartregister.fhircore.quest.ui.shared.models.QuestionnaireSubmission import org.smartregister.fhircore.quest.util.extensions.decodeBinaryResourcesToBitmap import org.smartregister.fhircore.quest.util.extensions.handleClickEvent @@ -107,9 +98,6 @@ constructor( ), ) - private val simpleDateFormat = SimpleDateFormat(SYNC_TIMESTAMP_OUTPUT_FORMAT, Locale.getDefault()) - private val registerCountMap: SnapshotStateMap = mutableStateMapOf() - val applicationConfiguration: ApplicationConfiguration by lazy { configurationRegistry.retrieveConfiguration(ConfigType.Application, paramsMap = emptyMap()) } @@ -121,6 +109,8 @@ constructor( private val measureReportConfigurations: List by lazy { configurationRegistry.retrieveConfigurations(ConfigType.MeasureReport) } + private val simpleDateFormat = SimpleDateFormat(SYNC_TIMESTAMP_OUTPUT_FORMAT, Locale.getDefault()) + private val registerCountMap: SnapshotStateMap = mutableStateMapOf() fun retrieveIconsAsBitmap() { navigationConfiguration.clientRegisters @@ -133,7 +123,7 @@ constructor( .decodeBinaryResourcesToBitmap(viewModelScope, registerRepository) } - suspend fun retrieveAppMainUiState(refreshAll: Boolean = true) { + fun retrieveAppMainUiState(refreshAll: Boolean = true) { if (refreshAll) { appMainUiState.value = appMainUiStateOf( @@ -147,7 +137,10 @@ constructor( ) } - // Count data for configured registers by populating the register count map + countRegisterData() + } + + fun countRegisterData() { viewModelScope.launch { navigationConfiguration.run { clientRegisters.countRegisterData() @@ -179,7 +172,7 @@ constructor( SharedPreferenceKey.LAST_SYNC_TIMESTAMP.name, formatLastSyncTimestamp(event.state.timestamp), ) - viewModelScope.launch { retrieveAppMainUiState() } + retrieveAppMainUiState() } } is AppMainEvent.TriggerWorkflow -> @@ -214,31 +207,6 @@ constructor( } } - fun launchFamilyRegistrationWithLocationId( - context: Context, - locationId: String, - questionnaireConfig: QuestionnaireConfig, - ) { - viewModelScope.launch { - val prePopulateLocationIdParameter = - ActionParameter( - key = "locationId", - paramType = ActionParameterType.PREPOPULATE, - dataType = Enumerations.DataType.STRING, - resourceType = ResourceType.Location, - value = locationId, - linkId = "household-location-reference", - ) - if (context is QuestionnaireHandler) { - context.launchQuestionnaire( - context = context, - questionnaireConfig = questionnaireConfig, - actionParams = listOf(prePopulateLocationIdParameter), - ) - } - } - } - private suspend fun List.countRegisterData() { // Set count for registerId against its value. Use action Id; otherwise default to menu id return this.filter { it.showCount } @@ -271,26 +239,6 @@ constructor( fun retrieveLastSyncTimestamp(): String? = sharedPreferencesHelper.read(SharedPreferenceKey.LAST_SYNC_TIMESTAMP.name, null) - fun launchProfileFromGeoWidget( - navController: NavController, - geoWidgetConfigId: String, - resourceId: String, - ) { - val geoWidgetConfiguration = - configurationRegistry.retrieveConfiguration( - ConfigType.GeoWidget, - geoWidgetConfigId, - ) - onEvent( - AppMainEvent.OpenProfile( - navController = navController, - profileId = geoWidgetConfiguration.profileId, - resourceId = resourceId, - resourceConfig = geoWidgetConfiguration.resourceConfig, - ), - ) - } - /** This function is used to schedule tasks that are intended to run periodically */ fun schedulePeriodicJobs() { workManager.run { diff --git a/android/quest/src/main/java/org/smartregister/fhircore/quest/ui/multiselect/MultiSelectBottomSheetFragment.kt b/android/quest/src/main/java/org/smartregister/fhircore/quest/ui/multiselect/MultiSelectBottomSheetFragment.kt index ab2928ff86..066f74acb7 100644 --- a/android/quest/src/main/java/org/smartregister/fhircore/quest/ui/multiselect/MultiSelectBottomSheetFragment.kt +++ b/android/quest/src/main/java/org/smartregister/fhircore/quest/ui/multiselect/MultiSelectBottomSheetFragment.kt @@ -25,43 +25,52 @@ import androidx.compose.runtime.livedata.observeAsState import androidx.compose.ui.platform.ComposeView import androidx.fragment.app.activityViewModels import androidx.fragment.app.viewModels +import androidx.lifecycle.lifecycleScope import androidx.navigation.fragment.navArgs import com.google.android.material.bottomsheet.BottomSheetDialogFragment import dagger.hilt.android.AndroidEntryPoint +import javax.inject.Inject +import kotlinx.coroutines.launch import org.smartregister.fhircore.engine.ui.theme.AppTheme import org.smartregister.fhircore.engine.util.extension.isDeviceOnline import org.smartregister.fhircore.engine.util.extension.showToast +import org.smartregister.fhircore.quest.event.AppEvent +import org.smartregister.fhircore.quest.event.EventBus import org.smartregister.fhircore.quest.ui.main.AppMainViewModel @AndroidEntryPoint class MultiSelectBottomSheetFragment() : BottomSheetDialogFragment() { + @Inject lateinit var eventBus: EventBus val bottomSheetArgs by navArgs() val multiSelectViewModel by viewModels() private val appMainViewModel by activityViewModels() override fun onViewCreated(view: View, savedInstanceState: Bundle?) { isCancelable = false - val multiSelectViewConfig = bottomSheetArgs.multiSelectViewConfig + val multiSelectViewConfig = bottomSheetArgs?.multiSelectViewConfig if (multiSelectViewConfig != null) { multiSelectViewModel.populateLookupMap(requireContext(), multiSelectViewConfig) } } private fun onSelectionDone() { - multiSelectViewModel.saveSelectedLocations(requireContext()) - appMainViewModel.run { - if (requireContext().isDeviceOnline()) { - triggerSync() - } else { - requireContext() - .showToast( - getString(org.smartregister.fhircore.engine.R.string.sync_failed), - Toast.LENGTH_LONG, - ) + lifecycleScope.launch { + multiSelectViewModel.saveSelectedLocations(requireContext()) + appMainViewModel.run { + if (requireContext().isDeviceOnline()) { + triggerSync() + } else { + requireContext() + .showToast( + getString(org.smartregister.fhircore.engine.R.string.sync_failed), + Toast.LENGTH_LONG, + ) + eventBus.triggerEvent(AppEvent.RefreshRegisterData) + } } + dismiss() } - dismiss() } override fun onCreateView( diff --git a/android/quest/src/main/java/org/smartregister/fhircore/quest/ui/multiselect/MultiSelectViewModel.kt b/android/quest/src/main/java/org/smartregister/fhircore/quest/ui/multiselect/MultiSelectViewModel.kt index 1c2f5a8f95..279aa8bbc5 100644 --- a/android/quest/src/main/java/org/smartregister/fhircore/quest/ui/multiselect/MultiSelectViewModel.kt +++ b/android/quest/src/main/java/org/smartregister/fhircore/quest/ui/multiselect/MultiSelectViewModel.kt @@ -66,6 +66,7 @@ constructor( val resourcesMap = defaultRepository .searchResourcesRecursively( + filterByRelatedEntityLocationMetaTag = false, fhirResourceConfig = multiSelectViewConfig.resourceConfig, filterActiveResources = null, secondaryResourceConfigs = null, @@ -140,11 +141,9 @@ constructor( } } - fun saveSelectedLocations(context: Context) { - viewModelScope.launch { - context.syncLocationIdsProtoStore.updateData { - selectedNodes.map { SyncLocationToggleableState(it.key, it.value) } - } + suspend fun saveSelectedLocations(context: Context) { + context.syncLocationIdsProtoStore.updateData { + selectedNodes.map { SyncLocationToggleableState(it.key, it.value) } } } diff --git a/android/quest/src/main/java/org/smartregister/fhircore/quest/ui/register/RegisterFragment.kt b/android/quest/src/main/java/org/smartregister/fhircore/quest/ui/register/RegisterFragment.kt index e6fa96f21d..5a289f6565 100644 --- a/android/quest/src/main/java/org/smartregister/fhircore/quest/ui/register/RegisterFragment.kt +++ b/android/quest/src/main/java/org/smartregister/fhircore/quest/ui/register/RegisterFragment.kt @@ -262,8 +262,13 @@ class RegisterFragment : Fragment(), OnSyncListener { eventBus.events .getFor(MainNavigationScreen.Home.eventId(registerFragmentArgs.registerId)) .onEach { appEvent -> - if (appEvent is AppEvent.OnSubmitQuestionnaire) { - handleQuestionnaireSubmission(appEvent.questionnaireSubmission) + when (appEvent) { + is AppEvent.OnSubmitQuestionnaire -> + handleQuestionnaireSubmission(appEvent.questionnaireSubmission) + is AppEvent.RefreshRegisterData -> { + appMainViewModel.countRegisterData() + refreshRegisterData() + } } } .launchIn(lifecycleScope) diff --git a/android/quest/src/test/java/org/smartregister/fhircore/quest/data/report/measure/MeasureReportPagingSourceTest.kt b/android/quest/src/test/java/org/smartregister/fhircore/quest/data/report/measure/MeasureReportPagingSourceTest.kt index 6c8748df5c..07a77032f2 100644 --- a/android/quest/src/test/java/org/smartregister/fhircore/quest/data/report/measure/MeasureReportPagingSourceTest.kt +++ b/android/quest/src/test/java/org/smartregister/fhircore/quest/data/report/measure/MeasureReportPagingSourceTest.kt @@ -107,6 +107,7 @@ class MeasureReportPagingSourceTest : RobolectricTest() { configRulesExecutor = mockk(), fhirPathDataExtractor = fhirPathDataExtractor, parser = parser, + context = ApplicationProvider.getApplicationContext(), ), ) diff --git a/android/quest/src/test/java/org/smartregister/fhircore/quest/data/report/measure/MeasureReportRepositoryTest.kt b/android/quest/src/test/java/org/smartregister/fhircore/quest/data/report/measure/MeasureReportRepositoryTest.kt index f42b5ec782..249c601e02 100644 --- a/android/quest/src/test/java/org/smartregister/fhircore/quest/data/report/measure/MeasureReportRepositoryTest.kt +++ b/android/quest/src/test/java/org/smartregister/fhircore/quest/data/report/measure/MeasureReportRepositoryTest.kt @@ -113,22 +113,23 @@ class MeasureReportRepositoryTest : RobolectricTest() { configRulesExecutor = mockk(), fhirPathDataExtractor = mockk(), parser = parser, + context = ApplicationProvider.getApplicationContext(), ), ) measureReportRepository = MeasureReportRepository( - fhirEngine, - DefaultDispatcherProvider(), - mockk(), - configurationRegistry, - mockk(), - mockk(), - registerRepository, - fhirOperator, - knowledgeManager, - mockk(), - parser, + fhirEngine = fhirEngine, + dispatcherProvider = DefaultDispatcherProvider(), + sharedPreferencesHelper = mockk(), + configurationRegistry = configurationRegistry, + configService = mockk(), + configRulesExecutor = mockk(), + fhirOperator = fhirOperator, + knowledgeManager = knowledgeManager, + fhirPathDataExtractor = mockk(), + parser = parser, + context = ApplicationProvider.getApplicationContext(), ) } diff --git a/android/quest/src/test/java/org/smartregister/fhircore/quest/ui/profile/ProfileViewModelTest.kt b/android/quest/src/test/java/org/smartregister/fhircore/quest/ui/profile/ProfileViewModelTest.kt index 31474d7eb8..69421858fd 100644 --- a/android/quest/src/test/java/org/smartregister/fhircore/quest/ui/profile/ProfileViewModelTest.kt +++ b/android/quest/src/test/java/org/smartregister/fhircore/quest/ui/profile/ProfileViewModelTest.kt @@ -106,6 +106,7 @@ class ProfileViewModelTest : RobolectricTest() { configRulesExecutor = mockk(), fhirPathDataExtractor = mockk(), parser = parser, + context = ApplicationProvider.getApplicationContext(), ), ) coEvery { diff --git a/android/quest/src/test/java/org/smartregister/fhircore/quest/ui/questionnaire/QuestionnaireViewModelTest.kt b/android/quest/src/test/java/org/smartregister/fhircore/quest/ui/questionnaire/QuestionnaireViewModelTest.kt index 8b014ba0f4..28d147f2a5 100644 --- a/android/quest/src/test/java/org/smartregister/fhircore/quest/ui/questionnaire/QuestionnaireViewModelTest.kt +++ b/android/quest/src/test/java/org/smartregister/fhircore/quest/ui/questionnaire/QuestionnaireViewModelTest.kt @@ -172,6 +172,7 @@ class QuestionnaireViewModelTest : RobolectricTest() { configRulesExecutor = configRulesExecutor, fhirPathDataExtractor = fhirPathDataExtractor, parser = parser, + context = context, ), ) diff --git a/docs/engineering/app/configuring/config-types/register.mdx b/docs/engineering/app/configuring/config-types/register.mdx index d15d22fdd3..941f0c9869 100644 --- a/docs/engineering/app/configuring/config-types/register.mdx +++ b/docs/engineering/app/configuring/config-types/register.mdx @@ -71,6 +71,9 @@ Below is a sample dataQuery config to filter register data by configRules `activeResourceFilters` | List of `ActiveResourceFilterConfig`s | Yes | `listOf(ActiveResourceFilterConfig(resourceType = ResourceType.Patient, active = true), ActiveResourceFilterConfig(resourceType = ResourceType.Group, active = true))` | `configRules` | List of `RuleConfig`s | No | `null` | `registerFilter` | `RegisterFilterConfig` | No | `null` | +`topScreenSection` | Optional configuration for register screen toolbar | `No` | `null` | +`filterDataByRelatedEntityLocation` | Configuration that indicates whether to filter register data with Related Entity Location meta tag | `No` | `false` | +