MedicationDispense form submission with FHIR

Hi @mseaton @ibacher Am working on the submitting the dispense form and a hit a bit of a hiccup with submitting the data. I’ve been using this documentation as a reference for what data to submit. Been having trouble trying to figure out what data to submit and after crawling a number of wiki’s i came up with these issues that maybe you could help throw some light on:

  1. Based on the structure, it looks like MedicationDispense has most fields similar to MedicationRequest except for the substitution related fields so does that mean in a form dispense with multiple drugs, are each of them treated as different records?

  2. The form has a field internalNotes , the closest to anything i came across regarding that field was a comment by @mogoodrich suggesting it to be added to the note field in the MedicationDispense . Is this the intended behaviour and in the case of multiple drugs in a single form, should each of them use the value from this field?

  3. What data does the POST expect? I tried to replicate the structure of request body and even came across a postman collection like the one below but kept getting this error when testing with postman;

REQUEST BODY

{
    "resourceType": "<string>",
    "id": "<string>",
    "text": {
        "status": "<string>",
        "div": "<string>"
    },
    "status": "<string>",
    "medicationReference": {
        "reference": "<string>",
        "_reference": {
            "fhir_comments": [
                "<object>",
                "<object>"
            ]
        },
        "display": "<string>"
    },
    "patient": {
        "reference": "<string>"
    },
    "dispenser": {
        "reference": "<string>"
    },
    "authorizingPrescription": [
        {
            "reference": "<string>"
        }
    ],
    "type": {
        "coding": [
            {
                "system": "<string>",
                "code": "<string>",
                "display": "<string>"
            }
        ]
    },
    "quantity": {
        "value": "<number>",
        "unit": "<string>",
        "system": "<string>",
        "code": "<string>"
    },
    "daysSupply": {
        "value": "<number>",
        "unit": "<string>",
        "system": "<string>",
        "code": "<string>"
    },
    "whenPrepared": "<string>",
    "whenHandedOver": "<string>",
    "dosageInstruction": [
        {
            "additionalInstructions": {
                "coding": [
                    {
                        "system": "<string>",
                        "code": "<string>",
                        "display": "<string>"
                    }
                ]
            },
            "timing": {
                "repeat": {
                    "frequency": {
                        "value": "<Error: Too many levels of nesting to fake this schema>"
                    },
                    "period": {
                        "value": "<Error: Too many levels of nesting to fake this schema>"
                    },
                    "periodUnit": {
                        "value": "<Error: Too many levels of nesting to fake this schema>"
                    }
                }
            },
            "siteCodeableConcept": {
                "coding": [
                    {
                        "system": "<string>",
                        "code": "<string>",
                        "display": "<string>"
                    }
                ]
            },
            "route": {
                "coding": [
                    {
                        "system": "<string>",
                        "code": "<string>",
                        "display": "<string>"
                    }
                ]
            },
            "doseQuantity": {
                "value": "<number>",
                "unit": "<string>",
                "system": "<string>",
                "code": "<string>"
            }
        }
    ]
}

RESPONSE BODY

{
    "resourceType": "OperationOutcome",
    "text": {
        "status": "generated",
        "div": "<div xmlns=\"http://www.w3.org/1999/xhtml\"><h1>Operation Outcome</h1><table border=\"0\"><tr><td style=\"font-weight: bold;\">ERROR</td><td>[]</td><td><pre>Invalid request: The FHIR endpoint on this server does not know how to handle POST operation[MedicationDispense] with parameters [[medication]]</pre></td>\n\t\t\t</tr>\n\t\t</table>\n\t</div>"
    },
    "issue": [
        {
            "severity": "error",
            "code": "not-supported",
            "diagnostics": "Invalid request: The FHIR endpoint on this server does not know how to handle POST operation[MedicationDispense] with parameters [[medication]]"
        }
    ]
}

cc: @eudson

Comment from @mogoodrich on slack

Re: Qn 2.

  1. I suspect we haven’t come to a decision about “internal notes” yet, do to the problem you mentioned… the “internal notes”, from the UI, appears to be a single note tied to the group of dispensing objects but I don’t think we have any sort of grouping object in FHIR to store it on… my suggestion would be to skip implementing that for now, and just get the stuff we know working (edited)

Defer to @ibacher on all things FHIR2. As a baseline, I pulled the latest code in the FHIR2 module, and opened up the MedicationDispenseFhirResourceProviderIntegrationTest and threw a debug point in shouldReturnExistingMedicationDispenseAsJson to see the resulting JSON text, and here is what it looks like:

