Schedules and Alerts Processing Using EC Data


In  Version 2.0, OpenSRP server app will be using events/clients data to generate enroll clients into various schedules. The diagram below highlights the hierarchical order of the classes involved in implementing the logic for enrolling, fulfilling, unenrolling clients into/from different milestones based on the events generated from the form submissions and also creating actions/alerts in the couchdb for syncing to the client app. 

Schedule Config Files

Since it's events that lead to clients joining schedules, some JSON config files are required to serve as  a guide to the EventsRouter class when determining which event leads to a client joining a given schedule and forwarding this event to the respective ScheduleHandler for processing. Authoring a schedule config file mainly involves specifying events, action,reference_date_fields and enrollment/unenrolment/fulfillment_fields that the scheduling logic should look out for in an event to automatically determine which schedule a client quailifies to join, fulfill or unenroll. These fields are questions and answers from the form submissions most of the times in form of OpenMRS concepts. In particular in the events object:

  • types are the event types to look out for
  • enrollment_fields are the conditions that must be satisfied to enroll a client to a schedule. Concept key in this object is the question that must be satisfied with answer specified in the value key. NOT_EMPTY in the value key means that value can be anything except and empty string. When not using a concept as the question, specify any other key as filed: {field_name} as shown in the fulfillment_date_fields
  • reference_date_field is the field that has the date to be used as the schedule reference date,
  • action specifies what should happen when a condition is satisfied i.e either to enroll/unenroll or fulfill a milestone
  • pass_logic is either AND/OR, when AND all the conditions in the enrollment_field must be satisfied
  • milestone is the the milestone affected by the specified condition

Sample schedule config file
{
                    "name": "Ante Natal Care - Normal",
                    "handler": "ANCScheduleHandler",
                    "events": [
                        {
                            "types": ["Pregnancy Surveillance and Registration"],
                            "pass_logic": "AND",
                            "enrollment_fields": [
                                {
                                    "concept": "162942AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
                                    "value":"1065AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
                                }
                            ],
                            "milestone": "ANC 1",
                            "reference_date_fields": [
                                {
                                  "concept": "1427AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
                                  "value": "NOT_EMPTY"
                                }
                             ],
                            "action": "enroll"
                        },
                        {
                            "types": ["ANC Reminder Visit 1"],
                            "pass_logic": "AND",
                            "fulfillment_date_fields": [
                                {
                                    "field": "eventDate",
                                    "value": "NOT_EMPTY"
                                }
                            ],
                            "milestone": "ANC 1",
                            "action": "fulfill"
                        }
                    ]
    
}




ClassModuleNotes
ApplicationStartupListeneropensrp-webThis is an implementation of the Spring ApplicationListener that listens for the web app context refresh event. It's in this class that an events processing repeating schedule is wired with the event subject EVENTS-SCHEDULE. Using MotechSchedulerService class a repeating job is started here to run every two minutes. After every two minutes the job emits the "EVENTS-SCHECULE" event subject which is consumed by the EventsListener class.
EventsListeneropensrp-coreThis class consumes the event emitted by the repeating job configured in the ApplicationStartupListener class by adding @MotechListener(subjects =AllConstants.EVENTS_SCHEDULE_SUBJECT) annotation to the processEvent method. It's in this method that the latest events are fetched and forwarded to the EventsRouter. To keep track of the last processed events, an app_state_token(EVENTS_PARSER_LAST_PROCESSED_EVENT) is created in the ConfigService and set to save the last processed event version value in the couch database.

EventsRouter

