Skip to content

Commit

Permalink
fix: Load events to fix program rule variables calculation [DHIS2-179…
Browse files Browse the repository at this point in the history
…51] (#18508)

* fix: Load events to fix program rule variables calculation [DHIS2-17951]

* Fix tests

* Fix tests

* Fix tests

* Fix review comments
  • Loading branch information
enricocolasante authored Sep 5, 2024
1 parent 9ef15d9 commit f72cc52
Show file tree
Hide file tree
Showing 12 changed files with 297 additions and 29 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -157,10 +157,12 @@ class JdbcEventStore implements EventStore {
private static final String COLUMN_EVENT_UID = "ev_uid";
private static final String COLUMN_PROGRAM_UID = "p_uid";
private static final String COLUMN_PROGRAM_STAGE_UID = "ps_uid";
private static final String COLUMN_PROGRAM_STAGE_NAME = "ps_name";
private static final String COLUMN_ENROLLMENT_UID = "en_uid";
private static final String COLUMN_ENROLLMENT_STATUS = "en_status";
private static final String COLUMN_ENROLLMENT_DATE = "en_enrollmentdate";
private static final String COLUMN_ORG_UNIT_UID = "orgunit_uid";
private static final String COLUMN_ORG_UNIT_CODE = "orgunit_code";
private static final String COLUMN_TRACKEDENTITY_UID = "te_uid";
private static final String COLUMN_EVENT_OCCURRED_DATE = "ev_occurreddate";
private static final String COLUMN_ENROLLMENT_FOLLOWUP = "en_followup";
Expand Down Expand Up @@ -302,8 +304,10 @@ private List<Event> fetchEvents(EventQueryParams queryParams, PageParams pagePar
enrollment.setTrackedEntity(te);
OrganisationUnit ou = new OrganisationUnit();
ou.setUid(resultSet.getString(COLUMN_ORG_UNIT_UID));
ou.setCode(resultSet.getString(COLUMN_ORG_UNIT_CODE));
ProgramStage ps = new ProgramStage();
ps.setUid(resultSet.getString("ps_identifier"));
ps.setName(resultSet.getString(COLUMN_PROGRAM_STAGE_NAME));
event.setDeleted(resultSet.getBoolean(COLUMN_EVENT_DELETED));

enrollment.setStatus(
Expand Down Expand Up @@ -756,10 +760,15 @@ private String getEventSelectQuery(
.append(", ")
.append("ou.uid as ")
.append(COLUMN_ORG_UNIT_UID)
.append(", ")
.append("ou.code as ")
.append(COLUMN_ORG_UNIT_CODE)
.append(", p.uid as ")
.append(COLUMN_PROGRAM_UID)
.append(", ps.uid as ")
.append(COLUMN_PROGRAM_STAGE_UID)
.append(", ps.name as ")
.append(COLUMN_PROGRAM_STAGE_NAME)
.append(", ")
.append("ev.eventid as ")
.append(COLUMN_EVENT_ID)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@
*/
package org.hisp.dhis.tracker.imports.programrule;

import static org.hisp.dhis.common.OrganisationUnitSelectionMode.ACCESSIBLE;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
Expand All @@ -36,11 +38,17 @@
import java.util.stream.Collectors;
import java.util.stream.Stream;
import lombok.RequiredArgsConstructor;
import org.hisp.dhis.feedback.BadRequestException;
import org.hisp.dhis.feedback.ForbiddenException;
import org.hisp.dhis.feedback.NotFoundException;
import org.hisp.dhis.program.Enrollment;
import org.hisp.dhis.program.Event;
import org.hisp.dhis.program.Program;
import org.hisp.dhis.trackedentity.TrackedEntity;
import org.hisp.dhis.trackedentityattributevalue.TrackedEntityAttributeValue;
import org.hisp.dhis.tracker.export.event.EventOperationParams;
import org.hisp.dhis.tracker.export.event.EventParams;
import org.hisp.dhis.tracker.export.event.EventService;
import org.hisp.dhis.tracker.imports.bundle.TrackerBundle;
import org.hisp.dhis.tracker.imports.converter.RuleEngineConverterService;
import org.hisp.dhis.tracker.imports.converter.TrackerConverterService;
Expand All @@ -59,6 +67,8 @@
class DefaultProgramRuleService implements ProgramRuleService {
private final ProgramRuleEngine programRuleEngine;

private final EventService eventService;

private final RuleEngineConverterService<
org.hisp.dhis.tracker.imports.domain.Enrollment, Enrollment>
enrollmentTrackerConverterService;
Expand Down Expand Up @@ -202,10 +212,21 @@ private List<TrackedEntityAttributeValue> getAttributes(
// if they are present in both places
private Set<Event> getEventsFromEnrollment(
String enrollmentUid, TrackerBundle bundle, TrackerPreheat preheat) {
Stream<Event> events =
preheat.getEvents().values().stream()
.filter(e -> e.getEnrollment().getUid().equals(enrollmentUid))
.filter(e -> bundle.findEventByUid(e.getUid()).isEmpty());
Stream<Event> events;
try {
events =
eventService
.getEvents(
EventOperationParams.builder()
.eventParams(EventParams.TRUE)
.orgUnitMode(ACCESSIBLE)
.enrollments(Set.of(enrollmentUid))
.build())
.stream()
.filter(e -> bundle.findEventByUid(e.getUid()).isEmpty());
} catch (BadRequestException | ForbiddenException | NotFoundException e) {
throw new RuntimeException(e);
}

Stream<Event> bundleEvents =
bundle.getEvents().stream()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@
import org.hisp.dhis.tracker.imports.domain.TrackerObjects;
import org.hisp.dhis.user.User;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;

Expand Down Expand Up @@ -85,6 +86,12 @@ void setUp() throws IOException {
importParams, fromJson("tracker/event_and_enrollment.json")));
}

@BeforeEach
void setUpUser() {
importUser = userService.getUser("tTgjgobT1oS");
injectSecurityContextUser(importUser);
}

@Test
void shouldFailWhenEventDoesNotExist() {
assertThrows(
Expand Down Expand Up @@ -142,7 +149,6 @@ void shouldFailWhenProgramWithoutRegistrationAndNoAccessToEventOrgUnit() {

@Test
void shouldReturnChangeLogsWhenDataValueIsCreated() throws NotFoundException, ForbiddenException {
testAsUser("M5zQapPyTZI");
Event event = getEvent("QRYjLTiJTrA");
String dataElementUid = event.getEventDataValues().iterator().next().getDataElement();

Expand All @@ -157,8 +163,6 @@ void shouldReturnChangeLogsWhenDataValueIsCreated() throws NotFoundException, Fo
@Test
void shouldReturnChangeLogsWhenDataValueIsDeleted()
throws NotFoundException, IOException, ForbiddenException {
testAsUser("M5zQapPyTZI");

Event event = getEvent("QRYjLTiJTrA");
String dataElementUid = event.getEventDataValues().iterator().next().getDataElement();

Expand All @@ -179,8 +183,6 @@ void shouldReturnChangeLogsWhenDataValueIsDeleted()
@Test
void shouldNotUpdateChangeLogsWhenDataValueIsDeletedTwiceInARow()
throws NotFoundException, IOException, ForbiddenException {
testAsUser("M5zQapPyTZI");

Event event = getEvent("QRYjLTiJTrA");
String dataElementUid = event.getEventDataValues().iterator().next().getDataElement();

Expand All @@ -203,8 +205,6 @@ void shouldNotUpdateChangeLogsWhenDataValueIsDeletedTwiceInARow()
@Test
void shouldReturnChangeLogsWhenDataValueIsUpdated()
throws NotFoundException, IOException, ForbiddenException {
testAsUser("M5zQapPyTZI");

Event event = getEvent("QRYjLTiJTrA");
String dataElementUid = event.getEventDataValues().iterator().next().getDataElement();

Expand All @@ -225,8 +225,6 @@ void shouldReturnChangeLogsWhenDataValueIsUpdated()
@Test
void shouldReturnChangeLogsWhenDataValueIsUpdatedTwiceInARow()
throws NotFoundException, IOException, ForbiddenException {
testAsUser("M5zQapPyTZI");

Event event = getEvent("QRYjLTiJTrA");
String dataElementUid = event.getEventDataValues().iterator().next().getDataElement();

Expand All @@ -250,8 +248,6 @@ void shouldReturnChangeLogsWhenDataValueIsUpdatedTwiceInARow()
@Test
void shouldReturnChangeLogsWhenDataValueIsCreatedUpdatedAndDeleted()
throws IOException, NotFoundException, ForbiddenException {
testAsUser("M5zQapPyTZI");

Event event = getEvent("QRYjLTiJTrA");
String dataElementUid = event.getEventDataValues().iterator().next().getDataElement();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,8 @@ void setUp() {
user.getGroups().add(userGroup);
manager.update(user);

injectSecurityContextUser(user);

templateForEnrollment =
createProgramNotification(
"enrollment",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ void setUp() throws IOException {

@Test
void testRunRuleEngineForEventOnBundleCreate() throws IOException {
injectSecurityContextUser(userService.getUser("tTgjgobT1oS"));
TrackerObjects trackerObjects = fromJson("tracker/event_events_and_enrollment.json");
assertEquals(8, trackerObjects.getEvents().size());
TrackerBundle trackerBundle =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,16 +28,20 @@
package org.hisp.dhis.tracker.imports.programrule;

import static org.hisp.dhis.programrule.ProgramRuleActionType.ASSIGN;
import static org.hisp.dhis.test.utils.Assertions.assertContainsOnly;
import static org.hisp.dhis.tracker.Assertions.assertHasOnlyErrors;
import static org.hisp.dhis.tracker.Assertions.assertHasOnlyWarnings;
import static org.hisp.dhis.tracker.imports.validation.ValidationCode.E1307;
import static org.hisp.dhis.tracker.imports.validation.ValidationCode.E1308;
import static org.hisp.dhis.tracker.imports.validation.ValidationCode.E1310;

import java.io.IOException;
import java.util.List;
import org.hisp.dhis.dataelement.DataElement;
import org.hisp.dhis.dxf2.metadata.objectbundle.ObjectBundle;
import org.hisp.dhis.eventdatavalue.EventDataValue;
import org.hisp.dhis.preheat.PreheatIdentifier;
import org.hisp.dhis.program.Event;
import org.hisp.dhis.program.Program;
import org.hisp.dhis.program.ProgramStage;
import org.hisp.dhis.programrule.ProgramRule;
Expand All @@ -47,6 +51,7 @@
import org.hisp.dhis.programrule.ProgramRuleService;
import org.hisp.dhis.programrule.ProgramRuleVariable;
import org.hisp.dhis.programrule.ProgramRuleVariableService;
import org.hisp.dhis.programrule.ProgramRuleVariableSourceType;
import org.hisp.dhis.setting.SettingKey;
import org.hisp.dhis.setting.SystemSettingManager;
import org.hisp.dhis.trackedentity.TrackedEntityAttribute;
Expand All @@ -57,8 +62,11 @@
import org.hisp.dhis.tracker.imports.domain.TrackerObjects;
import org.hisp.dhis.tracker.imports.report.ImportReport;
import org.hisp.dhis.user.User;
import org.hisp.dhis.util.DateUtils;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvSource;
import org.springframework.beans.factory.annotation.Autowired;

class ProgramRuleAssignActionTest extends TrackerTest {
Expand All @@ -76,6 +84,8 @@ class ProgramRuleAssignActionTest extends TrackerTest {

private DataElement dataElement1;

private DataElement dataElement2;

private TrackedEntityAttribute attribute1;

@BeforeAll
Expand All @@ -87,8 +97,7 @@ void setUp() throws IOException {

program = bundle.getPreheat().get(PreheatIdentifier.UID, Program.class, "BFcipDERJnf");
dataElement1 = bundle.getPreheat().get(PreheatIdentifier.UID, DataElement.class, "DATAEL00001");
DataElement dataElement2 =
bundle.getPreheat().get(PreheatIdentifier.UID, DataElement.class, "DATAEL00002");
dataElement2 = bundle.getPreheat().get(PreheatIdentifier.UID, DataElement.class, "DATAEL00002");
attribute1 =
bundle.getPreheat().get(PreheatIdentifier.UID, TrackedEntityAttribute.class, "dIVt4l5vIOa");
TrackedEntityAttribute attribute2 =
Expand All @@ -100,7 +109,12 @@ void setUp() throws IOException {
programRuleVariableService.addProgramRuleVariable(programRuleVariable);
programRuleVariableService.addProgramRuleVariable(programRuleVariableAttribute);

assignProgramRule();
ProgramRuleVariable programRuleVariablePreviousEvent =
createProgramRuleVariableWithDataElement('C', program, dataElement1);
programRuleVariablePreviousEvent.setSourceType(
ProgramRuleVariableSourceType.DATAELEMENT_PREVIOUS_EVENT);
programRuleVariableService.addProgramRuleVariable(programRuleVariablePreviousEvent);

trackerImportService.importTracker(
new TrackerImportParams(),
fromJson("tracker/programrule/te_enrollment_completed_event.json"));
Expand All @@ -109,6 +123,7 @@ void setUp() throws IOException {
@Test
void shouldNotImportWithWarningWhenAttributeWithSameValueIsAssignedByAssignRule()
throws IOException {
assignProgramRule();
TrackerImportParams params = new TrackerImportParams();
TrackerObjects trackerObjects =
fromJson("tracker/programrule/te_enrollment_update_attribute_same_value.json");
Expand All @@ -119,9 +134,43 @@ void shouldNotImportWithWarningWhenAttributeWithSameValueIsAssignedByAssignRule(
assertHasOnlyWarnings(importReport, E1310);
}

@ParameterizedTest
@CsvSource({"2024-02-10,THIRD", "2024-01-28,SECOND", "2024-01-19,FIRST"})
void shouldImportEventAndCorrectlyAssignPreviousEventDataValue(
String eventOccurredDate, String previousEventDataValue) throws IOException {
TrackerImportParams params = new TrackerImportParams();
TrackerObjects trackerObjects =
fromJson("tracker/programrule/three_events_with_different_dates.json");
params.setImportStrategy(TrackerImportStrategy.CREATE_AND_UPDATE);

trackerImportService.importTracker(params, trackerObjects);

assignPreviousEventProgramRule();

trackerObjects = fromJson("tracker/programrule/event_with_data_value.json");

trackerObjects
.getEvents()
.get(0)
.setOccurredAt(DateUtils.instantFromDateAsString(eventOccurredDate));

ImportReport importReport = trackerImportService.importTracker(params, trackerObjects);
assertHasOnlyWarnings(importReport, E1308);

Event event = manager.get(Event.class, "D9PbzJY8bZZ");

List<String> eventDataValues =
event.getEventDataValues().stream()
.filter(dv -> dv.getDataElement().equals("DATAEL00002"))
.map(EventDataValue::getValue)
.toList();
assertContainsOnly(List.of(previousEventDataValue), eventDataValues);
}

@Test
void shouldImportWithWarningWhenDataElementWithSameValueIsAssignedByAssignRule()
throws IOException {
assignProgramRule();
TrackerImportParams params = new TrackerImportParams();
TrackerObjects trackerObjects =
fromJson("tracker/programrule/event_update_datavalue_same_value.json");
Expand All @@ -134,6 +183,7 @@ void shouldImportWithWarningWhenDataElementWithSameValueIsAssignedByAssignRule()

@Test
void shouldNotImportWhenDataElementWithDifferentValueIsAssignedByAssignRule() throws IOException {
assignProgramRule();
TrackerImportParams params = new TrackerImportParams();
TrackerObjects trackerObjects =
fromJson("tracker/programrule/event_update_datavalue_different_value.json");
Expand All @@ -148,6 +198,7 @@ void shouldNotImportWhenDataElementWithDifferentValueIsAssignedByAssignRule() th
void
shouldImportWithWarningWhenDataElementWithDifferentValueIsAssignedByAssignRuleAndOverwriteKeyIsTrue()
throws IOException {
assignProgramRule();
systemSettingManager.saveSystemSetting(SettingKey.RULE_ENGINE_ASSIGN_OVERWRITE, true);
TrackerImportParams params = new TrackerImportParams();
TrackerObjects trackerObjects =
Expand All @@ -163,6 +214,7 @@ void shouldNotImportWhenDataElementWithDifferentValueIsAssignedByAssignRule() th
void
shouldImportWithWarningWhenDataElementWithDifferentAndEmptyValueIsAssignedByAssignRuleAndOverwriteKeyIsTrue()
throws IOException {
assignProgramRule();
systemSettingManager.saveSystemSetting(SettingKey.RULE_ENGINE_ASSIGN_OVERWRITE, true);
TrackerImportParams params = new TrackerImportParams();
TrackerObjects trackerObjects =
Expand All @@ -188,6 +240,16 @@ private void assignProgramRule() {
programRuleService.updateProgramRule(programRule);
}

private void assignPreviousEventProgramRule() {
ProgramRule programRule = createProgramRule('G', program, null, "true");
programRuleService.addProgramRule(programRule);
ProgramRuleAction programRuleAction =
createProgramRuleAction(programRule, ASSIGN, dataElement2, "#{ProgramRuleVariableC}");
programRuleActionService.addProgramRuleAction(programRuleAction);
programRule.getProgramRuleActions().add(programRuleAction);
programRuleService.updateProgramRule(programRule);
}

private ProgramRule createProgramRule(
char uniqueCharacter, Program program, ProgramStage programStage, String condition) {
ProgramRule programRule = createProgramRule(uniqueCharacter, program);
Expand Down
Loading

0 comments on commit f72cc52

Please sign in to comment.