Program Workflow refactoring

6 messages Options
Embed this post
Permalink
Burke Mamlin

Program Workflow refactoring

Reply Threaded More More options
Print post
Permalink
Tammy/Vibha,

Do you have any documentation or description of how program/workflow  
was adapted for CHICA's needs?  Any chance either of you are going to  
be going to AMIA?

-Burke

_________________________________________

To unsubscribe from OpenMRS Developers' mailing list, send an e-mail to [hidden email] with "SIGNOFF openmrs-devel-l" in the  body (not the subject) of your e-mail.

[mailto:[hidden email]?body=SIGNOFF%20openmrs-devel-l]
Anand, Vibha

Re: Program Workflow refactoring

Reply Threaded More More options
Print post
Permalink
Burke

The program/workflow was not used for CHICA's needs because the major flaw I saw at the time was it being non-deterministic. We ended up writing our own DFA state machine which is linked to atomic actions at each state (also configurable by use of custom java classes). This has been on the backburner but we have discussed with Paul a couple of times that it needs to go back in the core.

We are using the program as a high level construct to drive the machine (not based on concept id as is the case now) and more recently we have added support to configure same or different programs for different locations / sub-locations. Tammy can perhaps fill in the gaps here, she is not going to be at AMIA but I will be and can answer more if you like. Also, if there is any discussion about SMS services in OpenMRS at AMIA, I would like to participate. Please let me know. Thanks!

Vibha


-----Original Message-----
From: [hidden email] [mailto:[hidden email]] On Behalf Of Burke Mamlin
Sent: Thursday, November 05, 2009 11:34 AM
To: [hidden email]
Subject: [OPENMRS-DEV] Program Workflow refactoring

Tammy/Vibha,

Do you have any documentation or description of how program/workflow  
was adapted for CHICA's needs?  Any chance either of you are going to  
be going to AMIA?

-Burke

_________________________________________

To unsubscribe from OpenMRS Developers' mailing list, send an e-mail to [hidden email] with "SIGNOFF openmrs-devel-l" in the  body (not the subject) of your e-mail.

[mailto:[hidden email]?body=SIGNOFF%20openmrs-devel-l]

_________________________________________

To unsubscribe from OpenMRS Developers' mailing list, send an e-mail to [hidden email] with "SIGNOFF openmrs-devel-l" in the  body (not the subject) of your e-mail.

[mailto:[hidden email]?body=SIGNOFF%20openmrs-devel-l]
Tammy Dugan

Re: Program Workflow refactoring

Reply Threaded More More options
Print post
Permalink
It is pretty complicated so I am going to take some time this afternoon
and pull the state stuff out of atd and put it in a module. Once that is
done I will try to send a brief overview to the list and reference the
module for specifics.

Thanks,

Tammy

Anand, Vibha wrote:

> Burke
>
> The program/workflow was not used for CHICA's needs because the major flaw I saw at the time was it being non-deterministic. We ended up writing our own DFA state machine which is linked to atomic actions at each state (also configurable by use of custom java classes). This has been on the backburner but we have discussed with Paul a couple of times that it needs to go back in the core.
>
> We are using the program as a high level construct to drive the machine (not based on concept id as is the case now) and more recently we have added support to configure same or different programs for different locations / sub-locations. Tammy can perhaps fill in the gaps here, she is not going to be at AMIA but I will be and can answer more if you like. Also, if there is any discussion about SMS services in OpenMRS at AMIA, I would like to participate. Please let me know. Thanks!
>
> Vibha
>
>
> -----Original Message-----
> From: [hidden email] [mailto:[hidden email]] On Behalf Of Burke Mamlin
> Sent: Thursday, November 05, 2009 11:34 AM
> To: [hidden email]
> Subject: [OPENMRS-DEV] Program Workflow refactoring
>
> Tammy/Vibha,
>
> Do you have any documentation or description of how program/workflow  
> was adapted for CHICA's needs?  Any chance either of you are going to  
> be going to AMIA?
>
> -Burke
>
> _________________________________________
>
> To unsubscribe from OpenMRS Developers' mailing list, send an e-mail to [hidden email] with "SIGNOFF openmrs-devel-l" in the  body (not the subject) of your e-mail.
>
> [mailto:[hidden email]?body=SIGNOFF%20openmrs-devel-l]
>
> _________________________________________
>
> To unsubscribe from OpenMRS Developers' mailing list, send an e-mail to [hidden email] with "SIGNOFF openmrs-devel-l" in the  body (not the subject) of your e-mail.
>
> [mailto:[hidden email]?body=SIGNOFF%20openmrs-devel-l]
>  

