Skip to content

Commit

Permalink
Merge pull request openmrs#2643 from shifona1/TRUNK-5230
Browse files Browse the repository at this point in the history
Trunk-5230: PatientProgram: When completing a program, the end date of the most recent state in each workflow should be set to the completion date of the program
  • Loading branch information
mogoodrich authored Apr 11, 2018
2 parents 06a5393 + 49ed1b1 commit b611763
Show file tree
Hide file tree
Showing 3 changed files with 268 additions and 1 deletion.
26 changes: 26 additions & 0 deletions api/src/main/java/org/openmrs/PatientProgram.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
import java.util.List;
import java.util.Set;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

import org.openmrs.customdatatype.CustomValueDescriptor;
import org.openmrs.customdatatype.Customizable;
Expand Down Expand Up @@ -275,6 +277,30 @@ public Set<PatientState> getCurrentStates() {
return ret;
}

/**
* Returns a Set&lt;PatientState&gt; of all recent {@link PatientState}s for each workflow of the
* {@link PatientProgram}
*
* @return Set&lt;PatientState&gt; of all recent {@link PatientState}s for the {@link PatientProgram}
*/
public Set<PatientState> getMostRecentStateInEachWorkflow() {
HashMap<ProgramWorkflow,PatientState> map = new HashMap<ProgramWorkflow,PatientState>();

for (PatientState state : getSortedStates()) {
if (!state.isVoided()) {
ProgramWorkflow workflow = state.getState().getProgramWorkflow();
map.put(workflow,state);
}
}

Set<PatientState> ret = new HashSet<>();
for (Map.Entry<ProgramWorkflow, PatientState> entry : map.entrySet()) {
ret.add(entry.getValue());
}

return ret;
}