{
  "resourceType": "MedicationDispense",
  "id": "1bcb299c-b687-11ec-8065-0242ac110002",
  "meta": {
    "lastUpdated": "2008-09-22T13:00:00.000-04:00"
  },
  "status": "preparation",
  "medicationReference": {
    "reference": "Medication/05ec820a-d297-44e3-be6e-698531d9dd3f",
    "type": "Medication",
    "display": "ASPIRIN"
  },
  "subject": {
    "reference": "Patient/5946f880-b197-400b-9caa-a3c661d23041",
    "type": "Patient",
    "display": "Collet Test Chebaskwony (OpenMRS Identification Number: 6TS-4)"
  },
  "performer": [
    {
      "actor": {
        "reference": "Practitioner/c2299800-cca9-11e0-9572-0800200c9a66",
        "type": "Practitioner",
        "identifier": {
          "value": "Test"
        },
        "display": "Super User (Identifier: Test)"
      }
    }
  ],
  "location": {
    "reference": "Location/9356400c-a5a2-4532-8f2b-2361b3446eb8",
    "type": "Location",
    "display": "Xanadu"
  },
  "type": {
    "coding": [
      {
        "code": "6af1344a-b680-11ec-8065-0242ac110002",
        "display": "Refill"
      }
    ],
    "text": "Refill"
  },
  "quantity": {
    "value": 1.0,
    "unit": "tab (s)",
    "code": "5a2aa3db-68a3-11e3-bd76-0800271c1b75"
  },
  "whenPrepared": "2008-09-22T13:00:00-04:00",
  "whenHandedOver": "2008-09-22T14:11:00-04:00",
  "dosageInstruction": [
    {
      "text": "2x daily",
      "timing": {
        "code": {
          "coding": [
            {
              "code": "7e02d1a0-7869-11e3-981f-0800200c9a66",
              "display": "1/day x 7 days/week"
            }
          ],
          "text": "1/day x 7 days/week"
        }
      },
      "asNeededBoolean": false,
      "route": {
        "coding": [
          {
            "code": "e10ffe54-5184-4efe-8960-cd565ec1cdf8",
            "display": "UNKNOWN"
          }
        ],
        "text": "UNKNOWN"
      },
      "doseAndRate": [
        {
          "doseQuantity": {
            "value": 325.0,
            "unit": "mg",
            "code": "557b9699-68a3-11e3-bd76-0800271c1b75"
          }
        }
      ]
    }
  ],
  "substitution": {
    "wasSubstituted": false
  }
}

So likely something like this is appropriate for POSTing:

Note that all of the codes and UUIDs, etc. would need to be updated to correlate with values that actually exist in the system.

@ibacher @mseaton RE: data being posted, this looks like most of this will be coming from the MedicationRequest and optionally updated with edited values on the dispense form. Based on this UI Zeplin - Projects

Yes, I believe that is correct @pirupius , thanks!

It depends. subject definitely comes straight from the MedicationRequest. performer, location, type, status, whenPrepared and whenHandedOver, and substitution can only be known at the point something is dispensed. quantity probably originates from the MedicationRequest, but could be changed as part of the dispensing. And medication and dosageInstructions could change if a substitution was made (with a change to medication being more likely, e.g., substituting one medication for an equivalent).

You’d probably also want to include authorizingPrescription (not part of the original example) and context properties too.

@pirupius this should be helpful, it’s our original specifications for the creation of the new Medication Dispense object (hopefully still up to date):

https://wiki.openmrs.org/display/projects/Medication+Dispense+Data+Model

Note the “Related Order/Drug Order” column, and that any row that has an entry in this column can likely be prepopulated with the data from the Medication Request, though as @ibacher mentions all the fields that come from DrugOrder will potentially be editable within the form.

AuthorizingPrescription should contain the reference to the related MedicationRequest.

Other fields that I think we want to send:

  • Location = current session location
  • Provider = provider associated with the current user
  • whenPrepared = current datetime

I think we can skip the follow fields in this initial pass, but will will likely be adding many of them as we work through the specifics of handling substitution and status tracking:

  • context
  • status
  • statusReason
  • type
  • whenHandedOver
  • substitution.wasSubstuttied
  • substitution.type
  • substitution.reason
  • note.text

Also note there are several rows at the bottom that have “No” in the “Phase 1” column… these have not yet been implemented in OpenMRS and can therefore be skipped for now.