_________________________________________

To unsubscribe from OpenMRS Developers' mailing list, send an e-mail to [hidden email] with "SIGNOFF openmrs-devel-l" in the  body (not the subject) of your e-mail.

[mailto:[hidden email]?body=SIGNOFF%20openmrs-devel-l]
Tammy Dugan

Re: Program Workflow refactoring

Reply Threaded More More options
Print post
Permalink
In reply to this post by Burke Mamlin
I created a module called stateprocessing? Is it OK to commit it?


Tammy Dugan

Burke Mamlin wrote:

> Tammy/Vibha,
>
> Do you have any documentation or description of how program/workflow
> was adapted for CHICA's needs?  Any chance either of you are going to
> be going to AMIA?
>
> -Burke
>
> _________________________________________
>
> To unsubscribe from OpenMRS Developers' mailing list, send an e-mail
> to [hidden email] with "SIGNOFF openmrs-devel-l" in the  
> body (not the subject) of your e-mail.
>
> [mailto:[hidden email]?body=SIGNOFF%20openmrs-devel-l]

_________________________________________

To unsubscribe from OpenMRS Developers' mailing list, send an e-mail to [hidden email] with "SIGNOFF openmrs-devel-l" in the  body (not the subject) of your e-mail.

[mailto:[hidden email]?body=SIGNOFF%20openmrs-devel-l]
Tammy Dugan

Re: Program Workflow refactoring

Reply Threaded More More options
Print post
Permalink
I just committed the stateprocessing module. After my meeting this
morning, I will send some documentation to the list about the
stateprocessing module along with the randomization module (since Darius
mentioned supporting studies, which the randomization module does).

Tammy Dugan

Tammy Dugan wrote:

> I created a module called stateprocessing? Is it OK to commit it?
>
>
> Tammy Dugan
>
> Burke Mamlin wrote:
>> Tammy/Vibha,
>>
>> Do you have any documentation or description of how program/workflow
>> was adapted for CHICA's needs?  Any chance either of you are going to
>> be going to AMIA?
>>
>> -Burke
>>
>> _________________________________________
>>
>> To unsubscribe from OpenMRS Developers' mailing list, send an e-mail
>> to [hidden email] with "SIGNOFF openmrs-devel-l" in the  
>> body (not the subject) of your e-mail.
>>
>> [mailto:[hidden email]?body=SIGNOFF%20openmrs-devel-l]
>
> _________________________________________
>
> To unsubscribe from OpenMRS Developers' mailing list, send an e-mail
> to [hidden email] with "SIGNOFF openmrs-devel-l" in the  
> body (not the subject) of your e-mail.
>
> [mailto:[hidden email]?body=SIGNOFF%20openmrs-devel-l]

_________________________________________

To unsubscribe from OpenMRS Developers' mailing list, send an e-mail to [hidden email] with "SIGNOFF openmrs-devel-l" in the  body (not the subject) of your e-mail.

[mailto:[hidden email]?body=SIGNOFF%20openmrs-devel-l]
Tammy Dugan

Re: Program Workflow refactoring

Reply Threaded More More options
Print post
Permalink
The "randomization" module supports study definition and randomization.
It should be fairly self explanatory.

Here is a brief overview of the state processing in the
"stateprocessing" module:

StateManager class
-------------------
This class takes care of making state transitions (based on the state
mapping table), recording the current patient state in the patient_state
table, and processing the state action.

StateActionHandler class
--------------------------
This is an interface that is implemented to tell how to process actions.
I don't think this really needs to exist anymore now that we have the
action_class column in the state_action table. Attached is the
ChicaStateActionHandler class that we use to implement this interface.
The interface method defined in this class can probably be moved into
StateActionHandler and remove the need for an interface.