/**
* Returns a List&lt;PatientState&gt; of all {@link PatientState}s in the passed
* {@link ProgramWorkflow} for the {@link PatientProgram}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -261,7 +261,17 @@ public PatientProgram savePatientProgram(PatientProgram patientProgram) throws A
}
}
}

// Makes sure that the end dates of most recent states in each workflow
// and the program end date are consistent
if (patientProgram.getDateCompleted() != null) {
for (PatientState state : patientProgram.getMostRecentStateInEachWorkflow()) {
// The EndDate of active states only should be updated
if (state.getEndDate() == null) {
state.setEndDate(patientProgram.getDateCompleted());
}
}
}

return dao.savePatientProgram(patientProgram);
}

Expand Down
231 changes: 231 additions & 0 deletions api/src/test/java/org/openmrs/api/ProgramWorkflowServiceTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,237 @@ public void savePatientProgram_shouldUpdatePatientProgram() {
assertEquals(today, ptProg.getDateCompleted());

}

/**
* Tests if the savePatientProgram(PatientProgram) sets the EndDate of recent state of each workflow
* on calling the setDateCompleted(Date date) method.
*
* @see ProgramWorkflowService#savePatientProgram(PatientProgram)
*/
@Test
public void savePatientProgram_shouldSetEndDateOfAllRecentStatesWhenCompletingTheProgram() throws Exception {
Date day3 = new Date();
Date day2_5 = new Date(day3.getTime() - 12*3600*1000);
Date day2 = new Date(day3.getTime() - 24*3600*1000);
Date day1 = new Date(day2.getTime() - 24*3600*1000);

// Program Architecture
Program program = new Program();
program.setName("TEST PROGRAM");
program.setDescription("TEST PROGRAM DESCRIPTION");
program.setConcept(cs.getConcept(3));

ProgramWorkflow workflow1 = new ProgramWorkflow();
workflow1.setConcept(cs.getConcept(4));
program.addWorkflow(workflow1);

ProgramWorkflow workflow2 = new ProgramWorkflow();
workflow2.setConcept(cs.getConcept(4));
program.addWorkflow(workflow2);

// workflow1
ProgramWorkflowState state1_w1 = new ProgramWorkflowState();
state1_w1.setConcept(cs.getConcept(5));
state1_w1.setInitial(true);
state1_w1.setTerminal(false);
workflow1.addState(state1_w1);

ProgramWorkflowState state2_w1 = new ProgramWorkflowState();
state2_w1.setConcept(cs.getConcept(6));
state2_w1.setInitial(false);
state2_w1.setTerminal(true);
workflow1.addState(state2_w1);

// workflow2
ProgramWorkflowState state1_w2 = new ProgramWorkflowState();
state1_w2.setConcept(cs.getConcept(5));
state1_w2.setInitial(true);
state1_w2.setTerminal(false);
workflow2.addState(state1_w2);

ProgramWorkflowState state2_w2 = new ProgramWorkflowState();
state2_w2.setConcept(cs.getConcept(6));
state2_w2.setInitial(false);
state2_w2.setTerminal(true);
workflow2.addState(state2_w2);

Context.getProgramWorkflowService().saveProgram(program);

// Patient Program Architecture
PatientProgram patientprogram = new PatientProgram();
patientprogram.setProgram(program);
patientprogram.setPatient(new Patient());
patientprogram.setDateEnrolled(day1);
patientprogram.setDateCompleted(null);

PatientState patientstate1_w1 = new PatientState();
patientstate1_w1.setStartDate(day1);
patientstate1_w1.setEndDate(day2);
patientstate1_w1.setState(state1_w1);

PatientState patientstate2_w1 = new PatientState();
patientstate2_w1.setStartDate(day2);
// Forcefully setEndDate to simulate suspended state
patientstate2_w1.setEndDate(day2_5);
patientstate2_w1.setState(state2_w1);

PatientState patientstate1_w2 = new PatientState();
patientstate1_w2.setStartDate(day1);
patientstate1_w2.setEndDate(day2);
patientstate1_w2.setState(state1_w2);

PatientState patientstate2_w2 = new PatientState();
patientstate2_w2.setStartDate(day2);
patientstate2_w2.setEndDate(null);
patientstate2_w2.setState(state2_w2);

patientprogram.getStates().add(patientstate1_w1);
patientprogram.getStates().add(patientstate2_w1);
patientprogram.getStates().add(patientstate1_w2);
patientprogram.getStates().add(patientstate2_w2);

patientstate1_w1.setPatientProgram(patientprogram);
patientstate2_w1.setPatientProgram(patientprogram);
patientstate1_w2.setPatientProgram(patientprogram);
patientstate2_w2.setPatientProgram(patientprogram);

// when
Date terminal_date = day3;
patientprogram.setDateCompleted(terminal_date);
Context.getProgramWorkflowService().savePatientProgram(patientprogram);

// then
// End date of recent active states should be set
assertTrue((patientstate2_w2.getEndDate().toString()).equals(terminal_date.toString()));
assertTrue((patientprogram.getDateCompleted()).equals(patientstate2_w2.getEndDate()));
// End Date of suspended state should not change
assertTrue((patientstate2_w1.getEndDate().toString()).equals(day2_5.toString()));
// End date of past states should not change
assertTrue((patientstate1_w1.getEndDate().toString()).equals(day2.toString()));
assertTrue((patientstate1_w2.getEndDate().toString()).equals(day2.toString()));

}

