Skip to content

Commit

Permalink
fix: Assing distant future date to events without date [DHIS2-18631]
Browse files Browse the repository at this point in the history
  • Loading branch information
enricocolasante committed Dec 16, 2024
1 parent 0a324eb commit 26b1015
Show file tree
Hide file tree
Showing 5 changed files with 66 additions and 62 deletions.
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
package org.hisp.dhis.rules.engine

import kotlinx.datetime.Instant
import kotlinx.datetime.LocalDate
import kotlinx.datetime.TimeZone
import kotlinx.datetime.toLocalDateTime
import org.hisp.dhis.rules.api.RuleEngine
import org.hisp.dhis.rules.models.*
import org.hisp.dhis.rules.utils.RuleEngineUtils
import org.hisp.dhis.rules.utils.currentDate
Expand Down Expand Up @@ -133,18 +135,20 @@ internal class RuleVariableValueMapBuilder {
currentDate: LocalDate,
): Map<String, RuleVariableValue> {
val valueMap: MutableMap<String, RuleVariableValue> = HashMap()
val eventDate =
ruleEvent.eventDate
.toLocalDateTime(TimeZone.currentSystemDefault())
.date
.toString()
valueMap[RuleEngineUtils.ENV_VAR_EVENT_DATE] =
RuleVariableValue(
RuleValueType.TEXT,
eventDate,
listOf(eventDate),
currentDate.toString(),
)
if (ruleEvent.eventDate < Instant.DISTANT_FUTURE ){
val eventDate =
ruleEvent.eventDate
.toLocalDateTime(TimeZone.currentSystemDefault())
.date
.toString()
valueMap[RuleEngineUtils.ENV_VAR_EVENT_DATE] =
RuleVariableValue(
RuleValueType.TEXT,
eventDate,
listOf(eventDate),
currentDate.toString(),
)
}
if (ruleEvent.dueDate != null) {
val dueDate = ruleEvent.dueDate
valueMap[RuleEngineUtils.ENV_VAR_DUE_DATE] =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,44 @@ class RuleVariableValueMapBuilderTest {
.hasCandidates("test_value_two")
}

@Test
fun currentEventVariableShouldContainValuesFromCurrentEventWhenEventDateIsDistantFuture() {
val eventInstant = Instant.parse("2015-01-01T01:00:00Z")
val eventDate = LocalDate.parse("2015-01-01")
val dueDate = LocalDate.parse("2016-01-01")

// values from context events should be ignored
val contextEventOne =
RuleEvent(
"test_context_event_one",
"test_program_stage",
"",
RuleEventStatus.ACTIVE,
Instant.DISTANT_FUTURE,
Clock.System.now(),
LocalDate.currentDate(),
null,
"",
null,
listOf(
RuleDataValue(
"test_dataelement_one",
"test_context_value_one",
),
RuleDataValue(
"test_dataelement_two",
"test_context_value_two",
),
),
)

val valueMap =
RuleVariableValueMapBuilder()
.build(emptyMap(), listOf(), setOf(contextEventOne), null, null)

assertNull(valueMap["event_date"])
}

@Test
fun newestEventProgramVariableShouldContainValueFromNewestContextEvent() {
val ruleVariableOne: RuleVariable =
Expand Down
39 changes: 11 additions & 28 deletions src/jsMain/kotlin/org/hisp/dhis/rules/RuleEngineJs.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package org.hisp.dhis.rules

import js.array.tupleOf
import js.collections.JsMap
import kotlinx.datetime.Clock
import kotlinx.datetime.Instant
import kotlinx.datetime.LocalDate
import org.hisp.dhis.rules.api.DataItem
Expand All @@ -22,13 +23,9 @@ class RuleEngineJs(verbose: Boolean = false) {
fun validateDataFieldExpression(expression: String, dataItemStore: JsMap<String, DataItemJs>): RuleValidationResult{
return RuleEngine.getInstance().validateDataFieldExpression(expression, toMap(dataItemStore, {it}, ::toDataItemJava))
}
fun evaluateAll(enrollmentTarget: RuleEnrollmentJs?, eventsInProgressTarget: Array<RuleEventInProgressJs>, eventsTarget: Array<RuleEventJs>, executionContext: RuleEngineContextJs): Array<RuleEffectsJs>{
val lastEventDate = eventsTarget
.map { Instant.fromEpochMilliseconds(it.eventDate.toEpochMilli().toLong())}
.maxWith(compareBy { it })
.plus(Duration.parse("1D"))
fun evaluateAll(enrollmentTarget: RuleEnrollmentJs?, eventsTarget: Array<RuleEventJs>, executionContext: RuleEngineContextJs): Array<RuleEffectsJs>{
return toRuleEffectsJsList(RuleEngine.getInstance().evaluateAll(toEnrollmentJava(enrollmentTarget),
eventsTarget.map(::toEventJava).plus(eventsInProgressTarget.map{ e -> this.toEventJava(e, lastEventDate)}),
eventsTarget.map(::toEventJava),
toRuleEngineContextJava(executionContext)))
}

Expand All @@ -38,12 +35,8 @@ class RuleEngineJs(verbose: Boolean = false) {
toRuleEngineContextJava(executionContext))
.map(::toRuleEffectJs).toTypedArray()
}
fun evaluateEvent(target: RuleEventInProgressJs, ruleEnrollment: RuleEnrollmentJs?, ruleEvents: Array<RuleEventJs>, executionContext: RuleEngineContextJs): Array<RuleEffectJs>{
val lastEventDate = ruleEvents
.map { Instant.fromEpochMilliseconds(it.eventDate.toEpochMilli().toLong())}
.maxWith(compareBy { it })
.plus(Duration.parse("1D"))
return RuleEngine.getInstance().evaluate(toEventJava(target, lastEventDate),
fun evaluateEvent(target: RuleEventJs, ruleEnrollment: RuleEnrollmentJs?, ruleEvents: Array<RuleEventJs>, executionContext: RuleEngineContextJs): Array<RuleEffectJs>{
return RuleEngine.getInstance().evaluate(toEventJava(target),
toEnrollmentJava(ruleEnrollment),
ruleEvents.map(::toEventJava).toList(),
toRuleEngineContextJava(executionContext))
Expand Down Expand Up @@ -84,7 +77,10 @@ class RuleEngineJs(verbose: Boolean = false) {
programStage = event.programStage,
programStageName = event.programStageName,
status = event.status,
eventDate = Instant.fromEpochMilliseconds(event.eventDate.toEpochMilli().toLong()),
eventDate = if(event.eventDate != null)
Instant.fromEpochMilliseconds(event.eventDate.toEpochMilli().toLong())
else
Instant.DISTANT_FUTURE,
createdDate = Instant.fromEpochMilliseconds(event.createdDate.toEpochMilli().toLong()),
dueDate = toLocalDate(event.dueDate),
completedDate = toLocalDate(event.completedDate),
Expand All @@ -94,21 +90,7 @@ class RuleEngineJs(verbose: Boolean = false) {
)
}

private fun toEventJava(event: RuleEventInProgressJs, eventDate: Instant): RuleEvent {
return RuleEvent(
event = event.event,
programStage = event.programStage,
programStageName = event.programStageName,
status = event.status,
eventDate = eventDate,
createdDate = Instant.fromEpochMilliseconds(event.createdDate.toEpochMilli().toLong()),
dueDate = toLocalDate(event.dueDate),
completedDate = toLocalDate(event.completedDate),
organisationUnit = event.organisationUnit,
organisationUnitCode = event.organisationUnitCode,
dataValues = event.dataValues.toList()
)
}


private fun toRuleJava(rule: RuleJs): Rule {
return Rule(
Expand Down Expand Up @@ -222,5 +204,6 @@ class RuleEngineJs(verbose: Boolean = false) {

internal companion object {
var verbose: Boolean = false
var lastDate: Instant = Clock.System.now()
}
}
21 changes: 0 additions & 21 deletions src/jsMain/kotlin/org/hisp/dhis/rules/RuleEventInProgressJs.kt

This file was deleted.

2 changes: 1 addition & 1 deletion src/jsMain/kotlin/org/hisp/dhis/rules/RuleEventJs.kt
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ data class RuleEventJs(
val programStage: String,
val programStageName: String,
val status: RuleEventStatus,
val eventDate: Instant,
val eventDate: Instant?,
val createdDate: Instant,
val dueDate: LocalDate?,
val completedDate: LocalDate?,
Expand Down

0 comments on commit 26b1015

Please sign in to comment.