ProcessStateAction class
--------------------------
This is an interface implemented by state actions to tell what code
should be executed for the action. There are two methods: processAction
and changeState. The processAction method is the method that gets called
to initiate a method transition. It can optionally end the patient
state. The changeState method is used when the code has to wait for some
external event trigger (the presence of a file created by Teleform, for
example). The changeState method executes some code and ends the patient
state.

state table
-----------
The state table keeps track of state metadata like name, description,
etc. It also links to a state action from the state_action table to
describe what java code should run when entering the given state. The
form_name column is currently used to keep track of the name of the form
that we want to produce from a given state. Since we can have different
forms for different clinic locations, we look up the exact form
configuration in a location_tag_attribute_value table that we created.
The form_name column probably needs to be replaced by some other way of
configuring things.

state_action table
-----------------
This table keeps track of state action metadata like name, description,
etc. The action_class column defines the class that executes the action.
This class must implement the ProcessStateAction interface.

state_mapping table
--------------------
This table defines the transitions between states for a given program.
The program id points to our version of the program table.

program table
--------------
This table defines metadata about the program including start and end
states.

program_tag_map
-----------------
This table defines links between location and location_tag and a given
program so we can look up program by location information.

patient_state
-------------
The patient state table keeps track of what state the patient is
currently in. We keep track of patien_id,state_id,start_time, and
end_time. We also keep track of location_id and location_tag_id so we
can associate the states with specific clinic locations. We have
retirement columns so the states can be retired. We also keep track of a
session_id that keeps track of the given instance of state transitions
from the state_mapping table for the given patient. We also keep track
of form based information like form_id and form_instance_id to know
which instance of the form we are talking about.

session
-------
This table auto generates the session id for each patient's instance of
a program's state mapping process. It also links a session with an
encounter. Multiple sessions are allowed for a single encounter.

form_instance
--------------
This table generates a unique id for each form NAME per location. It is
form name and not form_id because we don't want to start the numbering
over again if we just update to a new form version.

These are some configuration tables that we created to extend the
openmrs data model that we would like to see in core as well:

atd_form_attribute
atd_form_attribute_value
location_attribute
location_attribute_value
location_tag_attribute
location_tag_attribute_value

The data model we are using could use some design tweaking but it is
functional and running live in two clinics right now. Please let me know
if you have any questions. I would love to get as much of this code into
core as possible so we don't have to maintain it.

Thanks,

Tammy Dugan


Tammy Dugan wrote:

> I just committed the stateprocessing module. After my meeting this
> morning, I will send some documentation to the list about the
> stateprocessing module along with the randomization module (since
> Darius mentioned supporting studies, which the randomization module
> does).
>
> Tammy Dugan
>
> Tammy Dugan wrote:
>> I created a module called stateprocessing? Is it OK to commit it?
>>
>>
>> Tammy Dugan
>>
>> Burke Mamlin wrote:
>>> Tammy/Vibha,
>>>
>>> Do you have any documentation or description of how program/workflow
>>> was adapted for CHICA's needs?  Any chance either of you are going
>>> to be going to AMIA?
>>>
>>> -Burke
>>>
>>> _________________________________________
>>>
>>> To unsubscribe from OpenMRS Developers' mailing list, send an e-mail
>>> to [hidden email] with "SIGNOFF openmrs-devel-l" in
>>> the  body (not the subject) of your e-mail.
>>>
>>> [mailto:[hidden email]?body=SIGNOFF%20openmrs-devel-l]
>>
>> _________________________________________
>>
>> To unsubscribe from OpenMRS Developers' mailing list, send an e-mail
>> to [hidden email] with "SIGNOFF openmrs-devel-l" in the  
>> body (not the subject) of your e-mail.
>>
>> [mailto:[hidden email]?body=SIGNOFF%20openmrs-devel-l]
>
> _________________________________________
>
> To unsubscribe from OpenMRS Developers' mailing list, send an e-mail
> to [hidden email] with "SIGNOFF openmrs-devel-l" in the  
> body (not the subject) of your e-mail.
>
> [mailto:[hidden email]?body=SIGNOFF%20openmrs-devel-l]
_________________________________________

