Skip to content

Commit

Permalink
fix: use tracker importer in EventSavingSMSListener
Browse files Browse the repository at this point in the history
  • Loading branch information
teleivo committed Sep 5, 2024
1 parent f72cc52 commit ccfffec
Show file tree
Hide file tree
Showing 9 changed files with 322 additions and 414 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ public enum ValidationCode {
E1025("Property enrolledAt is null or has an invalid format: `{0}`."),
E1029("Event OrganisationUnit: `{0}`, and Program: `{1}`, don't match."),
E1030("Event: `{0}`, already exists."),
E1031("Event OccurredAt date is missing."),
E1031("Event occurredAt date is missing."),
E1032("Event: `{0}`, do not exist."),
E1033("Event: `{0}`, Enrollment value is null."),
E1035("Event: `{0}`, ProgramStage value is null."),
Expand Down Expand Up @@ -160,7 +160,7 @@ public enum ValidationCode {
E1314("Generated by program rule (`{0}`) - DataElement `{1}` is mandatory and cannot be deleted"),
E1315(
"Status `{0}` does not allow defining data values. Statuses that do allow defining data values are: {1}"),
E1316("No event can transition from status `{0}` to status `{1}.`"),
E1316("No event can transition from status `{0}` to status `{1}`."),
E1317("Generated by program rule (`{0}`) - Attribute `{1}` is mandatory and cannot be deleted"),

/* Relationship */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -136,8 +136,8 @@ protected List<Object> saveEvent(
User user,
List<SmsDataValue> values,
SmsEventStatus eventStatus,
Date eventDate,
Date dueDate,
Date occurredDate,
Date scheduledDate,
GeoPoint coordinates) {
ArrayList<Object> errorUids = new ArrayList<>();

Expand All @@ -163,8 +163,8 @@ protected List<Object> saveEvent(
event.setOrganisationUnit(orgUnit);
event.setProgramStage(programStage);
event.setEnrollment(enrollment);
event.setOccurredDate(eventDate);
event.setScheduledDate(dueDate);
event.setOccurredDate(occurredDate);
event.setScheduledDate(scheduledDate);
event.setAttributeOptionCombo(aoc);
event.setStoredBy(user.getUsername());

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,48 +27,53 @@
*/
package org.hisp.dhis.tracker.imports.sms;

import java.time.Instant;
import java.util.List;
import org.hisp.dhis.category.CategoryOptionCombo;
import java.util.Set;
import java.util.stream.Collectors;
import org.hisp.dhis.category.CategoryService;
import org.hisp.dhis.common.IdentifiableObjectManager;
import org.hisp.dhis.common.collection.CollectionUtils;
import org.hisp.dhis.dataelement.DataElementService;
import org.hisp.dhis.external.conf.DhisConfigurationProvider;
import org.hisp.dhis.feedback.ForbiddenException;
import org.hisp.dhis.feedback.NotFoundException;
import org.hisp.dhis.fileresource.FileResourceService;
import org.hisp.dhis.event.EventStatus;
import org.hisp.dhis.message.MessageSender;
import org.hisp.dhis.organisationunit.OrganisationUnit;
import org.hisp.dhis.organisationunit.OrganisationUnitService;
import org.hisp.dhis.program.Enrollment;
import org.hisp.dhis.program.ProgramService;
import org.hisp.dhis.program.ProgramStage;
import org.hisp.dhis.program.ProgramStageService;
import org.hisp.dhis.sms.incoming.IncomingSms;
import org.hisp.dhis.sms.incoming.IncomingSmsService;
import org.hisp.dhis.sms.listener.CompressionSMSListener;
import org.hisp.dhis.sms.listener.SMSProcessingException;
import org.hisp.dhis.smscompression.SmsConsts.SmsEventStatus;
import org.hisp.dhis.smscompression.SmsConsts.SubmissionType;
import org.hisp.dhis.smscompression.SmsResponse;
import org.hisp.dhis.smscompression.models.GeoPoint;
import org.hisp.dhis.smscompression.models.SmsDataValue;
import org.hisp.dhis.smscompression.models.SmsSubmission;
import org.hisp.dhis.smscompression.models.TrackerEventSmsSubmission;
import org.hisp.dhis.smscompression.models.Uid;
import org.hisp.dhis.trackedentity.TrackedEntityAttributeService;
import org.hisp.dhis.trackedentity.TrackedEntityTypeService;
import org.hisp.dhis.tracker.export.enrollment.EnrollmentService;
import org.hisp.dhis.tracker.export.event.EventChangeLogService;
import org.hisp.dhis.tracker.export.event.EventService;
import org.hisp.dhis.tracker.imports.TrackerImportParams;
import org.hisp.dhis.tracker.imports.TrackerImportService;
import org.hisp.dhis.tracker.imports.TrackerImportStrategy;
import org.hisp.dhis.tracker.imports.domain.DataValue;
import org.hisp.dhis.tracker.imports.domain.Event.EventBuilder;
import org.hisp.dhis.tracker.imports.domain.MetadataIdentifier;
import org.hisp.dhis.tracker.imports.domain.TrackerObjects;
import org.hisp.dhis.tracker.imports.report.ImportReport;
import org.hisp.dhis.tracker.imports.report.Status;
import org.hisp.dhis.user.User;
import org.hisp.dhis.user.UserDetails;
import org.hisp.dhis.user.UserService;
import org.locationtech.jts.geom.Coordinate;
import org.locationtech.jts.geom.Geometry;
import org.locationtech.jts.geom.GeometryFactory;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

@Component("org.hisp.dhis.tracker.sms.TrackerEventSMSListener")
@Transactional
public class TrackerEventSMSListener extends EventSavingSMSListener {
private final ProgramStageService programStageService;

private final EnrollmentService enrollmentService;
public class TrackerEventSMSListener extends CompressionSMSListener {
private final TrackerImportService trackerImportService;

public TrackerEventSMSListener(
IncomingSmsService incomingSmsService,
Expand All @@ -81,12 +86,7 @@ public TrackerEventSMSListener(
CategoryService categoryService,
DataElementService dataElementService,
IdentifiableObjectManager identifiableObjectManager,
EventService eventService,
EventChangeLogService eventChangeLogService,
FileResourceService fileResourceService,
DhisConfigurationProvider config,
ProgramStageService programStageService,
EnrollmentService enrollmentService) {
TrackerImportService trackerImportService) {
super(
incomingSmsService,
smsSender,
Expand All @@ -97,66 +97,86 @@ public TrackerEventSMSListener(
organisationUnitService,
categoryService,
dataElementService,
identifiableObjectManager,
eventService,
eventChangeLogService,
fileResourceService,
config);
this.programStageService = programStageService;
this.enrollmentService = enrollmentService;
identifiableObjectManager);
this.trackerImportService = trackerImportService;
}

@Override
protected SmsResponse postProcess(IncomingSms sms, SmsSubmission submission, User user)
throws SMSProcessingException {
TrackerEventSmsSubmission subm = (TrackerEventSmsSubmission) submission;

Uid ouid = subm.getOrgUnit();
Uid stageid = subm.getProgramStage();
Uid enrolmentid = subm.getEnrollment();
Uid aocid = subm.getAttributeOptionCombo();

OrganisationUnit orgUnit = organisationUnitService.getOrganisationUnit(ouid.getUid());
EventBuilder event =
org.hisp.dhis.tracker.imports.domain.Event.builder()
.event(subm.getEvent() != null ? subm.getEvent().getUid() : null)
.enrollment(subm.getEnrollment().getUid())
.orgUnit(MetadataIdentifier.ofUid(subm.getOrgUnit().getUid()))
.programStage(MetadataIdentifier.ofUid(subm.getProgramStage().getUid()))
.attributeOptionCombo(MetadataIdentifier.ofUid(subm.getAttributeOptionCombo().getUid()))
.storedBy(user.getUsername())
.occurredAt(subm.getEventDate() != null ? subm.getEventDate().toInstant() : null)
.scheduledAt(subm.getDueDate() != null ? subm.getDueDate().toInstant() : null)
.status(map(subm.getEventStatus()))
.geometry(map(subm.getCoordinates()))
.dataValues(map(user, subm.getValues()));

Enrollment enrollment;
try {
enrollment =
enrollmentService.getEnrollment(enrolmentid.getUid(), UserDetails.fromUser(user));
} catch (ForbiddenException | NotFoundException e) {
throw new SMSProcessingException(SmsResponse.INVALID_ENROLL.set(enrolmentid));
if (subm.getEventStatus() == SmsEventStatus.COMPLETED) {
event.completedBy(user.getUsername());
event.completedAt(Instant.now());
}

ProgramStage programStage = programStageService.getProgramStage(stageid.getUid());
if (programStage == null) {
throw new SMSProcessingException(SmsResponse.INVALID_STAGE.set(stageid));
TrackerImportParams params =
TrackerImportParams.builder()
.importStrategy(TrackerImportStrategy.CREATE_AND_UPDATE)
.userId(
user.getUid()) // SMS processing is done inside a job executed as the user that sent
// the SMS. We might want to remove the params user in favor of the currentUser set on
// the thread.
.build();
TrackerObjects trackerObjects = TrackerObjects.builder().events(List.of(event.build())).build();
ImportReport importReport = trackerImportService.importTracker(params, trackerObjects);

if (Status.OK == importReport.getStatus()) {
return SmsResponse.SUCCESS;
}
// TODO(DHIS2-18003) we need to map tracker import report errors/warnings to an sms
return SmsResponse.INVALID_EVENT.set(subm.getEvent());
}

CategoryOptionCombo aoc = categoryService.getCategoryOptionCombo(aocid.getUid());
if (aoc == null) {
throw new SMSProcessingException(SmsResponse.INVALID_AOC.set(aocid));
private EventStatus map(SmsEventStatus eventStatus) {
return switch (eventStatus) {
case ACTIVE -> EventStatus.ACTIVE;
case COMPLETED -> EventStatus.COMPLETED;
case VISITED -> EventStatus.VISITED;
case SCHEDULE -> EventStatus.SCHEDULE;
case OVERDUE -> EventStatus.OVERDUE;
case SKIPPED -> EventStatus.SKIPPED;
};
}

private Geometry map(GeoPoint coordinates) {
if (coordinates == null) {
return null;
}

List<Object> errorUIDs =
saveEvent(
subm.getEvent().getUid(),
orgUnit,
programStage,
enrollment,
aoc,
user,
subm.getValues(),
subm.getEventStatus(),
subm.getEventDate(),
subm.getDueDate(),
subm.getCoordinates());
if (!errorUIDs.isEmpty()) {
return SmsResponse.WARN_DVERR.setList(errorUIDs);
} else if (subm.getValues() == null || subm.getValues().isEmpty()) {
// TODO: Should we save the event if there are no data values?
return SmsResponse.WARN_DVEMPTY;
return new GeometryFactory()
.createPoint(new Coordinate(coordinates.getLongitude(), coordinates.getLatitude()));
}

private Set<DataValue> map(User user, List<SmsDataValue> dataValues) {
if (CollectionUtils.isEmpty(dataValues)) {
return Set.of();
}

return SmsResponse.SUCCESS;
return dataValues.stream()
.map(
dv ->
DataValue.builder()
.dataElement(MetadataIdentifier.ofUid(dv.getDataElement().getUid()))
.value(dv.getValue())
.storedBy(user.getUsername())
.build())
.collect(Collectors.toSet());
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ private static String formatArgument(TrackerIdSchemeParams idSchemes, Object arg
if (Event.class.isAssignableFrom(type)) return ((Event) argument).getEvent();
if (TrackedEntity.class.isAssignableFrom(type))
return ((TrackedEntity) argument).getTrackedEntity();
return "";
return argument.toString();
}

private static String getIdAndName(MetadataIdentifier identifier) {
Expand Down
Loading

0 comments on commit ccfffec

Please sign in to comment.