# Orders, results and prescriptions

  An order and a prescription have the same shape. Something is requested here, performed
  somewhere else, and answered back. Write the routing once and it covers both.

  The order surface on this page is designed and not yet built: no `/orders` prefix is registered
  in the service under either version, and neither is `/api/v1/visits/{visit_id}/orders`. Every
  order and result call here answers 404 today.

  The prescription calls below are real. Read the order half as the shape that is coming — it is
  what the rail is being built to — and do not schedule work against it until the routes land.

## What changes when the request leaves the building

Inside one HMIS, ordering a test is a database write. The requester and the performer share a
schema, so "routed to the lab" means a row with a status on it.

On the rail the performer may be a different organisation, running different software, in a
different town. That works because neither side integrates with the other. Both are already
on the rail, and the rail does the routing.

<Wire
  rows={[
    { call: "You order", does: "A lab test, an image or a procedure. You name what you want and who should do it, and you never connect to them directly.", keep: "order_id" },
    { call: "They see it", does: "The order lands in the performing facility's inbox as work, whether they run your software or somebody else's.", keep: "their queue" },
    { call: "They answer", does: "Results are returned against the order and reach you as the requester. You do not build a second integration, and you do not poll a result mailbox per partner.", keep: "result_ref" },
  ]}
/>

## Orders

<ApiRef method="POST" path="/api/v1/visits/{visit_id}/orders" to="/rail-api/05-treat">
  Order a lab, an image or a procedure, with the diagnosis that justifies it.
</ApiRef>

Three things about the response are worth building for.

<Wire
  rows={[
    { call: "Panels expand", does: "An ordered panel comes back as its constituent parameters, each with its own code and reference range. The rail does that expansion, so do not keep a panel-to-parameter table of your own.", keep: "expanded_parameters[]" },
    { call: "Routing is a state you read", does: "routed means the performer has it. If they are briefly unreachable the order is held and retried. That is not a failure, and it must not make you raise a second order.", keep: "status" },
    { call: "The reason travels", does: "The diagnosis on the order is what a payer reads later to decide whether the test was indicated. An order with no reason can still be billed, and it can just as easily be rejected.", keep: "reason[]" },
  ]}
/>

<ApiRef method="GET" path="/api/v1/orders?performer_facility=" to="/rail-api/05-treat">
  The orders routed to this facility. This is your work queue, and it holds requests from every requester on the rail.
</ApiRef>

A facility that only ever posts orders has built half the feature. The inbox is what makes
you a performer as well as a requester, and it is the same call whether the request came from
your own clinician or from a facility two counties away.

## Results

<ApiRef method="POST" path="/api/v1/orders/{order_id}/results" to="/rail-api/05-treat">
  Return the result. It reaches the requester, and it lands in the patient's record.
</ApiRef>

Return observations against the expanded parameter list the order came back with, rather than
against your own panel definition. A result that carries observations the order did not ask
for, or misses ones it did, is refused with `RESULT_ORDER_MISMATCH` instead of being stored
quietly against the wrong codes.

A result written this way does three jobs at once. It answers the requester, it becomes an
`Observation` in the shared record, and it is the evidence behind the line when the claim is
assessed. That is why you record clinically instead of billing directly.

  `status: preliminary` is a legitimate return and clinicians act on it. Send it when you have
  it and supersede it with `final`. A system that holds everything back until verification
  keeps the requester waiting for information the lab already has.

## Prescriptions

The prescription is the case where routing matters most, because the patient chooses where to
fill it, and that is usually not where it was written.

<ApiRef method="POST" path="/api/v1/prescriptions" to="/rail-api/05-treat">
  Prescribe, routed to the pharmacy the patient names.
</ApiRef>

<Anatomy
  cards={[
    {
      title: "Per item",
      required: ["medication", "dose", "route", "frequency", "duration_days", "quantity"],
      optional: ["substitution_allowed", "instructions"],
      note: "medication is coded, with KEML as the national list. A free-text drug name gives you a prescription no other system can dispense against.",
    },
    {
      title: "Per prescription",
      required: ["diagnosis", "prescriber"],
      optional: ["route_to_facility"],
      note: "Omit route_to_facility and the prescription is open, so any pharmacy on the rail can claim it. Name one and only that pharmacy sees it.",
    },
  ]}
/>

## Pulling what was routed to you

<ApiRef method="GET" path="/api/v1/prescriptions" to="/rail-api/05-treat">
  Prescriptions written anywhere on the rail and routed to this pharmacy.
</ApiRef>

This call is what takes paper off the pharmacy counter. The patient arrives with an identity
rather than a slip, and you pull what was written for them and dispense against it.

<ApiRef method="POST" path="/api/v1/prescriptions/dispense" to="/rail-api/05-treat">
  Record what was actually handed over, including a partial fill or a substitution.
</ApiRef>

<Wire
  rows={[
    { call: "Partial fills accumulate", does: "Dispensing 10 of 24 leaves 14. The next dispense, possibly at another pharmacy, reads what remains, and anything over that is refused.", keep: "quantity_remaining" },
    { call: "Substitution follows the prescriber's flag", does: "Where the prescriber set substitution_allowed: false, a different product is refused. Send it back to the prescriber instead.", keep: "substitution_allowed" },
    { call: "Bill what was dispensed", does: "A pharmacy line traces back to the dispense record rather than to the prescription, so bill the fill.", keep: "dispense_id" },
  ]}
/>

## What breaks here

<CostTable
  rows={[
    {
      where: "Treat",
      symptom: "\"We raised the order twice because it looked stuck\"",
      cause: "routed means held and retrying rather than failed. A duplicated order produces a duplicated specimen and two results against one clinical question.",
    },
    {
      where: "Treat",
      symptom: "\"The result came back and the codes did not match anything\"",
      cause: "Results were returned against a local panel definition rather than the expanded parameters the order carried.",
    },
    {
      where: "Treat",
      symptom: "\"The pharmacy cannot see the prescription\"",
      cause: "It was routed to a named facility that is not this one. Re-route it rather than re-writing it.",
    },
    {
      where: "Bill",
      symptom: "\"We billed the prescription and were short-paid\"",
      cause: "The patient took a partial fill. The dispense is the billable event, not the prescription.",
    },
  ]}
/>

### Errors

| HTTP | `error` | When |
|------|---------|------|
| 502 | `ORDER_PERFORMER_UNREACHABLE` | The performing facility has not accepted the order yet. |
| 409 | `RESULT_ORDER_MISMATCH` | Observations returned do not match the order's parameters. |
| 403 | `PRESCRIPTION_NOT_ROUTED_HERE` | Dispensing against another pharmacy's prescription. |
| 409 | `DISPENSE_EXCEEDS_PRESCRIBED` | Cumulative dispensed quantity is over the prescribed one. |
| 409 | `SUBSTITUTION_NOT_ALLOWED` | A substitute was dispensed where the prescriber forbade it. |

  Sending a specimen to a hub is an order that also has to travel. The authorisation the
  patient gave you moves with the referral, so they do not have to give it again at the other
  end.