opensrp-coreIn this class IHandlerMapper implementation (EventsHandlerMapper in opensrp-register module) is injected. EventsHandlerMapper contains a Java util map of schedule handlers instances whereby the key is the name of the handler class and the value is the autowired instance of the handler class. Having loaded the events handlermapper, in the route(Event _event) method of the EventsRouter class, getScheduleConfigs() method is called to iterate through the schedule configs folder and read all the files concatenating them into a JSONArray object for easier processing. With the scheduleconfigs JSONArray, the route method iterates through this array to retrieve each of the scheduleconfig JSON objects (either the enroll, unenroll or fulfill JSON object) passing the object to processScheduleConfigEvents() which compares the events specified in the types JSON key with the current event from the EventsListener class. If a match is found, the event from the EventsListener class is forwarded to the respective schedule handler in the handlermap for processing.

ScheduleHandlers

opensrp-registerScheduleHandlers are the classes that have the logic that determines further if an event qualifies a client to joining a schedule and extend BaseScheduleHandler abstract class. The handle method has two parameters: event (the event from couchdb) and scheduleConfigEvent (the JSON object from the scheduleconfig file events key). Using these two params, evaluateEvent() method in the BaseScheduleHandler is called to determine if the conditions specified in the scheduleconfigs enrollment/fulfillment fields are met. The evaluateEvent() method returns a boolean value true if all the conditions are met and respective schedule service is called to accomplish the specified action in the scheduleconfigs.
HealthSchedulerServiceopensrp-coreThis class has the common methods used in handling enrollments, fulfillments, unenrolments and the alertFor() method which is called by ECAlertCreationAction class when creating actions for a client when motech issues an alert notification and further calls ActionService to save the action/alert in couchdb.
ScheduleServiceopensrp-core

This class builds Motech EnrollmentRequests that are passed to Motech ScheduleTrackingService enroll method. For OpenSRP EC alerts processing the enrollmentrequest should have the following values:

  • externalId- this is the client baseEntityId equivalent to the value returned by the method event.getBaseEntityId()
  • scheduleName- the current schedule name as it appears in the schedule files e.g Ante Natal Care - Normal
  • preferredAlertTime- Time of the day to send alerts to a client, this value is specified in opensrp.properties (preferred.time) property as 7am. NB If no preferred time is specified, all alerts will be raised exactly as per their offset from the date and time of enrollment
  • referenceDate-This is the start date of the schedule based on which all the window duration calculations are made
  • startingMilestoneName- The name of the first milestone into which the user will be directly enrolled
  • metadata- Additional information stored as key/value pair in Java util map. The value event.getId() is passed with the key enrollmentEvent. This value is later on retrieved in the ECAlertCreation class when Motech emits a MILESTONE_ALERT event and it's used to retrieve the event that enrolled a client into a schedule to retrieve entityType, providerId and any other value that might be required in building an action/alert for syncing to the client app

For more info about Motech see: http://modules.motechproject.org/en/latest/schedule_tracking.html#schedule-tracking-module, http://modules.motechproject.org/en/latest/schedule_tracking/sample_schedule.html#sample-schedule-definition


AlertRouteropensrp-core

The EnrollmentAlertService in Motech API emits events with the subject EventSubjects.MILESTONE_ALERT every time an alert is ready as per the schedule definition windows (earliest,due,late) otherwise EventSubjects.DEFAULTMENT_CAPTURE is emitted for the defaulted milestone windows alerts. It's after this event is emitted that the process to create an alert/action syncable to the client app is created and saved to couchdb. To listen to these events the AlertRouter class handleAlerts(MotechEvent realEvent) method is annotated with @MotechListener(subjects = {EventSubjects.MILESTONE_ALERT, EventSubjects.DEFAULTMENT_CAPTURE}) and forwards the info from the MotechEvent object to ECAlertCreationAction for alerts/action creation.

Currently emitted events with the subject EventSubjects.DEFAULTMENT_CAPTURE  are not being handled and throw NPE. Fix needed

ECAlertCreationActionopensrp-coreThis class calls the alertFor() method in HealthSchedulerService class passing the required params for creating an action
ActionServiceopensrp-coreHas the actions CRUD methods and it's here that the alerts are finally saved to couchdb ready for syncing to the client app