diff --git a/app/src/main/java/org/dhis2/data/forms/EnrollmentFormRepository.kt b/app/src/main/java/org/dhis2/data/forms/EnrollmentFormRepository.kt deleted file mode 100644 index a97016ff3e..0000000000 --- a/app/src/main/java/org/dhis2/data/forms/EnrollmentFormRepository.kt +++ /dev/null @@ -1,92 +0,0 @@ -package org.dhis2.data.forms - -import io.reactivex.Flowable -import io.reactivex.Single -import io.reactivex.schedulers.Schedulers -import org.dhis2.commons.rules.RuleEngineContextData -import org.dhis2.form.data.RulesRepository -import org.hisp.dhis.android.core.D2 -import org.hisp.dhis.rules.api.RuleEngineContext - -class EnrollmentFormRepository( - private val rulesRepository: RulesRepository, - private val enrollmentUid: String, - private val d2: D2, -) : FormRepository { - private var cachedRuleEngineFlowable: Flowable - private var enrollmentOrgUnitUid: String? = null - - init { - enrollmentOrgUnitUid = if (enrollmentUid.isNotEmpty()) { - d2.enrollmentModule().enrollments().uid(enrollmentUid).blockingGet()!! - .organisationUnit() - } else { - "" - } - // We don't want to rebuild RuleEngine on each request, since metadata of - // the event is not changing throughout lifecycle of FormComponent. - cachedRuleEngineFlowable = enrollmentProgram() - .switchMap { program -> - Single.zip( - rulesRepository.rulesNew(program, null).subscribeOn(Schedulers.io()), - rulesRepository.ruleVariables(program).subscribeOn(Schedulers.io()), - rulesRepository.enrollmentEvents(enrollmentUid).subscribeOn(Schedulers.io()), - rulesRepository.queryConstants().subscribeOn(Schedulers.io()), - rulesRepository.supplementaryData(enrollmentOrgUnitUid!!) - .subscribeOn(Schedulers.io()), - ) { rules, variables, events, constants, supplementaryData -> - - val ruleEngineContext = RuleEngineContext( - rules, - variables, - supplementaryData, - constants, - ) - RuleEngineContextData( - ruleEngineContext = ruleEngineContext, - ruleEnrollment = null, - ruleEvents = events, - ) - }.toFlowable() - } - .cacheWithInitialCapacity(1) - } - - override fun restartRuleEngine(): Flowable { - val orgUnit = d2.enrollmentModule().enrollments().uid(enrollmentUid).blockingGet()!! - .organisationUnit() - return enrollmentProgram() - .switchMap { program -> - Single.zip( - rulesRepository.rulesNew(program, null), - rulesRepository.ruleVariables(program), - rulesRepository.enrollmentEvents(enrollmentUid), - rulesRepository.queryConstants(), - rulesRepository.supplementaryData(orgUnit!!), - ) { rules, variables, events, constants, supplementaryData -> - val ruleEngineContext = RuleEngineContext( - rules, - variables, - supplementaryData, - constants, - ) - RuleEngineContextData( - ruleEngineContext = ruleEngineContext, - ruleEnrollment = null, - ruleEvents = events, - ) - }.toFlowable() - } - .cacheWithInitialCapacity(1).also { cachedRuleEngineFlowable = it } - } - - override fun ruleEngine(): Flowable { - return cachedRuleEngineFlowable - } - - private fun enrollmentProgram(): Flowable { - return d2.enrollmentModule().enrollments().uid(enrollmentUid).get() - .map { it.program()!! } - .toFlowable() - } -} diff --git a/app/src/main/java/org/dhis2/data/forms/EventRepository.java b/app/src/main/java/org/dhis2/data/forms/EventRepository.java deleted file mode 100644 index ff5e99b0fa..0000000000 --- a/app/src/main/java/org/dhis2/data/forms/EventRepository.java +++ /dev/null @@ -1,98 +0,0 @@ -package org.dhis2.data.forms; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -import org.dhis2.commons.rules.RuleEngineContextData; -import org.dhis2.form.data.RulesRepository; -import org.hisp.dhis.android.core.D2; -import org.hisp.dhis.rules.api.RuleEngineContext; - -import io.reactivex.Flowable; -import io.reactivex.Single; - -public class EventRepository implements FormRepository { - - private final String programUid; - private final String orgUnit; - - @NonNull - private Flowable cachedRuleEngineFlowable; - - private RuleEngineContextData ruleEngineContextData = null; - - @Nullable - private final String eventUid; - private final RulesRepository rulesRepository; - - public EventRepository( - @NonNull RulesRepository rulesRepository, - @Nullable String eventUid, - @NonNull D2 d2) { - this.eventUid = eventUid != null ? eventUid : ""; - this.rulesRepository = rulesRepository; - this.programUid = eventUid != null ? d2.eventModule().events().uid(eventUid).blockingGet().program() : ""; - this.orgUnit = !this.eventUid.isEmpty() ? d2.eventModule().events().uid(eventUid).blockingGet().organisationUnit() : ""; - // We don't want to rebuild RuleEngine on each request, since metadata of - // the event is not changing throughout lifecycle of FormComponent. - this.cachedRuleEngineFlowable = Single.zip( - rulesRepository.rulesNew(programUid, eventUid), - rulesRepository.ruleVariables(programUid), - rulesRepository.otherEvents(this.eventUid), - rulesRepository.enrollment(this.eventUid), - rulesRepository.queryConstants(), - rulesRepository.supplementaryData(orgUnit), - (rules, variables, events, enrollment, constants, supplementaryData) -> { - RuleEngineContext ruleEngineContext = new RuleEngineContext( - rules, - variables, - supplementaryData, - constants - ); - - return new RuleEngineContextData( - ruleEngineContext, - enrollment.getEnrollment().isEmpty() ? null : enrollment, - events - ); - }) - .doOnSuccess(contextData -> this.ruleEngineContextData = contextData) - .toFlowable() - .cacheWithInitialCapacity(1); - } - - - @Override - public Flowable restartRuleEngine() { - return this.cachedRuleEngineFlowable = Single.zip( - rulesRepository.rulesNew(programUid, eventUid), - rulesRepository.ruleVariables(programUid), - rulesRepository.otherEvents(this.eventUid), - rulesRepository.enrollment(this.eventUid), - rulesRepository.queryConstants(), - rulesRepository.supplementaryData(orgUnit), - (rules, variables, events, enrollment, constants, supplementaryData) -> { - RuleEngineContext ruleEngineContext = new RuleEngineContext( - rules, - variables, - supplementaryData, - constants - ); - - return new RuleEngineContextData( - ruleEngineContext, - enrollment.getEnrollment().isEmpty() ? null : enrollment, - events - ); - }) - .doOnSuccess(contextData -> this.ruleEngineContextData = contextData) - .toFlowable() - .cacheWithInitialCapacity(1); - } - - @NonNull - @Override - public Flowable ruleEngine() { - return ruleEngineContextData != null ? Flowable.just(ruleEngineContextData) : cachedRuleEngineFlowable; - } -} \ No newline at end of file diff --git a/app/src/main/java/org/dhis2/data/forms/FormRepository.java b/app/src/main/java/org/dhis2/data/forms/FormRepository.java deleted file mode 100644 index 78425ea42f..0000000000 --- a/app/src/main/java/org/dhis2/data/forms/FormRepository.java +++ /dev/null @@ -1,16 +0,0 @@ -package org.dhis2.data.forms; - -import androidx.annotation.NonNull; - -import org.dhis2.commons.rules.RuleEngineContextData; - -import io.reactivex.Flowable; - -public interface FormRepository { - - Flowable restartRuleEngine(); - - @NonNull - Flowable ruleEngine(); - -} \ No newline at end of file diff --git a/app/src/main/java/org/dhis2/usescases/eventsWithoutRegistration/eventCapture/EventCaptureModule.java b/app/src/main/java/org/dhis2/usescases/eventsWithoutRegistration/eventCapture/EventCaptureModule.java index cfc80799f2..6c699556c1 100644 --- a/app/src/main/java/org/dhis2/usescases/eventsWithoutRegistration/eventCapture/EventCaptureModule.java +++ b/app/src/main/java/org/dhis2/usescases/eventsWithoutRegistration/eventCapture/EventCaptureModule.java @@ -14,15 +14,12 @@ import org.dhis2.commons.resources.ResourceManager; import org.dhis2.commons.schedulers.SchedulerProvider; import org.dhis2.data.dhislogic.DhisEnrollmentUtils; -import org.dhis2.data.forms.EventRepository; -import org.dhis2.data.forms.FormRepository; import org.dhis2.data.forms.dataentry.SearchTEIRepository; import org.dhis2.data.forms.dataentry.SearchTEIRepositoryImpl; import org.dhis2.mobileProgramRules.EvaluationType; import org.dhis2.mobileProgramRules.RuleEngineHelper; import org.dhis2.form.data.FileController; import org.dhis2.form.data.FormValueStore; -import org.dhis2.form.data.RulesRepository; import org.dhis2.form.data.UniqueAttributeController; import org.dhis2.form.model.RowAction; import org.dhis2.form.ui.FieldViewModelFactory; @@ -77,12 +74,6 @@ EventCaptureContract.EventCaptureRepository provideRepository(D2 d2) { return new EventCaptureRepositoryImpl(eventUid, d2); } - @Provides - @PerActivity - RulesRepository rulesRepository(@NonNull D2 d2) { - return new RulesRepository(d2); - } - @Provides @PerActivity RuleEngineHelper ruleEngineRepository(D2 d2) { @@ -93,13 +84,6 @@ RuleEngineHelper ruleEngineRepository(D2 d2) { ); } - @Provides - @PerActivity - FormRepository formRepository(@NonNull RulesRepository rulesRepository, - @NonNull D2 d2) { - return new EventRepository(rulesRepository, eventUid, d2); - } - @Provides @PerActivity FormValueStore valueStore( diff --git a/app/src/main/java/org/dhis2/usescases/eventsWithoutRegistration/eventInitial/EventInitialModule.java b/app/src/main/java/org/dhis2/usescases/eventsWithoutRegistration/eventInitial/EventInitialModule.java index 949159bca4..9e9462ae0e 100644 --- a/app/src/main/java/org/dhis2/usescases/eventsWithoutRegistration/eventInitial/EventInitialModule.java +++ b/app/src/main/java/org/dhis2/usescases/eventsWithoutRegistration/eventInitial/EventInitialModule.java @@ -15,9 +15,6 @@ import org.dhis2.commons.resources.DhisPeriodUtils; import org.dhis2.commons.resources.ResourceManager; import org.dhis2.commons.schedulers.SchedulerProvider; -import org.dhis2.data.forms.EventRepository; -import org.dhis2.data.forms.FormRepository; -import org.dhis2.form.data.RulesRepository; import org.dhis2.form.data.RulesUtilsProvider; import org.dhis2.form.data.metadata.FileResourceConfiguration; import org.dhis2.form.data.metadata.OptionSetConfiguration; @@ -118,17 +115,6 @@ FieldViewModelFactory fieldFactory( ); } - @Provides - FormRepository formRepository(@NonNull RulesRepository rulesRepository, - @NonNull D2 d2) { - return new EventRepository(rulesRepository, eventUid, d2); - } - - @Provides - RulesRepository rulesRepository(@NonNull D2 d2) { - return new RulesRepository(d2); - } - @Provides @PerActivity EventInitialRepository eventDetailRepository( diff --git a/app/src/main/java/org/dhis2/usescases/teiDashboard/TeiDashboardModule.kt b/app/src/main/java/org/dhis2/usescases/teiDashboard/TeiDashboardModule.kt index 617c21cfc2..cc085f13ad 100644 --- a/app/src/main/java/org/dhis2/usescases/teiDashboard/TeiDashboardModule.kt +++ b/app/src/main/java/org/dhis2/usescases/teiDashboard/TeiDashboardModule.kt @@ -9,9 +9,6 @@ import org.dhis2.commons.prefs.PreferenceProvider import org.dhis2.commons.resources.MetadataIconProvider import org.dhis2.commons.schedulers.SchedulerProvider import org.dhis2.commons.viewmodel.DispatcherProvider -import org.dhis2.data.forms.EnrollmentFormRepository -import org.dhis2.data.forms.FormRepository -import org.dhis2.form.data.RulesRepository import org.dhis2.mobileProgramRules.EvaluationType import org.dhis2.mobileProgramRules.RuleEngineHelper import org.dhis2.utils.analytics.AnalyticsHelper @@ -73,26 +70,6 @@ class TeiDashboardModule( ) } - @Provides - @PerActivity - fun rulesRepository(d2: D2): RulesRepository { - return RulesRepository(d2) - } - - @Provides - @PerActivity - fun formRepository( - rulesRepository: RulesRepository, - d2: D2, - ): FormRepository { - val enrollmentUidToUse = enrollmentUid ?: "" - return EnrollmentFormRepository( - rulesRepository, - enrollmentUidToUse, - d2, - ) - } - @Provides @PerActivity fun ruleEngineRepository( diff --git a/app/src/main/java/org/dhis2/usescases/troubleshooting/TroubleshootingRepository.kt b/app/src/main/java/org/dhis2/usescases/troubleshooting/TroubleshootingRepository.kt index f7b881d9cf..6a1771468a 100644 --- a/app/src/main/java/org/dhis2/usescases/troubleshooting/TroubleshootingRepository.kt +++ b/app/src/main/java/org/dhis2/usescases/troubleshooting/TroubleshootingRepository.kt @@ -1,8 +1,8 @@ package org.dhis2.usescases.troubleshooting import org.dhis2.commons.resources.MetadataIconProvider -import org.dhis2.form.bindings.toRuleEngineObject -import org.dhis2.form.bindings.toRuleVariableList +import org.dhis2.mobileProgramRules.toRuleEngineObject +import org.dhis2.mobileProgramRules.toRuleVariableList import org.dhis2.usescases.development.ProgramRuleValidation import org.dhis2.usescases.development.RuleValidation import org.hisp.dhis.android.core.D2 diff --git a/app/src/test/java/org/dhis2/data/forms/RulesRepositoryTest.kt b/app/src/test/java/org/dhis2/data/forms/RulesRepositoryTest.kt index dd70f99a31..2036da7924 100644 --- a/app/src/test/java/org/dhis2/data/forms/RulesRepositoryTest.kt +++ b/app/src/test/java/org/dhis2/data/forms/RulesRepositoryTest.kt @@ -1,6 +1,5 @@ package org.dhis2.data.forms -import org.dhis2.form.data.RulesRepository import org.hisp.dhis.android.core.D2 import org.hisp.dhis.android.core.organisationunit.OrganisationUnit import org.hisp.dhis.android.core.organisationunit.OrganisationUnitGroup diff --git a/commons/src/main/java/org/dhis2/commons/rules/RuleEngineExtensions.kt b/commons/src/main/java/org/dhis2/commons/rules/RuleEngineExtensions.kt deleted file mode 100644 index 8a1ea6b4ca..0000000000 --- a/commons/src/main/java/org/dhis2/commons/rules/RuleEngineExtensions.kt +++ /dev/null @@ -1,12 +0,0 @@ -package org.dhis2.commons.rules - -import kotlinx.datetime.Instant -import kotlinx.datetime.TimeZone -import kotlinx.datetime.toLocalDateTime -import java.util.Date - -fun Date.toRuleEngineInstant() = - Instant.fromEpochMilliseconds(this.time) - -fun Date.toRuleEngineLocalDate() = - toRuleEngineInstant().toLocalDateTime(TimeZone.currentSystemDefault()).date diff --git a/dhis2-mobile-program-rules/build.gradle.kts b/dhis2-mobile-program-rules/build.gradle.kts index 89845ee924..a43e52b776 100644 --- a/dhis2-mobile-program-rules/build.gradle.kts +++ b/dhis2-mobile-program-rules/build.gradle.kts @@ -27,15 +27,18 @@ android { } compileOptions { isCoreLibraryDesugaringEnabled = true - sourceCompatibility = JavaVersion.VERSION_1_8 - targetCompatibility = JavaVersion.VERSION_1_8 + sourceCompatibility = JavaVersion.VERSION_17 + targetCompatibility = JavaVersion.VERSION_17 } kotlinOptions { - jvmTarget = "1.8" + jvmTarget = "17" } } dependencies { implementation(project(":commons")) + testImplementation(libs.test.mockitoCore) + testImplementation(libs.test.mockitoInline) + testImplementation(libs.test.mockitoKotlin) coreLibraryDesugaring(libs.desugar) } \ No newline at end of file diff --git a/dhis2-mobile-program-rules/src/main/java/org/dhis2/mobileProgramRules/RuleEngineExtensions.kt b/dhis2-mobile-program-rules/src/main/java/org/dhis2/mobileProgramRules/RuleEngineExtensions.kt index c521196cd4..fb17dd50e7 100644 --- a/dhis2-mobile-program-rules/src/main/java/org/dhis2/mobileProgramRules/RuleEngineExtensions.kt +++ b/dhis2-mobile-program-rules/src/main/java/org/dhis2/mobileProgramRules/RuleEngineExtensions.kt @@ -3,7 +3,6 @@ package org.dhis2.mobileProgramRules import kotlinx.datetime.Instant import kotlinx.datetime.TimeZone import kotlinx.datetime.toLocalDateTime -import org.dhis2.commons.rules.toRuleEngineInstant import org.hisp.dhis.android.core.D2 import org.hisp.dhis.android.core.common.ValueType import org.hisp.dhis.android.core.dataelement.DataElementCollectionRepository diff --git a/dhis2-mobile-program-rules/src/main/java/org/dhis2/mobileProgramRules/RulesRepository.kt b/dhis2-mobile-program-rules/src/main/java/org/dhis2/mobileProgramRules/RulesRepository.kt index 73e75d0c98..8caa9372b2 100644 --- a/dhis2-mobile-program-rules/src/main/java/org/dhis2/mobileProgramRules/RulesRepository.kt +++ b/dhis2-mobile-program-rules/src/main/java/org/dhis2/mobileProgramRules/RulesRepository.kt @@ -11,8 +11,6 @@ import org.dhis2.commons.bindings.event import org.dhis2.commons.bindings.organisationUnit import org.dhis2.commons.bindings.program import org.dhis2.commons.bindings.programStage -import org.dhis2.commons.rules.toRuleEngineInstant -import org.dhis2.commons.rules.toRuleEngineLocalDate import org.hisp.dhis.android.core.D2 import org.hisp.dhis.android.core.arch.helpers.UidsHelper import org.hisp.dhis.android.core.arch.repositories.scope.RepositoryScope diff --git a/app/src/test/java/org/dhis2/bindings/RuleExtensionsTest.kt b/dhis2-mobile-program-rules/src/test/java/org/dhis2/mobileProgramRules/RuleEngineExtensionsTest.kt similarity index 95% rename from app/src/test/java/org/dhis2/bindings/RuleExtensionsTest.kt rename to dhis2-mobile-program-rules/src/test/java/org/dhis2/mobileProgramRules/RuleEngineExtensionsTest.kt index 50912371cd..2cc3e6e057 100644 --- a/app/src/test/java/org/dhis2/bindings/RuleExtensionsTest.kt +++ b/dhis2-mobile-program-rules/src/test/java/org/dhis2/mobileProgramRules/RuleEngineExtensionsTest.kt @@ -1,10 +1,5 @@ -package org.dhis2.bindings +package org.dhis2.mobileProgramRules -import org.dhis2.form.bindings.toRuleActionList -import org.dhis2.form.bindings.toRuleAttributeValue -import org.dhis2.form.bindings.toRuleDataValue -import org.dhis2.form.bindings.toRuleEngineObject -import org.dhis2.form.bindings.toRuleVariable import org.hisp.dhis.android.core.D2 import org.hisp.dhis.android.core.common.ObjectWithUid import org.hisp.dhis.android.core.common.ValueType @@ -14,7 +9,6 @@ import org.hisp.dhis.android.core.event.Event import org.hisp.dhis.android.core.option.Option import org.hisp.dhis.android.core.option.OptionCollectionRepository import org.hisp.dhis.android.core.program.ProgramRuleAction -import org.hisp.dhis.android.core.program.ProgramRuleActionType.SHOWERROR import org.hisp.dhis.android.core.program.ProgramRuleVariable import org.hisp.dhis.android.core.program.ProgramRuleVariableCollectionRepository import org.hisp.dhis.android.core.program.ProgramRuleVariableSourceType @@ -32,7 +26,7 @@ import org.mockito.kotlin.mock import org.mockito.kotlin.whenever import java.util.Date -class RuleExtensionsTest { +class RuleEngineExtensionsTest { private val dataElementRepository: DataElementCollectionRepository = Mockito.mock( DataElementCollectionRepository::class.java, @@ -374,16 +368,6 @@ class RuleExtensionsTest { assertTrue(ruleEngineAction.type == "unsupported") } - @Test - fun `Should parse program rule error`() { - val programRuleAction = ProgramRuleAction.builder() - .uid("uid") - .programRuleActionType(SHOWERROR) - .build() - val ruleActionList = listOf(programRuleAction).toRuleActionList() - assertTrue(ruleActionList.first().type == "error") - } - @Test fun `should parse ProgramRuleVariable to RuleVariable`() { val programRuleVariable = ProgramRuleVariable.builder() diff --git a/form/src/main/java/org/dhis2/form/bindings/RuleExtensions.kt b/form/src/main/java/org/dhis2/form/bindings/RuleExtensions.kt deleted file mode 100644 index 22a9c6e33d..0000000000 --- a/form/src/main/java/org/dhis2/form/bindings/RuleExtensions.kt +++ /dev/null @@ -1,563 +0,0 @@ -/* - * Copyright (c) 2004 - 2019, University of Oslo - * All rights reserved. - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * Neither the name of the HISP project nor the names of its contributors may - * be used to endorse or promote products derived from this software without - * specific prior written permission. - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -package org.dhis2.form.bindings - -import org.dhis2.commons.rules.toRuleEngineInstant -import org.hisp.dhis.android.core.D2 -import org.hisp.dhis.android.core.common.ValueType -import org.hisp.dhis.android.core.dataelement.DataElementCollectionRepository -import org.hisp.dhis.android.core.event.Event -import org.hisp.dhis.android.core.option.OptionCollectionRepository -import org.hisp.dhis.android.core.program.ProgramRule -import org.hisp.dhis.android.core.program.ProgramRuleAction -import org.hisp.dhis.android.core.program.ProgramRuleActionType -import org.hisp.dhis.android.core.program.ProgramRuleVariable -import org.hisp.dhis.android.core.program.ProgramRuleVariableCollectionRepository -import org.hisp.dhis.android.core.program.ProgramRuleVariableSourceType -import org.hisp.dhis.android.core.trackedentity.TrackedEntityAttributeCollectionRepository -import org.hisp.dhis.android.core.trackedentity.TrackedEntityAttributeValue -import org.hisp.dhis.android.core.trackedentity.TrackedEntityDataValue -import org.hisp.dhis.rules.models.Option -import org.hisp.dhis.rules.models.Rule -import org.hisp.dhis.rules.models.RuleAction -import org.hisp.dhis.rules.models.RuleAttributeValue -import org.hisp.dhis.rules.models.RuleDataValue -import org.hisp.dhis.rules.models.RuleValueType -import org.hisp.dhis.rules.models.RuleVariable -import org.hisp.dhis.rules.models.RuleVariableAttribute -import org.hisp.dhis.rules.models.RuleVariableCalculatedValue -import org.hisp.dhis.rules.models.RuleVariableCurrentEvent -import org.hisp.dhis.rules.models.RuleVariableNewestEvent -import org.hisp.dhis.rules.models.RuleVariableNewestStageEvent -import org.hisp.dhis.rules.models.RuleVariablePreviousEvent -import timber.log.Timber - -fun List.toRuleList(): List { - return map { - it.toRuleEngineObject() - } -} - -fun List.toRuleActionList(): List { - return map { - try { - it.toRuleEngineObject() - } catch (e: Exception) { - RuleAction( - data = e.message ?: "UNKNOWN", - type = "error", - ) - } - } -} - -fun List.toRuleVariableList( - attributeRepository: TrackedEntityAttributeCollectionRepository, - dataElementRepository: DataElementCollectionRepository, - optionRepository: OptionCollectionRepository, -): List { - return filter { - when { - it.dataElement() != null -> { - dataElementRepository.uid(it.dataElement()?.uid()).blockingExists() - } - - it.trackedEntityAttribute() != null -> { - attributeRepository.uid(it.trackedEntityAttribute()?.uid()).blockingExists() - } - - else -> isCalculatedValue(it) - } - }.map { - it.toRuleVariable(attributeRepository, dataElementRepository, optionRepository) - } -} - -private fun isCalculatedValue(it: ProgramRuleVariable) = it.dataElement() == null && - it.trackedEntityAttribute() == null && - it.programRuleVariableSourceType() == ProgramRuleVariableSourceType.CALCULATED_VALUE - -fun ProgramRule.toRuleEngineObject(): Rule { - return Rule( - condition = condition() ?: "", - actions = programRuleActions()?.toRuleActionList() ?: ArrayList(), - uid = uid(), - name = name(), - programStage = programStage()?.uid(), - priority = priority(), - ) -} - -fun ProgramRuleAction.toRuleEngineObject(): RuleAction { - val field = - when { - dataElement() != null -> dataElement()!!.uid() - trackedEntityAttribute() != null -> trackedEntityAttribute()!!.uid() - else -> "" - } - - return when (programRuleActionType()) { - ProgramRuleActionType.HIDEFIELD -> - RuleAction( - data = null, - type = ProgramRuleActionType.HIDEFIELD.name, - values = mutableMapOf( - Pair("field", field), - ).also { map -> - content()?.let { map["content"] = it } - }, - ) - - ProgramRuleActionType.DISPLAYTEXT -> - RuleAction( - data = data(), - type = ProgramRuleActionType.DISPLAYTEXT.name, - values = mutableMapOf( - Pair("location", location() ?: "indicators"), - ).also { map -> - content()?.let { map["content"] = it } - }, - ) - - ProgramRuleActionType.DISPLAYKEYVALUEPAIR -> - RuleAction( - data = data(), - type = ProgramRuleActionType.DISPLAYKEYVALUEPAIR.name, - values = mutableMapOf( - Pair("location", location()!!), - ).also { map -> - content()?.let { map["content"] = it } - }, - ) - - ProgramRuleActionType.HIDESECTION -> - programStageSection()?.let { - RuleAction( - data = null, - type = ProgramRuleActionType.HIDESECTION.name, - values = mutableMapOf( - Pair("programStageSection", it.uid()), - ), - ) - } ?: RuleAction( - "HIDE SECTION RULE IS MISSING PROGRAM STAGE SECTION", - "unsupported", - ) - - ProgramRuleActionType.HIDEPROGRAMSTAGE -> - programStage()?.let { - RuleAction( - data = data(), - type = ProgramRuleActionType.HIDEPROGRAMSTAGE.name, - values = mutableMapOf( - Pair("programStage", it.uid()), - ), - ) - } ?: RuleAction( - "HIDE STAGE RULE IS MISSING PROGRAM STAGE", - "unsupported", - ) - - ProgramRuleActionType.ASSIGN -> { - if (field.isEmpty() && content().isNullOrEmpty()) { - RuleAction( - "ASSIGN RULE IS MISSING FIELD TO ASSIGN TO", - type = "unsupported", - ) - } else { - RuleAction( - data = data() ?: "", - type = ProgramRuleActionType.ASSIGN.name, - values = mutableMapOf( - Pair("field", field), - ).also { map -> - content()?.let { map["content"] = it } - }, - ) - } - } - - ProgramRuleActionType.SHOWWARNING -> RuleAction( - data = data(), - type = ProgramRuleActionType.SHOWWARNING.name, - values = mutableMapOf( - Pair("field", field), - ).also { map -> - content()?.let { map["content"] = it } - }, - ) - ProgramRuleActionType.WARNINGONCOMPLETE -> RuleAction( - data = data(), - type = ProgramRuleActionType.WARNINGONCOMPLETE.name, - values = mutableMapOf( - Pair("field", field), - ).also { map -> - content()?.let { map["content"] = it } - }, - ) - - ProgramRuleActionType.SHOWERROR -> { - require(field.isNotEmpty()) - RuleAction( - data = data(), - type = ProgramRuleActionType.SHOWERROR.name, - values = mutableMapOf( - Pair("field", field), - ).also { map -> - content()?.let { map["content"] = it } - }, - ) - } - ProgramRuleActionType.ERRORONCOMPLETE -> - RuleAction( - data = data(), - type = ProgramRuleActionType.ERRORONCOMPLETE.name, - values = mutableMapOf( - Pair("field", field), - ).also { map -> - content()?.let { map["content"] = it } - }, - ) - - ProgramRuleActionType.CREATEEVENT -> - programStage()?.uid()?.let { stageUid -> - RuleAction( - data = data(), - type = ProgramRuleActionType.CREATEEVENT.name, - values = mutableMapOf( - Pair("programStage", stageUid), - ).also { map -> - content()?.let { map["content"] = it } - }, - ) - } ?: RuleAction( - "CREATE EVENT RULE IS MISSING PROGRAM STAGE SECTION", - "unsupported", - ) - - ProgramRuleActionType.SETMANDATORYFIELD -> - RuleAction( - data = data(), - type = ProgramRuleActionType.SETMANDATORYFIELD.name, - values = mutableMapOf( - Pair("field", field), - ).also { map -> - content()?.let { map["content"] = it } - }, - ) - ProgramRuleActionType.HIDEOPTION -> - option()?.uid()?.let { optionUid -> - RuleAction( - data = data(), - type = ProgramRuleActionType.HIDEOPTION.name, - values = mutableMapOf( - Pair("field", field), - Pair("option", optionUid), - ).also { map -> - content()?.let { map["content"] = it } - }, - ) - } ?: RuleAction( - "HIDE OPTION RULE IS MISSING OPTION", - "unsupported", - ) - - ProgramRuleActionType.SHOWOPTIONGROUP -> - optionGroup()?.uid()?.let { optionGroupUid -> - RuleAction( - data = data(), - type = ProgramRuleActionType.SHOWOPTIONGROUP.name, - values = mutableMapOf( - Pair("field", field), - Pair("optionGroup", optionGroupUid), - ).also { map -> - content()?.let { map["content"] = it } - }, - ) - } ?: RuleAction( - "SHOW OPTION GROUP RULE IS MISSING OPTION GROUP", - "unsupported", - ) - - ProgramRuleActionType.HIDEOPTIONGROUP -> - optionGroup()?.uid()?.let { optionGroupUid -> - RuleAction( - data = data(), - type = ProgramRuleActionType.HIDEOPTIONGROUP.name, - values = mutableMapOf( - Pair("field", field), - Pair("optionGroup", optionGroupUid), - ).also { map -> - content()?.let { map["content"] = it } - }, - ) - } ?: RuleAction( - "HIDE OPTION GROUP RULE IS MISSING OPTION GROUP", - "unsupported", - ) - - ProgramRuleActionType.SENDMESSAGE, ProgramRuleActionType.SCHEDULEMESSAGE, null -> - RuleAction( - "UNSUPPORTED RULE ACTION TYPE", - "unsupported", - ) - } -} - -fun ProgramRuleVariable.toRuleVariable( - attributeRepository: TrackedEntityAttributeCollectionRepository, - dataElementRepository: DataElementCollectionRepository, - optionRepository: OptionCollectionRepository, -): RuleVariable { - val valueType = when (programRuleVariableSourceType()) { - ProgramRuleVariableSourceType.DATAELEMENT_NEWEST_EVENT_PROGRAM_STAGE, - ProgramRuleVariableSourceType.DATAELEMENT_NEWEST_EVENT_PROGRAM, - ProgramRuleVariableSourceType.DATAELEMENT_CURRENT_EVENT, - ProgramRuleVariableSourceType.DATAELEMENT_PREVIOUS_EVENT, - -> - dataElement()?.let { - dataElementRepository.uid(it.uid()).blockingGet() - ?.valueType()?.toRuleValueType() - } ?: RuleValueType.TEXT - - ProgramRuleVariableSourceType.TEI_ATTRIBUTE -> - trackedEntityAttribute()?.let { - attributeRepository.uid(it.uid()).blockingGet() - ?.valueType()?.toRuleValueType() - } ?: RuleValueType.TEXT - - ProgramRuleVariableSourceType.CALCULATED_VALUE, null -> RuleValueType.TEXT - } - - val useCodeForOptionSet = useCodeForOptionSet() ?: false - val options = getOptions( - useCodeForOptionSet, - dataElement()?.uid(), - trackedEntityAttribute()?.uid(), - attributeRepository, - dataElementRepository, - optionRepository, - ) - - return when (programRuleVariableSourceType()) { - ProgramRuleVariableSourceType.CALCULATED_VALUE -> - RuleVariableCalculatedValue( - name = name() ?: "", - useCodeForOptionSet = useCodeForOptionSet, - options = options, - field = dataElement()?.uid() ?: trackedEntityAttribute()?.uid() ?: "", - fieldType = valueType, - ) - - ProgramRuleVariableSourceType.TEI_ATTRIBUTE -> - RuleVariableAttribute( - name = name() ?: "", - useCodeForOptionSet = useCodeForOptionSet, - options = options, - field = trackedEntityAttribute()?.uid() ?: "", - fieldType = valueType, - ) - - ProgramRuleVariableSourceType.DATAELEMENT_NEWEST_EVENT_PROGRAM_STAGE -> - RuleVariableNewestStageEvent( - name = name() ?: "", - useCodeForOptionSet = useCodeForOptionSet, - options = options, - field = dataElement()?.uid() ?: "", - fieldType = valueType, - programStage = programStage()?.uid() ?: "", - ) - - ProgramRuleVariableSourceType.DATAELEMENT_NEWEST_EVENT_PROGRAM -> - RuleVariableNewestEvent( - name = name() ?: "", - useCodeForOptionSet = useCodeForOptionSet, - options = options, - field = dataElement()?.uid() ?: "", - fieldType = valueType, - ) - - ProgramRuleVariableSourceType.DATAELEMENT_CURRENT_EVENT -> - RuleVariableCurrentEvent( - name = name() ?: "", - useCodeForOptionSet = useCodeForOptionSet, - options = options, - field = dataElement()?.uid() ?: "", - fieldType = valueType, - ) - - ProgramRuleVariableSourceType.DATAELEMENT_PREVIOUS_EVENT -> - RuleVariablePreviousEvent( - name = name() ?: "", - useCodeForOptionSet = useCodeForOptionSet, - options = options, - field = dataElement()?.uid() ?: "", - fieldType = valueType, - ) - - else -> throw IllegalArgumentException("Unsupported variable ") - } -} - -fun getOptions( - useCodeForOptionSet: Boolean, - dataElementUid: String?, - trackedEntityAttributeUid: String?, - attributeRepository: TrackedEntityAttributeCollectionRepository, - dataElementRepository: DataElementCollectionRepository, - optionRepository: OptionCollectionRepository, -): List