| 91 | | } |
|---|
| 92 | | /* |
|---|
| 93 | | private Set<PatientState> states; |
|---|
| 94 | | */ |
|---|
| | 108 | } |
|---|
| | 109 | |
|---|
| | 110 | // ****************** |
|---|
| | 111 | // Instance methods |
|---|
| | 112 | // ****************** |
|---|
| | 113 | |
|---|
| | 114 | /** |
|---|
| | 115 | * Returns true if the associated {@link Patient} is enrolled in the associated {@link Program} on the passed {@link Date} |
|---|
| | 116 | * @param onDate - Date to check for PatientProgram enrollment |
|---|
| | 117 | * @return boolean - true if the associated {@link Patient} is enrolled in the associated {@link Program} on the passed {@link Date} |
|---|
| | 118 | */ |
|---|
| | 119 | public boolean getActive(Date onDate) { |
|---|
| | 120 | if (onDate == null) { |
|---|
| | 121 | onDate = new Date(); |
|---|
| | 122 | } |
|---|
| | 123 | return !getVoided() && (getDateEnrolled() == null || OpenmrsUtil.compare(getDateEnrolled(), onDate) <= 0) && (getDateCompleted() == null || OpenmrsUtil.compare(getDateCompleted(), onDate) > 0); |
|---|
| | 124 | } |
|---|
| | 125 | |
|---|
| | 126 | /** |
|---|
| | 127 | * Returns true if the associated {@link Patient} is currently enrolled in the associated {@link Program} |
|---|
| | 128 | * @return boolean - true if the associated {@link Patient} is currently enrolled in the associated {@link Program} |
|---|
| | 129 | */ |
|---|
| | 130 | public boolean getActive() { |
|---|
| | 131 | return getActive(null); |
|---|
| | 132 | } |
|---|
| | 133 | |
|---|
| | 134 | /** |
|---|
| | 135 | * Returns the {@link PatientState} associated with this PatientProgram that has an id that matches the passed <code>patientStateId</code> |
|---|
| | 136 | * @param patientStateId - The identifier to use to lookup a {@link PatientState} |
|---|
| | 137 | * @return PatientState that has an id that matches the passed <code>patientStateId</code> |
|---|
| | 138 | */ |
|---|
| | 139 | public PatientState getPatientState(Integer patientStateId) { |
|---|
| | 140 | for (PatientState s : getStates()) { |
|---|
| | 141 | if (s.getPatientStateId() != null && s.getPatientStateId().equals(patientStateId)) { |
|---|
| | 142 | return s; |
|---|
| | 143 | } |
|---|
| | 144 | } |
|---|
| | 145 | return null; |
|---|
| | 146 | } |
|---|
| | 147 | |
|---|
| | 148 | /** |
|---|
| | 149 | * Attempts to transition the PatientProgram to the passed {@link ProgramWorkflowState} on the passed {@link Date} |
|---|
| | 150 | * by ending the most recent {@link PatientState} in the {@link PatientProgram} and creating a new one with the passed {@link ProgramWorkflowState} |
|---|
| | 151 | * This will throw an IllegalArgumentException if the transition is invalid |
|---|
| | 152 | * @param programWorkflowState - The {@link ProgramWorkflowState} to transition to |
|---|
| | 153 | * @param onDate - The {@link Date} of the transition |
|---|
| | 154 | * @throws IllegalArgumentException |
|---|
| | 155 | */ |
|---|
| | 156 | public void transitionToState(ProgramWorkflowState programWorkflowState, Date onDate) { |
|---|
| | 157 | PatientState lastState = getCurrentState(programWorkflowState.getProgramWorkflow()); |
|---|
| | 158 | if (lastState != null && onDate == null) { |
|---|
| | 159 | throw new IllegalArgumentException("You can't change from a non-null state without giving a change date"); |
|---|
| | 160 | } |
|---|
| | 161 | if (lastState != null && lastState.getEndDate() != null) { |
|---|
| | 162 | throw new IllegalArgumentException("You can't change out of a state that has an end date already"); |
|---|
| | 163 | } |
|---|
| | 164 | if (lastState != null && lastState.getStartDate() != null && OpenmrsUtil.compare(lastState.getStartDate(), onDate) > 0) { |
|---|
| | 165 | throw new IllegalArgumentException("You can't change out of a state before that state started"); |
|---|
| | 166 | } |
|---|
| | 167 | if (lastState != null && !programWorkflowState.getProgramWorkflow().isLegalTransition(lastState.getState(), programWorkflowState)) { |
|---|
| | 168 | throw new IllegalArgumentException("You can't change from state " + lastState.getState() + " to " + programWorkflowState); |
|---|
| | 169 | } |
|---|
| | 170 | if (lastState != null) { |
|---|
| | 171 | lastState.setEndDate(onDate); |
|---|
| | 172 | } |
|---|
| | 173 | PatientState newState = new PatientState(); |
|---|
| | 174 | newState.setPatientProgram(this); |
|---|
| | 175 | newState.setState(programWorkflowState); |
|---|
| | 176 | newState.setStartDate(onDate); |
|---|
| | 177 | getStates().add(newState); |
|---|
| | 178 | } |
|---|
| | 179 | |
|---|
| | 180 | /** |
|---|
| | 181 | * Attempts to void the latest {@link PatientState} in the {@link PatientProgram} |
|---|
| | 182 | * If earlier PatientStates exist, it will try to reset the endDate to null so that |
|---|
| | 183 | * the next latest state becomes the current {@link PatientState} |
|---|
| | 184 | * @param workflow - The {@link ProgramWorkflow} whose last {@link PatientState} within the current {@link PatientProgram} we want to void |
|---|
| | 185 | * @param voidBy - The user who is voiding the {@link PatientState} |
|---|
| | 186 | * @param voidDate - The date to void the {@link PatientState} |
|---|
| | 187 | * @param voidReason - The reason for voiding the {@link PatientState} |
|---|
| | 188 | */ |
|---|
| | 189 | public void voidLastState(ProgramWorkflow workflow, User voidBy, Date voidDate, String voidReason) { |
|---|
| | 190 | List<PatientState> states = statesInWorkflow(workflow, false); |
|---|
| | 191 | if (voidDate == null) { |
|---|
| | 192 | voidDate = new Date(); |
|---|
| | 193 | } |
|---|
| | 194 | PatientState last = null; |
|---|
| | 195 | PatientState nextToLast = null; |
|---|
| | 196 | if (states.size() > 0) { |
|---|
| | 197 | last = states.get(states.size() - 1); |
|---|
| | 198 | } |
|---|
| | 199 | if (states.size() > 1) { |
|---|
| | 200 | nextToLast = states.get(states.size() - 2); |
|---|
| | 201 | } |
|---|
| | 202 | if (last != null) { |
|---|
| | 203 | last.setVoided(true); |
|---|
| | 204 | last.setVoidedBy(voidBy); |
|---|
| | 205 | last.setDateVoided(voidDate); |
|---|
| | 206 | last.setVoidReason(voidReason); |
|---|
| | 207 | } |
|---|
| | 208 | if (nextToLast != null && nextToLast.getEndDate() != null) { |
|---|
| | 209 | nextToLast.setEndDate(null); |
|---|
| | 210 | nextToLast.setDateChanged(voidDate); |
|---|
| | 211 | nextToLast.setChangedBy(voidBy); |
|---|
| | 212 | } |
|---|
| | 213 | } |
|---|
| | 214 | |
|---|
| | 215 | /** |
|---|
| | 216 | * Returns the current {@link PatientState} for the passed {@link ProgramWorkflow} within this {@link PatientProgram} |
|---|
| | 217 | * @param programWorkflow - The ProgramWorkflow whose current {@link PatientState} we want to retrieve |
|---|
| | 218 | * @return PatientState - The current {@link PatientState} for the passed {@link ProgramWorkflow} within this {@link PatientProgram} |
|---|
| | 219 | */ |
|---|
| | 220 | public PatientState getCurrentState(ProgramWorkflow programWorkflow) { |
|---|
| | 221 | Date now = new Date(); |
|---|
| | 222 | for (PatientState state : getStates()) { |
|---|
| | 223 | if ( ( programWorkflow == null || state.getState().getProgramWorkflow().equals(programWorkflow) ) && state.getActive(now) ) { |
|---|
| | 224 | return state; |
|---|
| | 225 | } |
|---|
| | 226 | } |
|---|
| | 227 | return null; |
|---|
| | 228 | } |
|---|
| | 229 | |
|---|
| | 230 | /** |
|---|
| | 231 | * @deprecated use {@link #getCurrentState(ProgramWorkflow)} |
|---|
| | 232 | */ |
|---|
| | 233 | public PatientState getCurrentState() { |
|---|
| | 234 | return getCurrentState(null); |
|---|
| | 235 | } |
|---|
| | 236 | |
|---|
| | 237 | /** |
|---|
| | 238 | * Returns a Set<PatientState> of all current {@link PatientState}s for the {@link PatientProgram} |
|---|
| | 239 | * @return Set<PatientState> of all current {@link PatientState}s for the {@link PatientProgram} |
|---|
| | 240 | */ |
|---|
| | 241 | public Set<PatientState> getCurrentStates() { |
|---|
| | 242 | Set<PatientState> ret = new HashSet<PatientState>(); |
|---|
| | 243 | Date now = new Date(); |
|---|
| | 244 | for ( PatientState state : getStates() ) { |
|---|
| | 245 | if (state.getActive(now)) { |
|---|
| | 246 | ret.add(state); |
|---|
| | 247 | } |
|---|
| | 248 | } |
|---|
| | 249 | return ret; |
|---|
| | 250 | } |
|---|
| | 251 | |
|---|
| | 252 | /** |
|---|
| | 253 | * Returns a List<PatientState> of all {@link PatientState}s in the passed {@link ProgramWorkflow} for the {@link PatientProgram} |
|---|
| | 254 | * @param programWorkflow - The {@link ProgramWorkflow} to check |
|---|
| | 255 | * @param includeVoided - If true, return voided {@link PatientState}s in the returned {@link List} |
|---|
| | 256 | * @return List<PatientState> of all {@link PatientState}s in the passed {@link ProgramWorkflow} for the {@link PatientProgram} |
|---|
| | 257 | */ |
|---|
| | 258 | public List<PatientState> statesInWorkflow(ProgramWorkflow programWorkflow, boolean includeVoided) { |
|---|
| | 259 | List<PatientState> ret = new ArrayList<PatientState>(); |
|---|
| | 260 | for (PatientState st : getStates()) { |
|---|
| | 261 | if (st.getState().getProgramWorkflow().equals(programWorkflow) && (includeVoided || !st.getVoided())) { |
|---|
| | 262 | ret.add(st); |
|---|
| | 263 | } |
|---|
| | 264 | } |
|---|
| | 265 | Collections.sort(ret, new Comparator<PatientState>() { |
|---|
| | 266 | public int compare(PatientState left, PatientState right) { |
|---|
| | 267 | return OpenmrsUtil.compareWithNullAsEarliest(left.getStartDate(), right.getStartDate()); |
|---|
| | 268 | } |
|---|
| | 269 | }); |
|---|
| | 270 | return ret; |
|---|
| | 271 | } |
|---|
| | 272 | |
|---|
| | 273 | /** @see Object#equals(Object) */ |
|---|
| | 274 | public boolean equals(Object obj) { |
|---|
| | 275 | if (obj != null && obj instanceof PatientProgram) { |
|---|
| | 276 | PatientProgram p = (PatientProgram)obj; |
|---|
| | 277 | if (this.getPatientProgramId() == null) { |
|---|
| | 278 | return p.getPatientProgramId() == null; |
|---|
| | 279 | } |
|---|
| | 280 | return (this.getPatientProgramId().equals(p.getPatientProgramId())); |
|---|
| | 281 | } |
|---|
| | 282 | return false; |
|---|
| | 283 | } |
|---|
| | 284 | |
|---|
| | 285 | /** @see Object#toString() */ |
|---|
| | 286 | public String toString() { |
|---|
| | 287 | return "PatientProgram(id=" + getPatientProgramId() + ", patient=" + getPatient() + ", program=" + getProgram() + ")"; |
|---|
| | 288 | } |
|---|
| | 289 | |
|---|
| | 290 | // ****************** |
|---|
| | 291 | // Property Access |
|---|
| | 292 | // ****************** |
|---|
| 207 | | |
|---|
| 208 | | public boolean getActive(Date onDate) { |
|---|
| 209 | | if (onDate == null) |
|---|
| 210 | | onDate = new Date(); |
|---|
| 211 | | return !getVoided() && (dateEnrolled == null || OpenmrsUtil.compare(dateEnrolled, onDate) <= 0) && (dateCompleted == null || OpenmrsUtil.compare(dateCompleted, onDate) > 0); |
|---|
| 212 | | } |
|---|
| 213 | | |
|---|
| 214 | | public boolean getActive() { |
|---|
| 215 | | return getActive(null); |
|---|
| 216 | | } |
|---|
| 217 | | |
|---|
| 218 | | public PatientState getCurrentState(ProgramWorkflow wf) { |
|---|
| 219 | | Set<PatientState> states = this.getStates(); |
|---|
| 220 | | Date now = new Date(); |
|---|
| 221 | | if (states != null) { |
|---|
| 222 | | for (PatientState state : states) { |
|---|
| 223 | | if ( !state.getVoided() && |
|---|
| 224 | | ( wf == null || state.getState().getProgramWorkflow().equals(wf) ) && |
|---|
| 225 | | state.getActive(now) ) |
|---|
| 226 | | return state; |
|---|
| 227 | | } |
|---|
| 228 | | } |
|---|
| 229 | | return null; |
|---|
| 230 | | } |
|---|
| 231 | | |
|---|
| 232 | | @Deprecated |
|---|
| 233 | | public PatientState getCurrentState() { |
|---|
| 234 | | // TODO: this isn't really right - a patient can have many current states (in different workflows) |
|---|
| 235 | | return getCurrentState(null); |
|---|
| 236 | | } |
|---|
| 237 | | |
|---|
| 238 | | |
|---|
| 239 | | public Set<PatientState> getCurrentStates() { |
|---|
| 240 | | |
|---|
| 241 | | Set<PatientState> ret = null; |
|---|
| 242 | | |
|---|
| 243 | | Set<PatientState> states = this.getStates(); |
|---|
| 244 | | if ( states != null ) { |
|---|
| 245 | | Date now = new Date(); |
|---|
| 246 | | for ( PatientState state : states ) { |
|---|
| 247 | | if (!state.getVoided() && state.getActive(now)) { |
|---|
| 248 | | if ( ret == null ) ret = new HashSet<PatientState>(); |
|---|
| 249 | | ret.add(state); |
|---|
| 250 | | } |
|---|
| 251 | | } |
|---|
| 252 | | } |
|---|
| 253 | | return ret; |
|---|
| 254 | | } |
|---|
| 255 | | |
|---|
| 256 | | public List<PatientState> statesInWorkflow(ProgramWorkflow wf, boolean includeVoided) { |
|---|
| 257 | | List<PatientState> ret = new ArrayList<PatientState>(); |
|---|
| 258 | | for (PatientState st : getStates()) { |
|---|
| 259 | | if (st.getState().getProgramWorkflow().equals(wf) && (includeVoided || !st.getVoided())) |
|---|
| 260 | | ret.add(st); |
|---|
| 261 | | } |
|---|
| 262 | | Collections.sort(ret, new Comparator<PatientState>() { |
|---|
| 263 | | public int compare(PatientState left, PatientState right) { |
|---|
| 264 | | return OpenmrsUtil.compareWithNullAsEarliest(left.getStartDate(), right.getStartDate()); |
|---|
| 265 | | } |
|---|
| 266 | | }); |
|---|
| 267 | | return ret; |
|---|
| 268 | | } |
|---|