/**
* Tests if the savePatientProgram(PatientProgram) sets the EndDate of recent state of each workflow
* when a patient transitions to a terminal state.
*
* @see ProgramWorkflowService#savePatientProgram(PatientProgram)
*/
@Test
public void savePatientProgram_shouldSetEndDateOfAllRecentStatesOnTransitionToTerminalState() throws Exception {
Date day3 = new Date();
Date day2_5 = new Date(day3.getTime() - 12*3600*1000);
Date day2 = new Date(day3.getTime() - 24*3600*1000);
Date day1 = new Date(day2.getTime() - 24*3600*1000);

// Program Architecture
Program program = new Program();
program.setName("TEST PROGRAM");
program.setDescription("TEST PROGRAM DESCRIPTION");
program.setConcept(cs.getConcept(3));

ProgramWorkflow workflow1 = new ProgramWorkflow();
workflow1.setConcept(cs.getConcept(4));
program.addWorkflow(workflow1);

ProgramWorkflow workflow2 = new ProgramWorkflow();
workflow2.setConcept(cs.getConcept(4));
program.addWorkflow(workflow2);

ProgramWorkflow workflow3 = new ProgramWorkflow();
workflow3.setConcept(cs.getConcept(4));
program.addWorkflow(workflow3);

// workflow1
ProgramWorkflowState state1_w1 = new ProgramWorkflowState();
state1_w1.setConcept(cs.getConcept(5));
state1_w1.setInitial(true);
state1_w1.setTerminal(false);
workflow1.addState(state1_w1);

ProgramWorkflowState state2_w1 = new ProgramWorkflowState();
state2_w1.setConcept(cs.getConcept(6));
state2_w1.setInitial(false);
state2_w1.setTerminal(true);
workflow1.addState(state2_w1);

// workflow2
ProgramWorkflowState state1_w2 = new ProgramWorkflowState();
state1_w2.setConcept(cs.getConcept(5));
state1_w2.setInitial(true);
state1_w2.setTerminal(false);
workflow2.addState(state1_w2);

ProgramWorkflowState state2_w2 = new ProgramWorkflowState();
state2_w2.setConcept(cs.getConcept(6));
state2_w2.setInitial(false);
state2_w2.setTerminal(true);
workflow2.addState(state2_w2);

//workflow3
ProgramWorkflowState state1_w3 = new ProgramWorkflowState();
state1_w3.setConcept(cs.getConcept(5));
state1_w3.setInitial(true);
state1_w3.setTerminal(false);
workflow3.addState(state1_w3);

ProgramWorkflowState state2_w3 = new ProgramWorkflowState();
state2_w3.setConcept(cs.getConcept(6));
state2_w3.setInitial(false);
state2_w3.setTerminal(true);
workflow3.addState(state2_w3);

Context.getProgramWorkflowService().saveProgram(program);

// Patient Program Architecture
PatientProgram patientprogram = new PatientProgram();
patientprogram.setProgram(program);
patientprogram.setPatient(new Patient());
patientprogram.setDateEnrolled(day1);
patientprogram.setDateCompleted(null);

PatientState patientstate1_w1 = new PatientState();
patientstate1_w1.setStartDate(day1);
patientstate1_w1.setState(state1_w1);

PatientState patientstate1_w2 = new PatientState();
patientstate1_w2.setStartDate(day1);
patientstate1_w2.setState(state1_w2);

PatientState patientstate1_w3 = new PatientState();
patientstate1_w3.setStartDate(day1);
patientstate1_w3.setState(state1_w3);
// Forcefully setEndDate to simulate suspended state
patientstate1_w3.setEndDate(day2_5);

patientprogram.getStates().add(patientstate1_w1);
patientprogram.getStates().add(patientstate1_w2);
patientprogram.getStates().add(patientstate1_w3);

patientstate1_w1.setPatientProgram(patientprogram);
patientstate1_w2.setPatientProgram(patientprogram);
patientstate1_w3.setPatientProgram(patientprogram);

// when
patientprogram.transitionToState(state2_w1, day3);
pws.savePatientProgram(patientprogram);

// then
for (PatientState state : patientprogram.getMostRecentStateInEachWorkflow()) {
if (!(state.equals(patientstate1_w3))) {
assertTrue(state.getEndDate().toString().equals(patientprogram.getDateCompleted().toString()));
}
}

// End date of recent states should be set
assertTrue((patientstate1_w2.getEndDate().toString()).equals(patientprogram.getDateCompleted().toString()));
assertTrue((patientprogram.getDateCompleted().toString()).equals(day3.toString()));
// End date of suspended state should not change
assertTrue(patientstate1_w3.getEndDate().toString().equals(day2_5.toString()));
// End date of past states should not change
assertTrue((patientstate1_w1.getEndDate().toString()).equals(day3.toString()));
}

/**
* Tests creating a new program containing workflows and states
Expand Down

0 comments on commit b611763

Please sign in to comment.