2 Likes

Peeking at the code, turnsout the necessary Resource Providers weren’t properly configured. Wired a PR to fix this: Update MedicationDispense providers with necessary annotations by samuelmale · Pull Request #427 · openmrs/openmrs-module-fhir2 · GitHub

cc: @mseaton / @ibacher

1 Like

Status Update:

So I succeeded in POSTing a Medication dispense but with a few minor fixes(see PR) and configurations:

  1. Configuring MedicationRequest Status Codes
    The fhir2 module has an internal table(fhir_concept_source) that maps conceptsources with the standard URIs. Be sure that this table holds a mapping of your “MedicationDispenseStatus” concept source (if you don’t have one, create one) to the standard URI => http://hl7.org/fhir/CodeSystem/medicationdispense-status. This mapping is important because this is how the framework infers the target conceptsource. Lastly, pull the Medication Dispense Status conceptset from CIEL and be sure the set members have a SAME-AS mapping with your MDS concept source with reference term code exactly the same as this FHIR codesystem valueset.

Example payload:

{
  "resourceType": "MedicationDispense",
  "status": "on-hold",
  "medicationReference": {
    "reference": "Medication/c28a92d6-8441-472a-8813-bd8949b7c541"
  },
  "subject": {
    "reference": "Patient/f16e2140-c589-4d5c-98d7-13642b670d9d"
  },
  "performer": [
    {
      "actor": {
        "reference": "Practitioner/8c3af80b-0c58-4de3-8add-46ecc5951b72"
      }
    }
  ],
  "location": {
    "reference": "Location/1ce1b7d4-c865-4178-82b0-5932e51503d6"
  },
  "type": {
    "coding": [
      {
        "code": "04affd1a-49ab-44e5-a6d1-c0a3fffceb7d"
      }
    ]
  },
  "quantity": {
    "value": 1.0,
    "unit": "Box",
    "code": "3c6a70ed-a762-41b9-8163-352c9bb36f20"
  },
  "whenPrepared": "2008-09-22T13:00:00-04:00",
  "whenHandedOver": "2008-09-22T14:11:00-04:00",
  "dosageInstruction": [
    {
      "timing": {
        "code": {
          "coding": [
            {
              "code": "2293b1d3-b7f1-4fd9-913c-b36536015e1e",
              "display": "Once Daily"
            }
          ],
          "text": "Once Daily"
        }
      },
      "asNeededBoolean": false,
      "route": {
        "coding": [
          {
            "code": "160240AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
          }
        ]
      },
      "doseAndRate": [
        {
          "doseQuantity": {
            "value": 325.0,
            "unit": "Milligram",
            "code": "161553AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
          }
        }
      ]
    }
  ],
  "substitution": {
    "wasSubstituted": false
  }
}

Thanks @samuel34 !

@pirupius let me know if the fixes from Samuel get you unblocked… happy to try to debug myself if need be.

@burke @mseaton please advise on how to treat the field with the label Dose the UI shows it as a dropdown but there are no values defined in the Order Entry Config ({{url}}/openmrs/ws/rest/v1/orderentryconfig). I also can’t figure out what it should be mapped as in the MedicationDispense object. Is this something we should omit entirely?

@pirupius . Defer to @burke and @ibacher knowledge on this, but I believe in both MedicationRequest and MedicationDispense, this is found within the “dosageInstruction property”, which is of type “Dosage”. A Dosage can contain a lot of information and can get quite complicated. For this relatively simple use case, where we are modeling an OpenMRS “SimpleDosageInstructions” that has a single numeric quantity and unit, this is mapped as a “SimpleQuantity” under dosage.doseAndRate.dose[0].dosageQuantity.

  • dosage.doseAndRate.dose[0].doseQuantity.value = decimal
  • dosage.doseAndRate.dose[0].doseQuantity.system = coding system of the units
  • dosage.doseAndRate.dose[0].doseQuantity.code = code within the coding system for the units

Mike

1 Like

@mseaton @ibacher Please take a look at this and advise if this is the correct mapping between the UI, Order Config and MedicationRequest/MedicationDispense

UI label Order Config FHIR
Quantity - quantity.value
Dose - dosageInstruction[0].doseAndRate[0].doseQuantity.value
Dose unit drugDosingUnits e.g Tablet dosageInstruction[0].doseAndRate[0].doseQuantity.unit
Route drugRoutes e.g Oral dosageInstruction[0].route.text
Frequency orderFrequencies e.g Twice Daily dosageInstruction[0].timing.code.text