To unsubscribe from OpenMRS Developers' mailing list, send an e-mail to [hidden email] with "SIGNOFF openmrs-devel-l" in the  body (not the subject) of your e-mail.

[mailto:[hidden email]?body=SIGNOFF%20openmrs-devel-l]

/**
 *
 */
package org.openmrs.module.chica;

import java.io.FileInputStream;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.HashMap;
import java.util.List;
import java.util.Set;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.openmrs.Concept;
import org.openmrs.FormField;
import org.openmrs.Location;
import org.openmrs.LocationTag;
import org.openmrs.Obs;
import org.openmrs.Patient;
import org.openmrs.api.AdministrationService;
import org.openmrs.api.ConceptService;
import org.openmrs.api.LocationService;
import org.openmrs.api.ObsService;
import org.openmrs.api.PatientService;
import org.openmrs.api.context.Context;
import org.openmrs.logic.LogicService;
import org.openmrs.logic.result.EmptyResult;
import org.openmrs.logic.result.Result;
import org.openmrs.module.atd.StateActionHandler;
import org.openmrs.module.atd.StateManager;
import org.openmrs.module.atd.TeleformFileMonitor;
import org.openmrs.module.atd.TeleformFileState;
import org.openmrs.module.atd.action.ProcessStateAction;
import org.openmrs.module.atd.datasource.TeleformExportXMLDatasource;
import org.openmrs.module.atd.hibernateBeans.ATDError;
import org.openmrs.module.atd.hibernateBeans.FormInstance;
import org.openmrs.module.atd.hibernateBeans.PatientState;
import org.openmrs.module.atd.hibernateBeans.Program;
import org.openmrs.module.atd.hibernateBeans.State;
import org.openmrs.module.atd.hibernateBeans.StateAction;
import org.openmrs.module.atd.service.ATDService;
import org.openmrs.module.chica.advice.ThreadManager;
import org.openmrs.module.chica.hibernateBeans.Encounter;
import org.openmrs.module.chica.service.ChicaService;
import org.openmrs.module.chica.service.EncounterService;
import org.openmrs.module.chica.util.Util;

/**
 * @author tmdugan
 *
 */
public class ChicaStateActionHandler implements StateActionHandler
{
        private static Log log = LogFactory.getLog(ChicaStateActionHandler.class);
        private static ChicaStateActionHandler stateActionHandler = null;
       
        public void fillUnfinishedStates()
        {
                AdministrationService adminService = Context.getAdministrationService();
                Context.authenticate(adminService
                                .getGlobalProperty("scheduler.username"), adminService
                                .getGlobalProperty("scheduler.password"));

                ATDService atdService = Context.getService(ATDService.class);
                Calendar todaysDate = Calendar.getInstance();
                todaysDate.set(Calendar.HOUR_OF_DAY, 0);
                todaysDate.set(Calendar.MINUTE, 0);
                todaysDate.set(Calendar.SECOND, 0);
                LocationService locationService = Context.getLocationService();

                List<Location> locations = locationService.getAllLocations();
               
                for(Location location:locations){
               
                Set<LocationTag> tags = location.getTags();
               
                if(tags != null){
               
                        for(LocationTag tag:tags){
                                Integer locationId = location.getLocationId();
                                Integer locationTagId = tag.getLocationTagId();
                List<PatientState> unfinishedStatesToday = atdService.
                        getUnfinishedPatientStatesAllPatients(todaysDate.getTime(),locationTagId,locationId);
                               
                int numUnfinishedStates = unfinishedStatesToday.size();
                double processedStates = 0;
               
                log.info("fillUnfinishedStates(): Starting Today's state initialization....");
                for(PatientState currPatientState:unfinishedStatesToday)
                {
                        State state = currPatientState.getState();
                        if (state != null)
                        {
                                StateAction stateAction = state.getAction();

                                try
                                {
                                        if (stateAction!=null&&stateAction.getActionName().equalsIgnoreCase(
                                                        "CONSUME FORM INSTANCE"))
                                        {
                                                TeleformFileState teleformFileState = TeleformFileMonitor
                                                        .addToPendingStatesWithoutFilename(
                                                                currPatientState.getFormInstance());
                                                teleformFileState.addParameter("patientState",
                                                                currPatientState);
                                        }
                                        HashMap<String,Object> parameters = new HashMap<String,Object>();
                                        parameters.put("formInstance", currPatientState.getFormInstance());
                                        processAction(stateAction, currPatientState.getPatient(),
                                                        currPatientState,parameters);
                                } catch (Exception e)
                                {
                                        log.error(e.getMessage());
                                        log
                                                        .error(org.openmrs.module.dss.util.Util
                                                                        .getStackTrace(e));
                                }
                        }
                        if(processedStates%100==0){
                                log.info("State initialization is: "+(int)((processedStates/numUnfinishedStates)*100)+"% complete. "+
                                                processedStates+" out of "+numUnfinishedStates+" processed.");
                        }
                        processedStates++;
                }
               
                log.info("Today's state initialization is: "+(int)((processedStates/numUnfinishedStates)*100)+"% complete.");
                }}}
                Thread thread = new Thread(new InitializeOldStates());
                ThreadManager.startThread(thread);
        }
       
