Transition patient to new state in program workflow via REST API

A patient is enrolled in a program. How do I transition a patient through the states of the workflow, using the REST API?

Firstly, what rules are applied in the background regarding states? For example:

Some states are designated as initial and some as terminal. I see that the UI uses this to filter the state list that is shown to the user. I also see that the backend will terminate an enrollment (patient_program) if it reaches a terminal state. Is any other business logic applied regarding initial vs terminal vs other state, or can I just change the state of an enrollment in any way I wish by posting an update to programenrollment/{uuid}/state?

Secondly, when I post a state update, I want to specify the startDate explicitly. However, I get an error: Some properties are not allowed to be set: startDate’. I have to omit the ‘startDate’ and then it defaults it to today’s date. not what I want. Is there a workaround?

Thirdly, I include the initial state with the creation of the new enrollment. However, after that I want to post individual state changes, but I can’t get the state change to take effect. I’m posting a change of state to the existing enrollment with UUID 173e5d32-eea6-44e4-af67-4efa35a5da66. The workflow state UUID is ca632b9d-4317-41e4-8ee8-48b54e553b06:

  • POST to URL: programenrollment/173e5d32-eea6-44e4-af67-4efa35a5da66/state
  • Request body: { "state":"ca632b9d-4317-41e4-8ee8-48b54e553b06" }

I don’t see this state change applied. Am I missing something?

Is this helpful? https://github.com/openmrs/openmrs-module-webservices.rest/blob/2.36.0/omod-1.10/src/test/java/org/openmrs/module/webservices/rest/web/v1_0/controller/openmrs1_10/ProgramEnrollmentController1_10Test.java#L96-L117

Here are the rules: https://github.com/openmrs/openmrs-core/blob/2.5.5/api/src/main/java/org/openmrs/validator/PatientProgramValidator.java#L56-L70

And this is the validator test class: https://github.com/openmrs/openmrs-core/blob/2.5.5/api/src/test/java/org/openmrs/validator/PatientProgramValidatorTest.java

How does your request body look like and which url are you posting to? Is it? /ws/rest/v1/programenrollment/{uuid}/state/{uuid}

Can you try this? OpenMRS Docs

Or take a look at this: https://github.com/openmrs/openmrs-module-webservices.rest/blob/2.36.0/omod-1.10/src/test/java/org/openmrs/module/webservices/rest/web/v1_0/controller/openmrs1_10/ProgramEnrollmentController1_10Test.java#L119-L141

OK, so in summary, it seems there are some bits of the OpenMRS REST API that are not working as advertised:

  1. You cannot create a new state by posting to /programenrollment/{uuid}/state, it just doesn’t work. You can only create a new state by posting a “states” update to /programenrollment/{uuid}.
  2. When you post the latter, each "state" ref in "states" must be a separate JSON object with nested "uuid".
  3. Any new state gets its endDate set to its startDate automatically: you cannot leave it null.

Example of 1

Example URL (existing enrollment): POST /programenrollment/58cda2ec-2b59-47c2-8b0b-b7a516002849/state

Body (UUID shown is for existing ProgramWorkflowState):

{
    "state": {
        "uuid":"ca632b9d-4317-41e4-8ee8-48b54e553b06"
    },
    "startDate": "2022-08-30T13:00:00+02:00"
    }
}

Result: Exception - Not allowed to set startDate.

Then, without startDate:

{
    "state": {
        "uuid":"ca632b9d-4317-41e4-8ee8-48b54e553b06"
    }
}

Result: Appears to create state (shows successful state response, with UUID and everything, but when you query for that state by UUID (/programenrollment/58cda2ec-2b59-47c2-8b0b-b7a516002849/state/cbc88fa2-be92-471c-b53f-873b6e51e203) it is not found. Also when you try to find it in the database with SQL: it was never actually created!

Example of 2

So, the previous endpoint doesn’t work; the only one that works is to post to the enrollment endpoint, including the "states" property. But contrary to some of the documentation, each individual "state" in the JSON is not just a UUID, it must be an object with a nested “uuid”, e.g.:

POST to /programenrollment/1ea944a6-c71d-4d92-8154-1a1d33215762

This doesn’t work:

{
    "states": [
        {
            "state": "ca632b9d-4317-41e4-8ee8-48b54e553b06",
            "startDate": "2022-09-14T00:00:00.000+0000"
        }
    ]
}

but this does work:

{
    "states": [
        {
            "state": {
                "uuid":"ca632b9d-4317-41e4-8ee8-48b54e553b06"
            },
            "startDate": "2022-09-14T00:00:00.000+0000"
        }
    ]
}

Re no. 3: I couldn’t get a way to work around this. If you post a subsequent state change with a specific startDate, that new state’s endDate is automatically set to that (it doesn’t remain null), and the endDate of the previous state (the initial state) is also set to the same date.

Are you able to reproduce these from this server? https://qa-refapp.openmrs.org/