-
Notifications
You must be signed in to change notification settings - Fork 0
LAMP-49: Add scheduler to complete programs #5
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
72e5fd3
b031fe6
ed8a935
f9ccd00
224591f
02cfe5f
ccdb46c
0dcf8e4
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,103 @@ | ||
| package org.openmrs.module.lamp.scheduler; | ||
|
|
||
| import org.apache.commons.logging.Log; | ||
| import org.apache.commons.logging.LogFactory; | ||
| import org.openmrs.PatientProgram; | ||
| import org.openmrs.PatientState; | ||
| import org.openmrs.Program; | ||
| import org.openmrs.ProgramWorkflow; | ||
| import org.openmrs.ProgramWorkflowState; | ||
| import org.openmrs.api.ProgramWorkflowService; | ||
| import org.openmrs.api.context.Context; | ||
| import org.openmrs.module.lamp.LampConfig; | ||
| import org.openmrs.module.lamp.Utils; | ||
| import org.openmrs.scheduler.tasks.AbstractTask; | ||
| import org.springframework.stereotype.Component; | ||
|
|
||
| import java.util.Calendar; | ||
| import java.util.Date; | ||
| import java.util.List; | ||
|
|
||
| @Component | ||
| public class CompleteProgramsTask extends AbstractTask { | ||
|
|
||
| private static final Log log = LogFactory.getLog(CompleteProgramsTask.class); | ||
|
|
||
| @Override | ||
| public void execute() { | ||
| log.debug("Executing CompletePrograms Task"); | ||
| ProgramWorkflowService service = Context.getProgramWorkflowService(); | ||
|
|
||
| completeProgramIfExists(service, LampConfig.PROGRAM_CHILD_NUTRITION_UUID, 18); | ||
| completeProgramIfExists(service, LampConfig.PROGRAM_PRENATAL_UUID, 44); | ||
| } | ||
|
|
||
| @Override | ||
| public void shutdown() { | ||
| log.debug("Shutting down CompletePrograms Task"); | ||
| stopExecuting(); | ||
| } | ||
|
|
||
| private void completeProgramIfExists(ProgramWorkflowService service, String programUuid, int weeksThreshold) { | ||
| Program program = service.getProgramByUuid(programUuid); | ||
| if (program != null) { | ||
| completeProgramsStartedBefore(service, program, getThresholdDateWeeksAgo(weeksThreshold)); | ||
| } | ||
| } | ||
|
|
||
| private Date getThresholdDateWeeksAgo(int weeks) { | ||
| Calendar cal = Calendar.getInstance(); | ||
| cal.add(Calendar.WEEK_OF_YEAR, -weeks); | ||
| return cal.getTime(); | ||
| } | ||
|
|
||
| private void completeProgramsStartedBefore(ProgramWorkflowService service, Program program, Date thresholdDate) { | ||
| List<PatientProgram> patientPrograms = service.getPatientPrograms(null, program, null, null, null, null, false); | ||
|
|
||
| for (PatientProgram pp : patientPrograms) { | ||
| if (pp == null || Boolean.TRUE.equals(pp.getVoided()) || pp.getDateCompleted() != null | ||
| || pp.getDateEnrolled() == null) { | ||
| continue; | ||
| } | ||
|
|
||
| if (pp.getDateEnrolled().before(thresholdDate)) { | ||
| completePatientProgram(pp, program); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| private void completePatientProgram(PatientProgram pp, Program program) { | ||
| String programUuid = pp.getProgram().getUuid(); | ||
|
|
||
| if (LampConfig.PROGRAM_CHILD_NUTRITION_UUID.equals(programUuid)) { | ||
| transitionProgramState(pp, program, LampConfig.WORKFLOW_CHILD_NUTRITION_UUID, | ||
| LampConfig.CONCEPT_18_WEEKS_IN_CHILD_NUTRITION_PROGRAM, pp.getProgram().getName()); | ||
| } else if (LampConfig.PROGRAM_PRENATAL_UUID.equals(programUuid)) { | ||
| transitionProgramState(pp, program, LampConfig.WORKFLOW_PRENATAL_UUID, | ||
| LampConfig.CONCEPT_10_MONTHS_IN_PRENATAL_PROGRAM, pp.getProgram().getName()); | ||
| } | ||
| } | ||
|
|
||
| private void transitionProgramState(PatientProgram pp, Program program, String workflowUuid, String conceptUuid, | ||
| String programName) { | ||
| ProgramWorkflow workflow = Utils.getWorkflowByUuid(program, workflowUuid); | ||
| if (workflow == null) { | ||
| return; | ||
| } | ||
|
|
||
| ProgramWorkflowState programWorkflowState = Utils.getStateByConcept(workflow, Context.getConceptService() | ||
| .getConceptByUuid(conceptUuid)); | ||
| if (programWorkflowState == null) { | ||
| return; | ||
| } | ||
| for (PatientState ps : pp.getStates()) { | ||
| if (ps.getActive() && ps.getState().getProgramWorkflow().equals(programWorkflowState.getProgramWorkflow())) { | ||
| ps.setEndDate(new Date()); | ||
| } | ||
| } | ||
|
|
||
| pp.transitionToState(programWorkflowState, new Date()); | ||
|
|
||
| log.info("Auto-completed " + programName + " program"); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,41 @@ | ||
| <?xml version="1.0" encoding="UTF-8"?> | ||
|
|
||
| <databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog/1.9" | ||
| xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | ||
| xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog/1.9 | ||
| http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-1.9.xsd"> | ||
|
|
||
| <!-- | ||
| See http://wiki.openmrs.org/display/docs/Module+liquibase+File for | ||
| documentation on this file. | ||
|
|
||
| See http://www.liquibase.org/manual/home#available_database_refactorings | ||
| for a list of supported elements and attributes | ||
| --> | ||
|
|
||
| <changeSet id="create-complete-program-task-2025-11-04" author="siddharth"> | ||
| <preConditions onFail="MARK_RAN"> | ||
| <sqlCheck expectedResult="0"> | ||
| SELECT COUNT(*) FROM scheduler_task_config | ||
| WHERE schedulable_class = 'org.openmrs.module.lamp.scheduler.CompleteProgramsTask' | ||
| And name = 'Complete LAMP Program Task' | ||
| </sqlCheck> | ||
| </preConditions> | ||
| <comment>Inserting CompletePrograms Task into 'schedule_task_config' table</comment> | ||
| <insert tableName="scheduler_task_config"> | ||
|
Comment on lines
+16
to
+25
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. At some point, I would like us to migrate from using this approach (built-in scheduled task engine). This is because if the module is removed for some reason, there will be always scheduled task configuration hanging around, which throws errors due to classes not being found |
||
| <column name="name" value="Complete LAMP Program Task" /> | ||
| <column name="description" value="Completes open Programs in Ozone LAMP" /> | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can this module be used outside Ozone Lamp distro? If yes, let's remove 'Ozone Lamp' in the description.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not really. This module is tied to Ozone LAMP programs. |
||
| <column name="schedulable_class" value="org.openmrs.module.lamp.scheduler.CompleteProgramsTask" /> | ||
| <column name="start_time_pattern" value="MM/dd/yyyy HH:mm:ss" /> | ||
| <column name="start_time" valueDate="now()" /> | ||
| <column name="repeat_interval" value="60" /> | ||
| <column name="date_created" valueDate="CURRENT_TIMESTAMP" /> | ||
| <column name="created_by" value="1" /> | ||
| <column name="start_on_startup" value="1"/> | ||
| <column name="started" value="0"/> | ||
| <column name="uuid" value="e8ed7c5d-80f2-4f77-beeb-d12c5f0badc6" /> | ||
| </insert> | ||
| </changeSet> | ||
| </databaseChangeLog> | ||
|
|
||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This class shouldn't be a Spring bean but rather just a constants Class.