        public static ChicaStateActionHandler getInstance()
        {
                if(stateActionHandler == null){
                        stateActionHandler = new ChicaStateActionHandler();
                }
                return stateActionHandler;
        }
       
        public ChicaStateActionHandler(){
               
        }
       
        private ProcessStateAction loadProcessStateAction(StateAction stateAction){
               
                ProcessStateAction processStateAction = null;
               
                try
                {
                        String stateActionClass = stateAction.getActionClass();
                        Class classInstatiation = Class.forName(stateActionClass);
                        if(stateActionClass == null)
                        {
                                return null;
                        }
                        //class the initialization method is in
                        processStateAction = (ProcessStateAction) classInstatiation.newInstance();
                } catch (Exception e)
                {
                        log.error(e.getMessage());
                        log.error(org.openmrs.module.dss.util.Util.getStackTrace(e));
                }
                return processStateAction;
        }
       
        public synchronized void changeState(PatientState patientState,
                        HashMap<String,Object> parameters) throws Exception{
                StateAction stateAction = patientState.getState().getAction();
                if (stateAction == null)
                {
                        return;
                }

                ProcessStateAction processStateAction = loadProcessStateAction(stateAction);

                if (processStateAction != null)
                {
                        processStateAction.changeState(patientState, parameters);
                }
        }
       
        public synchronized void processAction(StateAction stateAction, Patient patient,
                        PatientState patientState,HashMap<String,Object> parameters) throws Exception
        {
                if (stateAction == null)
                {
                        return;
                }

                // lookup the patient again to avoid lazy initialization errors
                PatientService patientService = Context.getPatientService();
                Integer patientId = patient.getPatientId();
                patient = patientService.getPatient(patientId);

                ProcessStateAction processStateAction = loadProcessStateAction(stateAction);

                if (processStateAction != null)
                {
                        processStateAction.processAction(stateAction, patient,
                                        patientState, parameters);
                }
        }

