Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix:(2.39) Notification trigger when status is changed to completed [DHIS2-17180] #18204

Merged
merged 2 commits into from
Jul 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@
import org.hisp.dhis.tracker.domain.Attribute;
import org.hisp.dhis.tracker.domain.MetadataIdentifier;
import org.hisp.dhis.tracker.domain.TrackerDto;
import org.hisp.dhis.tracker.job.SideEffectTrigger;
import org.hisp.dhis.tracker.job.TrackerSideEffectDataBundle;
import org.hisp.dhis.tracker.preheat.TrackerPreheat;
import org.hisp.dhis.tracker.report.TrackerObjectReport;
Expand Down Expand Up @@ -106,6 +107,9 @@ public TrackerTypeReport persist(Session session, TrackerBundle bundle) {
TrackerObjectReport objectReport =
new TrackerObjectReport(getType(), trackerDto.getUid(), dtos.indexOf(trackerDto));

List<SideEffectTrigger> triggers =
determineSideEffectTriggers(bundle.getPreheat(), trackerDto);

try {
//
// Convert the TrackerDto into an Hibernate-managed entity
Expand Down Expand Up @@ -146,7 +150,7 @@ public TrackerTypeReport persist(Session session, TrackerBundle bundle) {
}

if (!bundle.isSkipSideEffects()) {
sideEffectDataBundles.add(handleSideEffects(bundle, convertedDto));
sideEffectDataBundles.add(handleSideEffects(bundle, convertedDto, triggers));
}

//
Expand Down Expand Up @@ -234,7 +238,18 @@ protected boolean isNew(TrackerPreheat preheat, T trackerDto) {
protected abstract boolean isNew(TrackerPreheat preheat, String uid);

/** TODO add comment */
protected abstract TrackerSideEffectDataBundle handleSideEffects(TrackerBundle bundle, V entity);
protected abstract TrackerSideEffectDataBundle handleSideEffects(
TrackerBundle bundle, V entity, List<SideEffectTrigger> triggers);

/**
* Determines the side effect triggers based on the enrollment/event status.
*
* @param preheat the enrollment/event fetched from the database
* @param entity the enrollment/event coming from the request payload
* @return a list of NotificationTriggers
*/
protected abstract List<SideEffectTrigger> determineSideEffectTriggers(
TrackerPreheat preheat, T entity);

/** Get the Tracker Type for which the current Persister is responsible for. */
protected abstract TrackerType getType();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
import org.hisp.dhis.tracker.converter.TrackerConverterService;
import org.hisp.dhis.tracker.converter.TrackerSideEffectConverterService;
import org.hisp.dhis.tracker.domain.Enrollment;
import org.hisp.dhis.tracker.domain.EnrollmentStatus;
import org.hisp.dhis.tracker.job.SideEffectTrigger;
import org.hisp.dhis.tracker.job.TrackerSideEffectDataBundle;
import org.hisp.dhis.tracker.preheat.TrackerPreheat;
Expand Down Expand Up @@ -126,23 +127,7 @@ protected boolean isNew(TrackerPreheat preheat, String uid) {

@Override
protected TrackerSideEffectDataBundle handleSideEffects(
TrackerBundle bundle, ProgramInstance programInstance) {
TrackerPreheat preheat = bundle.getPreheat();
List<SideEffectTrigger> triggers = new ArrayList<>();

if (isNew(preheat, programInstance.getUid())) {
triggers.add(SideEffectTrigger.ENROLLMENT);
if (programInstance.isCompleted()) {
triggers.add(SideEffectTrigger.ENROLLMENT_COMPLETION);
}
} else {
ProgramInstance exitingEnrollment = preheat.getEnrollment(programInstance.getUid());
if (exitingEnrollment.getStatus() != programInstance.getStatus()
&& programInstance.isCompleted()) {
triggers.add(SideEffectTrigger.ENROLLMENT_COMPLETION);
}
}

TrackerBundle bundle, ProgramInstance programInstance, List<SideEffectTrigger> triggers) {
return TrackerSideEffectDataBundle.builder()
.klass(ProgramInstance.class)
.enrollmentRuleEffects(
Expand All @@ -159,6 +144,31 @@ protected TrackerSideEffectDataBundle handleSideEffects(
.build();
}

@Override
protected List<SideEffectTrigger> determineSideEffectTriggers(
TrackerPreheat preheat, Enrollment entity) {
ProgramInstance persistedEnrollment = preheat.getEnrollment(entity.getUid());
List<SideEffectTrigger> triggers = new ArrayList<>();

if (persistedEnrollment == null) {
// New enrollment
triggers.add(SideEffectTrigger.ENROLLMENT);

// New enrollment that is completed
if (entity.getStatus() == EnrollmentStatus.COMPLETED) {
triggers.add(SideEffectTrigger.ENROLLMENT_COMPLETION);
}
} else {
// Existing enrollment that has changed to completed
if (persistedEnrollment.getStatus() != entity.getStatus().getProgramStatus()
&& entity.getStatus() == EnrollmentStatus.COMPLETED) {
triggers.add(SideEffectTrigger.ENROLLMENT_COMPLETION);
}
}

return triggers;
}

@Override
protected ProgramInstance convert(TrackerBundle bundle, Enrollment enrollment) {
return enrollmentConverter.from(bundle.getPreheat(), enrollment);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
import org.hibernate.Session;
import org.hisp.dhis.common.AuditType;
import org.hisp.dhis.dataelement.DataElement;
import org.hisp.dhis.event.EventStatus;
import org.hisp.dhis.eventdatavalue.EventDataValue;
import org.hisp.dhis.program.ProgramStageInstance;
import org.hisp.dhis.reservedvalue.ReservedValueService;
Expand Down Expand Up @@ -118,22 +119,9 @@ protected boolean isNew(TrackerPreheat preheat, String uid) {

@Override
protected TrackerSideEffectDataBundle handleSideEffects(
TrackerBundle bundle, ProgramStageInstance programStageInstance) {
TrackerPreheat preheat = bundle.getPreheat();
List<SideEffectTrigger> triggers = new ArrayList<>();

if (isNew(preheat, programStageInstance.getUid())) {
if (programStageInstance.isCompleted()) {
triggers.add(SideEffectTrigger.EVENT_COMPLETION);
}
} else {
ProgramStageInstance existingEvent = preheat.getEvent(programStageInstance.getUid());
if (existingEvent.getStatus() != programStageInstance.getStatus()
&& programStageInstance.isCompleted()) {
triggers.add(SideEffectTrigger.EVENT_COMPLETION);
}
}

TrackerBundle bundle,
ProgramStageInstance programStageInstance,
List<SideEffectTrigger> triggers) {
return TrackerSideEffectDataBundle.builder()
.klass(ProgramStageInstance.class)
.enrollmentRuleEffects(new HashMap<>())
Expand All @@ -150,6 +138,28 @@ protected TrackerSideEffectDataBundle handleSideEffects(
.build();
}

@Override
protected List<SideEffectTrigger> determineSideEffectTriggers(
TrackerPreheat preheat, Event entity) {
ProgramStageInstance persistedEvent = preheat.getEvent(entity.getUid());
List<SideEffectTrigger> triggers = new ArrayList<>();
// If the event is new and has been completed
if (persistedEvent == null && entity.getStatus() == EventStatus.COMPLETED) {
triggers.add(SideEffectTrigger.EVENT_COMPLETION);
return triggers;
}

// If the event is existing and its status has changed to completed
if (persistedEvent != null
&& persistedEvent.getStatus() != entity.getStatus()
&& entity.getStatus() == EventStatus.COMPLETED) {
triggers.add(SideEffectTrigger.EVENT_COMPLETION);
return triggers;
}

return triggers;
}

@Override
protected ProgramStageInstance convert(TrackerBundle bundle, Event event) {
return eventConverter.from(bundle.getPreheat(), event);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,15 @@
*/
package org.hisp.dhis.tracker.bundle.persister;

import java.util.List;
import org.hibernate.Session;
import org.hisp.dhis.reservedvalue.ReservedValueService;
import org.hisp.dhis.trackedentityattributevalue.TrackedEntityAttributeValueAuditService;
import org.hisp.dhis.tracker.TrackerType;
import org.hisp.dhis.tracker.bundle.TrackerBundle;
import org.hisp.dhis.tracker.converter.TrackerConverterService;
import org.hisp.dhis.tracker.domain.Relationship;
import org.hisp.dhis.tracker.job.SideEffectTrigger;
import org.hisp.dhis.tracker.job.TrackerSideEffectDataBundle;
import org.hisp.dhis.tracker.preheat.TrackerPreheat;
import org.springframework.stereotype.Component;
Expand Down Expand Up @@ -117,10 +119,18 @@ protected boolean isNew(TrackerPreheat preheat, String uid) {

@Override
protected TrackerSideEffectDataBundle handleSideEffects(
TrackerBundle bundle, org.hisp.dhis.relationship.Relationship entity) {
TrackerBundle bundle,
org.hisp.dhis.relationship.Relationship entity,
List<SideEffectTrigger> triggerList) {
return TrackerSideEffectDataBundle.builder().build();
}

@Override
protected List<SideEffectTrigger> determineSideEffectTriggers(
TrackerPreheat preheat, Relationship entity) {
return List.of();
}

@Override
protected TrackerType getType() {
return TrackerType.RELATIONSHIP;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
package org.hisp.dhis.tracker.bundle.persister;

import java.util.Collections;
import java.util.List;
import javax.validation.constraints.NotNull;
import org.hibernate.Session;
import org.hisp.dhis.reservedvalue.ReservedValueService;
Expand All @@ -37,6 +38,7 @@
import org.hisp.dhis.tracker.bundle.TrackerBundle;
import org.hisp.dhis.tracker.converter.TrackerConverterService;
import org.hisp.dhis.tracker.domain.TrackedEntity;
import org.hisp.dhis.tracker.job.SideEffectTrigger;
import org.hisp.dhis.tracker.job.TrackerSideEffectDataBundle;
import org.hisp.dhis.tracker.preheat.TrackerPreheat;
import org.springframework.stereotype.Component;
Expand Down Expand Up @@ -103,10 +105,16 @@ protected boolean isNew(TrackerPreheat preheat, String uid) {

@Override
protected TrackerSideEffectDataBundle handleSideEffects(
TrackerBundle bundle, TrackedEntityInstance entity) {
TrackerBundle bundle, TrackedEntityInstance entity, List<SideEffectTrigger> triggerList) {
return TrackerSideEffectDataBundle.builder().build();
}

@Override
protected List<SideEffectTrigger> determineSideEffectTriggers(
TrackerPreheat preheat, TrackedEntity entity) {
return List.of();
}

@Override
protected void persistOwnership(TrackerPreheat preheat, TrackedEntityInstance entity) {
// DO NOTHING, Tei alone does not have ownership records
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ public interface ProgramInstanceMapper extends PreheatMapper<ProgramInstance> {
@Mapping(target = "deleted")
@Mapping(target = "createdByUserInfo")
@Mapping(target = "lastUpdatedByUserInfo")
@Mapping(target = "status")
ProgramInstance map(ProgramInstance programInstance);

@Named("userGroupAccessesPi")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,100 @@ void shouldSendTrackerNotificationAtEnrollmentCompletionAndThenEventCompletion()
subjectMessages);
}

@Test
void shouldSendTrackerNotificationAtEnrollmentCompletionAndThenEventStatusChangedToCompletion() {
String eventUid = CodeGenerator.generateUid();
org.hisp.dhis.tracker.domain.Enrollment enrollment =
org.hisp.dhis.tracker.domain.Enrollment.builder()
.program(MetadataIdentifier.ofUid(programA.getUid()))
.orgUnit(MetadataIdentifier.ofUid(orgUnitA.getUid()))
.trackedEntity(trackedEntityA.getUid())
.status(EnrollmentStatus.COMPLETED)
.enrolledAt(Instant.now())
.occurredAt(Instant.now())
.enrollment(CodeGenerator.generateUid())
.build();

org.hisp.dhis.tracker.domain.Event event =
org.hisp.dhis.tracker.domain.Event.builder()
.program(MetadataIdentifier.ofUid(programA.getUid()))
.orgUnit(MetadataIdentifier.ofUid(orgUnitA.getUid()))
.enrollment(enrollment.getEnrollment())
.event(eventUid)
.programStage(MetadataIdentifier.ofUid(programStageA.getUid()))
.status(EventStatus.ACTIVE)
.attributeOptionCombo(MetadataIdentifier.EMPTY_UID)
.completedAt(Instant.now())
.occurredAt(Instant.now())
.build();

TrackerImportReport importReport =
trackerImportService.importTracker(
TrackerImportParams.builder()
.userId(user.getUid())
.importStrategy(TrackerImportStrategy.CREATE_AND_UPDATE)
.enrollments(List.of(enrollment))
.events(List.of(event))
.build());

assertNoErrors(importReport);

await()
.atMost(3, TimeUnit.SECONDS)
.until(() -> manager.getAll(MessageConversation.class).size() > 1);

List<MessageConversation> messageConversations = manager.getAll(MessageConversation.class);

List<String> subjectMessages = new ArrayList<>();
for (MessageConversation messageConversation : messageConversations) {
String subject = messageConversation.getSubject();
subjectMessages.add(subject);
}

assertContainsOnly(
List.of("enrollment_subject", "enrollment_completion_subject"), subjectMessages);

org.hisp.dhis.tracker.domain.Event updatedEvent =
org.hisp.dhis.tracker.domain.Event.builder()
.program(MetadataIdentifier.ofUid(programA.getUid()))
.orgUnit(MetadataIdentifier.ofUid(orgUnitA.getUid()))
.enrollment(enrollment.getEnrollment())
.event(eventUid)
.programStage(MetadataIdentifier.ofUid(programStageA.getUid()))
.status(EventStatus.COMPLETED)
.attributeOptionCombo(MetadataIdentifier.EMPTY_UID)
.completedAt(Instant.now())
.occurredAt(Instant.now())
.build();

importReport =
trackerImportService.importTracker(
TrackerImportParams.builder()
.userId(user.getUid())
.importStrategy(TrackerImportStrategy.CREATE_AND_UPDATE)
.events(List.of(updatedEvent))
.build());

assertNoErrors(importReport);

await()
.atMost(3, TimeUnit.SECONDS)
.until(() -> manager.getAll(MessageConversation.class).size() > 2);

messageConversations = manager.getAll(MessageConversation.class);

List<String> list = new ArrayList<>();
for (MessageConversation messageConversation : messageConversations) {
String subject = messageConversation.getSubject();
list.add(subject);
}
subjectMessages = list;

assertContainsOnly(
List.of("enrollment_subject", "enrollment_completion_subject", "event_completion_subject"),
subjectMessages);
}

@Test
void shouldSendEnrollmentCompletionNotificationOnlyOnce() {
String uid = CodeGenerator.generateUid();
Expand Down
Loading