Other configurations on the Order Entry Config

  • drugDispensingUnits e.g Box, Bag
  • durationUnits e.g Days

“Correct mapping” for what purpose? The text and unit elements you’ve selected are probably ok to use for display, but should not be used for submitting data to the backend. For those, you need to use the system and code elements (or the corresponding sub-elements of the coding[0] property) to properly pass the values to the backend. (This is necessary to disambiguate codes where they are used… the display values are provided as a convenience).

Yes, agree with the @ibacher and @mseaton … for Dose Unit you will want to be submitting to "dosageInstructions[0].doseAndRate[0].doseQuantity.code, where code would be a coded reference to the unit (likely the uuid or snowmed code of the unit).

If you look at the MedicationRequest object returned when viewing a prescription, you’ll see how these elements like the dose unit, route, and frequency are defined:

In each of these cases, though you’ll be displaying the “unit” or “display” fields to the user, you’ll need to submit the “code” back to the server so that a proper match is made.

A current potential missing step is that there should be an endpoint for you to to request all the valid dose units, routes, and frequencies to use to render those drop downs (with the “unit” or “display” being the display text of the dropdown, and the “code” being the underlying value). If you don’t already know these endpoint, it would likely be worth looking at the code for the Drug Orders ESM (or perhaps talk to whoever is working on it… @samuel34 @grace?) as they will have a need for the same endpoints there.

There is a REST endpoint provided by the REST module to get this information this that is used in the 2.0 Order Entry OWA:

ws/rest/v1/orderentryconfig?v=custom:(uuid,display)

… but I’m not sure if is what we intend/want to use going forward, or if we’ve developed a FHIR equivalent? (@ibacher ?)

Acutally, just saw that there been a lot of discussion around Order Templates here… I haven’t read through it all here, but it relates to fetching the various combinations of dosage units, route, etc:

The “right” way to do this via FHIR would be to have a ValueSet that defines the values. We have a basic mapping between ConceptSets (in OMRS) and ValueSets (in FHIR) that I’d like to get some feedback on if that’s of interest… Basically if you pass the UUID of a ConceptSet to /ws/fhir2/R4/ValueSet/<UUID>, you should get the concept set as a FHIR ValueSet, which would allow you to more directly select the appropriate code and system.

Thanks @ibacher !

We probably want to create a FHIR equivalent (in the FHIR2 module?) of the “OrderConfig” endpoint in REST WS?

This would return a ValueSet for each of the six ConceptsSets?

You can see in the Order Service the underlying logic just fetches concept sets based on defined global properties:

(That being said, this is probably lower priority, and using the existing REST Order Entry Config endpoint is likely perfectly fine to use for now).

I would expect dispense events would be tracked for each individual drug.

I would expect the possible values for dose units to come from:

  1. One of the members of a concept set defined in the order entry configuration (typically, I’d expect implementations would use CIEL’s Dosing units concept set).
  2. (Someday) A subset of items from #1 based on drug-specific dosage form data. We don’t have this now, but ultimately national, WHO, or other sources (similar to the US’s RxNorm) could provide drug-specific dosage unit data that could be imported into OpenMRS and used to create more informed choice lists. You can ignore this for now.
  3. A subset of items from the intersection of #1 & #2 defined within an order template when available (i.e., an order template could set the default and/or constrain dosage unit choices to only those dosage units that make sense for the particular drug).
  4. Inferring a default by matching the drug’s dosage form to units available in #1 (when we don’t have #2 or #3).

tl;dr avoid hardcoding the expectation that all drugs will use simple dosing instructions

Keep in mind that the examples used here are for simple dosing instructions – where we have the simple case of a series of simple fields (dose + dosing unit + route + frequency ± as needed + additional instructions) being able to fully describe how the medication is to be administered. But there are many cases where this simple dosing will be insufficient to describe how to dose the drug. For now, we should be prepared to support (1) simple dosing instruction and (2) free text dosing instructions, where the first is used for simple cases and the free text dosing instructions (where only the instructions field is needed for dosing) is used to handle anything else. In the future, we expect to handle additional structures (like tapers, dosing of intravenous drugs, etc.); however, if we focus on simple dosing & free text dosing for now, we’ll be prepared to handle a 3rd, 4th, etc. form of dosing instructions.

This is what I would expect for getting OpenMRS concept sets (i.e., as FHIR ValueSets). Are members return in the order of ascending sort weight?