        public static synchronized void consume(Integer sessionId,FormInstance formInstance,Patient patient,
                        HashMap<String,Object> parameters,List<FormField> fieldsToConsume,
                        Integer locationTagId)
        {
                AdministrationService adminService = Context.getAdministrationService();
                ATDService atdService = Context.getService(ATDService.class);
                ChicaService chicaService = Context.getService(ChicaService.class);
                Integer encounterId = atdService.getSession(sessionId).getEncounterId();
                String exportFilename = null;
               
                if(parameters != null){
                        exportFilename = (String) parameters.get("filename");
                }
                try
                {
                        InputStream input = new FileInputStream(exportFilename);
                       
                        chicaService.consume(input,patient,encounterId,
                                        formInstance,sessionId,fieldsToConsume,locationTagId);
                        input.close();
                } catch (Exception e)
                {
                        log.error("Error consuming chica file: " + exportFilename);
                        log.error(e.getMessage());
                        log.error(org.openmrs.module.dss.util.Util.getStackTrace(e));
                }
               
                // save specific observations
                saveObs(encounterId, patient,locationTagId);

                // remove the parsed xml from the xml datasource
                try
                {
                        Integer purgeXMLDatasourceProperty = null;
                        try
                        {
                                purgeXMLDatasourceProperty = Integer.parseInt(adminService
                                                .getGlobalProperty("atd.purgeXMLDatasource"));
                        } catch (Exception e)
                        {
                        }
                        LogicService logicService = Context.getLogicService();

                        TeleformExportXMLDatasource xmlDatasource = (TeleformExportXMLDatasource) logicService
                                        .getLogicDataSource("xml");
                        if (purgeXMLDatasourceProperty != null
                                        && purgeXMLDatasourceProperty == 1)
                        {
                                xmlDatasource.deleteParsedFile(formInstance);
                        }
                } catch (Exception e)
                {
                        log.error(e.getMessage());
                        log.error(org.openmrs.module.dss.util.Util.getStackTrace(e));
                }
        }
       
        private static synchronized void saveObs(Integer encounterId,Patient patient,
                        Integer locationTagId){
                EncounterService encounterService = Context.getService(EncounterService.class);
                Encounter encounter = (Encounter) encounterService.getEncounter(encounterId);
                ObsService obsService = Context.getObsService();
                ATDService atdService = Context.getService(ATDService.class);
                List<org.openmrs.Encounter> encounters = new ArrayList<org.openmrs.Encounter>();
                encounters.add(encounter);
                List<Concept> questions = new ArrayList<Concept>();
                HashMap<String,Object> parameters = new HashMap<String,Object>();
                Calculator calculator = new Calculator();
                parameters.put("encounterId", encounterId);
                ConceptService conceptService = Context.getConceptService();
                Concept concept = conceptService.getConcept("BMICentile");
                questions.add(concept);
                List<Obs> obs = obsService.getObservations(null, encounters, questions, null, null, null, null,
                                null, null, null, null, false);
               
                if (obs == null || obs.size() == 0)
                {
                        Result result = atdService.evaluateRule("bmi", patient, parameters,
                                        null);

                        if (!(result instanceof EmptyResult))
                        {
                                Double percentile = calculator.calculatePercentile(result
                                                .toNumber(), patient.getGender(), patient
                                                .getBirthdate(), "bmi", null);
                                if (percentile != null)
                                {
                                        percentile = org.openmrs.module.dss.util.Util.round(
                                                        percentile, 2); // round percentile to two places
                                        Util.saveObs(patient, concept, encounterId, percentile
                                                        .toString(), null,null,locationTagId);
                                }
                        }
                }
               
                questions = new ArrayList<Concept>();
                concept = conceptService.getConcept("HCCentile");
                questions.add(concept);
                obs = obsService.getObservations(null, encounters, questions, null, null, null, null,
                                null, null, null, null, false);
               
                if(obs == null || obs.size()==0){
                        parameters.put("concept", "HC");
                        Result result = atdService.evaluateRule("conceptRule", patient, parameters, null);
                        if (!(result instanceof EmptyResult))
                        {
                                Double percentile = calculator.calculatePercentile(result
                                                .toNumber(), patient.getGender(), patient
                                                .getBirthdate(), "hc", null);
                                if (percentile != null)
                                {
                                        percentile = org.openmrs.module.dss.util.Util.round(
                                                        percentile, 2); // round percentile to two places
                                        Util.saveObs(patient, concept, encounterId, percentile
                                                        .toString(), null,null,locationTagId);
                                }
                        }
                }
               
                questions = new ArrayList<Concept>();
                concept = conceptService.getConcept("HtCentile");
                questions.add(concept);
                obs = obsService.getObservations(null, encounters, questions, null, null, null, null,
                                null, null, null, null, false);
               
                if(obs == null || obs.size()==0){
                        parameters.put("concept", "HEIGHT");
                        Result result = atdService.evaluateRule("conceptRule", patient, parameters, null);
                        if (!(result instanceof EmptyResult))
                        {
                                Double percentile = calculator.calculatePercentile(result
                                                .toNumber(), patient.getGender(), patient
                                                .getBirthdate(), "length", org.openmrs.module.dss.util.Util.MEASUREMENT_IN);
                                if (percentile != null)
                                {
                                        percentile = org.openmrs.module.dss.util.Util.round(
                                                        percentile, 2); // round percentile to two places
                                        Util.saveObs(patient, concept, encounterId, percentile
                                                        .toString() , null,null,locationTagId);
                                }
                        }
                }
               
                questions = new ArrayList<Concept>();
                concept = conceptService.getConcept("WtCentile");
                questions.add(concept);
                obs = obsService.getObservations(null, encounters, questions, null, null, null, null,
                                null, null, null, null, false);
               
                if(obs == null || obs.size()==0){
                        parameters.put("concept", "WEIGHT");
                        Result result = atdService.evaluateRule("conceptRule", patient, parameters, null);
                        if (!(result instanceof EmptyResult))
                        {
                                Double percentile = calculator.calculatePercentile(result
                                                .toNumber(), patient.getGender(), patient
                                                .getBirthdate(), "weight",
                                                org.openmrs.module.dss.util.Util.MEASUREMENT_LB);
                                if (percentile != null)
                                {
                                        percentile = org.openmrs.module.dss.util.Util.round(
                                                        percentile, 2); // round percentile to two places
                                        Util.saveObs(patient, concept, encounterId, percentile
                                                        .toString(), null,null,locationTagId);
                                }
                        }
                }
               
                //save BP
                questions = new ArrayList<Concept>();
                concept = conceptService.getConcept("BP");
                questions.add(concept);
                obs = obsService.getObservations(null, encounters, questions, null, null, null, null,
                                null, null, null, null, false);
               
                if(obs == null || obs.size()==0){
                        Result result = atdService.evaluateRule("bp", patient, parameters, null);
                        if (!(result instanceof EmptyResult))
                        {
                                Util.saveObs(patient, concept, encounterId, result
                                                        .toString(), null,
                                                        null,locationTagId);
                        }
                }
               
                //save BMI
                questions = new ArrayList<Concept>();
                concept = conceptService.getConcept("BMI CHICA");
                questions.add(concept);
                obs = obsService.getObservations(null, encounters, questions, null, null, null, null,
                                null, null, null, null, false);
               
                if(obs == null || obs.size()==0){
                        Result result = atdService.evaluateRule("bmi", patient, parameters, null);
                        if (!(result instanceof EmptyResult))
                        {
                                Util.saveObs(patient, concept, encounterId, result
                                                        .toString(), null,
                                                        null,locationTagId);
                        }
                }
        }
       
