Repeat prescriptions in O3: counting refills and renewing safely

Hi all,

At SolDevelo we’ve been tasked by MSF to deliver better repeat prescribing and dispensing, and we want to build it in O3 itself, in a way the community agrees. I’ve seen several threads that have already designed parts of this. The intention for this post is to collect the decisions from various threads, verify the state and agree on the way we implement it.

The need

Some treatments run for a long time. For example, a treatment lasts a year, and the doctor prescribes 2 months at a time, knowing the patient will be back (not actual numbers).

Two people are involved:

  • The pharmacist is legally responsible for dispensing the right medication the right number of times. They need to see how many times a prescription has been dispensed, and the system must not allow more than was prescribed. MSF sees the pharmacist as the main user.
  • The prescriber must still review what they prescribe, so repeating a prescription must not skip that review.

What O3 does today

We tested this on MSF’s LIME distribution (dispensing app 1.11.2-pre, patient chart 12.3.5-pre, default settings):

  • Refills are not counted. An order with 2 refills (3 fills) accepted 5 dispenses posted through the FHIR API, and the dispensing app still offered Dispense, with the card showing “Refills 2”. The history lists the fills without totaling them.
  • The quantity limit is frontend only. restrictTotalQuantityDispensed is off by default. When it is on, it caps tablets at quantity × (1 + refills) in the dispense form, and marks the order completed after the last fill. Dispenses posted to the API are not checked.
  • Refills stop at day 90. A request older than medicationRequestExpirationPeriodInDays (90) cannot be dispensed, whatever its refills. A 2-month supply with 5 refills stops after the second fill.
  • A renewal does not stop the original. If the original still has refills, both orders can be dispensed.
  • Renew puts the order straight into the basket. The order form does not open, so the prescriber can sign without seeing the details.

What the community has already worked out

As far as we can see, none of these has a ticket or work in progress. If someone is already on one of them, please say so and we will work with you.

Part 1: what we plan to implement

These follow designs already discussed. Unless there are objections, we will file the tickets and send the PRs:

  1. RENEW stops the original, following @dennis plan in t/49428. This is a core change (OrderServiceImpl).
  2. Renew opens the order form, so the prescriber reviews each line before it goes into the basket. Question 5 below asks whether today’s one-click behaviour should stay as an option.

Part 2: open questions

  1. How should O3 support repeats? Several models are in use:

    • (a) Refills counted on one order. The doctor prescribes “2 months + 5 refills”. Dispensing shows “Fill 2 of 6”, the last fill and the next due date, and blocks a fill after the last one. This is the 2022 rule, and the model that seems to be present in other dispensing systems.
    • (b) Whole span with a quantity limit. The doctor prescribes 12 months and the total quantity. The pharmacy gives 2 months at a time against restrictTotalQuantityDispensed. This exists today but counts tablets, not fills.
    • (c) A new prescription each cycle. The prescriber renews and reviews at every visit, so each order is dispensed once.

    We lean towards (a) for the pharmacist, with (c) for patients who see the prescriber at every visit.

  2. Where should the limit be enforced? In the dispensing app only (as today), in a backend validator (@burke has said dispensing logic belongs outside core, so a module or fhir2?), or both? Could this extend the duplicate-dispense validator? We would favor the backend, but should it belong to totally seperate module?

  3. When does a repeat prescription expire? Options: keep the global 90-day setting; derive it per order from the start date + duration × (1 + refills); or add an explicit end date (FHIR validityPeriod.end).

  4. Does a partial dispense count as a fill? For example, 30 tablets given against a 56-tablet fill.

  5. One-click renew: should Renew always open the form, or should today’s one-click behaviour stay as a configurable option?

We would like to settle the direction in the next week or couple, and then start the implementation. Reviewers and anyone with the same need are very welcome.

I’ve tagged several people that ware involved in the dispensing threads over the years:

@burke @ibacher @mseaton @mogoodrich @dennis @veronica

Thanks @pwargulak ! A few quick thoughts.

  • I agree that ideally this should happen in the backend somewhere, we built this into the ESM for expediency but happy to see it moved to the backend–though to you point not quite sure exactly where this logic should live, though. FHIR2 doesn’t seem quite appropriate
  • Due to the fact that stock-outs and partial fills are common at sites, there was a specific request to restrict dispensing at the tablet/quantity level vs the fill level, ie max quantity to dispense = quantity per fill * (1 + numnber of refills). This is certainly more complicated than just doing it based on allowed fills = 1 + num of refills, but it was intentional. (Doesn’t necessarily mean we can’t change or tweak, but wanted to flag that)
  • For the expiration date, agree that 90 days may be too short for the average implementation and it was made to be configurable. It’s kind of a blunt instrument at this point,and making it based on the length of the prescription does make some sense, but may not be the only thing to consider. The expiration date is also meant to account for any delay between when the prescription is filled and the patient goes to fill it. ie, if we base it on start date + duration, and we have one prescription with a duration of 30 days, the patient only has 30 days to do the initial fill, but if it’s a prescription for a year, they could could wait 11 months before starting to fill it, which doesn’t seem quite right.

Also flagging @fanderson