        public static synchronized void changeState(Patient patient, Integer sessionId,
                        State currState,StateAction action,
                        HashMap<String,Object> parameters,
                        Integer locationTagId,Integer locationId) throws Exception
        {
                ATDService atdService = Context.getService(ATDService.class);
                List<ATDError> errors = null;
                // change to error state if fatal error exists for session
                //only look up errors for consume state, for now
                if (action!=null&&action.getActionName().equalsIgnoreCase("CONSUME FORM INSTANCE"))
                {
                        errors = atdService.getATDErrorsByLevel(
                                        "Fatal", sessionId);
                }
                if (errors != null && errors.size() > 0)
                {
                        //open an error state
                        currState = atdService.getStateByName("ErrorState");
                        atdService.addPatientState(patient,
                                        currState, sessionId,locationTagId,locationId);
                } else
                {
                        Program program = atdService.getProgram(locationTagId,locationId);
                        StateManager.changeState(patient, sessionId, currState,program,
                                        parameters,locationTagId,locationId,ChicaStateActionHandler.getInstance());
                }

        }
}

_________________________________________

To unsubscribe from OpenMRS Developers' mailing list, send an e-mail to [hidden email] with "SIGNOFF openmrs-devel-l" in the  body (not the subject) of your e-mail.

[mailto:[hidden email]?body=SIGNOFF%20openmrs-devel-l]