Specimen data from external FHIR orders is never available at accessioning (Add Sample sample-type always blank)

Summary

When an external EMR places an order via the FHIR Task/ServiceRequest import path (org.openelisglobal.remote.source.uri), a well-formed Specimen resource — correctly referenced from ServiceRequest.specimen — never makes it to the accessioning UI. The “Add Sample” screen’s sample-type dropdown is always empty, regardless of what the EMR sends, requiring a lab tech to manually re-select it every time.

Environment

  • OpenELIS-Global-2 (develop branch), docker-compose deployment
  • Remote FHIR source: public hapi.fhir.org test server (reproducible against any HAPI FHIR server)
  • Confirmed via direct source inspection, not just observed behavior

Root cause (traced in source)

  1. FhirApiWorkFlowServiceImpl’s Task-import path (saveRemoteTaskAsLocalTask / beginTaskImportOrderPath) does correctly resolve Task.basedOnServiceRequestServiceRequest.specimenSpecimen, and mirrors all of them into the co-resident FHIR store. This part works.

  2. However, electronic_order.data (the table backing the Incoming Orders queue) only ever caches the raw Task resource JSON — it never stores the associated ServiceRequest or Specimen. Confirmed by inspecting the column directly:

    {"resourceType":"Task","id":"...","basedOn":[...],"for":{...},"owner":{...}} 
    
    

    No ServiceRequest or Specimen data present, regardless of what was sent.

  3. The “Add Sample” screen (frontend/src/components/addOrder/AddSample.jsx, line 21) initializes sampleTypeId: "" with no pre-fill logic from any order source at all — manual entry, electronic order, or FHIR import all land on the same blank dropdown.

So the gap isn’t in FHIR resource resolution (that part is correct) — it’s that the specimen data gets dropped between “resolved during Task import” and “displayed at accessioning.”

We also checked and ruled out:

  • Task.input — not read anywhere in FhirApiWorkFlowServiceImpl, TaskInterpreterImpl, or TaskWorker. A checklist we found suggesting Task.input explicitly flags the specimen doesn’t match this codebase.
  • sample_type_terminology_mapping — populating this (via the real Admin → Sample Type Management → Terminology feature) makes no difference to this specific screen; it appears to serve a different purpose (unconfirmed which).

Minimal reproduction

Attached Postman collection (2 requests): upserts a Practitioner, then submits a transaction Bundle with Patient + Specimen + ServiceRequest (referencing the Specimen) + Task (referencing the ServiceRequest) to a public HAPI FHIR test server. Set remote_fhir_base to whatever your instance’s org.openelisglobal.remote.source.uri points at, and practitioner_id to match org.openelisglobal.requester.identifier.

{

  "info": {

    "name": "OpenELIS Specimen-Linking Repro",

    "description": "Minimal reproduction: an external FHIR order (Task + ServiceRequest + Specimen + Patient) with a well-formed ServiceRequest.specimen reference still results in an empty 'Select sample type' dropdown when accessioning the order in OpenELIS. See the forum post this collection accompanies for full analysis.\n\nUsage:\n1. Set `remote_fhir_base` to whatever your OpenELIS instance's `org.openelisglobal.remote.source.uri` points at (this example uses the public 
 test server).\n2. Set `practitioner_id` to match your instance's `org.openelisglobal.requester.identifier` (strip any 'Practitioner/' prefix).\n3. Run '01 - Upsert requesting Practitioner', then '02 - Place order with Specimen'.\n4. Wait for OpenELIS's poll cycle (org.openelisglobal.remote.poll.frequency, default ~2 min), then check the Incoming Orders queue in OpenELIS and try to accession the resulting order.",

    "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"

  },

  "variable": [

    { "key": "remote_fhir_base", "value": "
", "type": "string" },

    { "key": "practitioner_id", "value": "f9badd80-ab76-11e2-9e96-0800200c9a66", "type": "string" },

    { "key": "patient_id", "value": "", "type": "string" },

    { "key": "specimen_id", "value": "", "type": "string" },

    { "key": "service_request_id", "value": "", "type": "string" },

    { "key": "task_id", "value": "", "type": "string" }

  ],

  "item": [

    {

      "name": "01 - Upsert requesting Practitioner",

      "request": {

        "auth": { "type": "noauth" },

        "method": "PUT",

        "header": [{ "key": "Content-Type", "value": "application/fhir+json" }],

        "url": {

          "raw": "{{remote_fhir_base}}/Practitioner/{{practitioner_id}}",

          "host": ["{{remote_fhir_base}}"],

          "path": ["Practitioner", "{{practitioner_id}}"]

        },

        "body": {

          "mode": "raw",

          "raw": "{\n  \"resourceType\": \"Practitioner\",\n  \"id\": \"{{practitioner_id}}\",\n  \"name\": [{ \"family\": \"Smith\", \"given\": [\"John\"] }]\n}",

          "options": { "raw": { "language": "json" } }

        }

      },

      "event": [

        {

          "listen": "test",

          "script": {

            "type": "text/javascript",

            "exec": [

              "pm.test('Practitioner upserted', function () {",

              "    pm.expect([200, 201]).to.include(pm.response.code);",

              "});"

            ]

          }

        }

      ]

    },

    {

      "name": "02 - Place order with Specimen (repro)",

      "request": {

        "auth": { "type": "noauth" },

        "method": "POST",

        "header": [{ "key": "Content-Type", "value": "application/fhir+json" }],

        "url": { "raw": "{{remote_fhir_base}}", "host": ["{{remote_fhir_base}}"] },

        "body": {

          "mode": "raw",

          "raw": "{\n  \"resourceType\": \"Bundle\",\n  \"type\": \"transaction\",\n  \"entry\": [\n    {\n      \"fullUrl\": \"urn:uuid:{{patient_id}}\",\n      \"resource\": {\n        \"resourceType\": \"Patient\",\n        \"id\": \"{{patient_id}}\",\n        \"name\": [{ \"family\": \"Repro\", \"given\": [\"Specimen\"] }],\n        \"gender\": \"unknown\"\n      },\n      \"request\": { \"method\": \"PUT\", \"url\": \"Patient/{{patient_id}}\" }\n    },\n    {\n      \"fullUrl\": \"urn:uuid:{{specimen_id}}\",\n      \"resource\": {\n        \"resourceType\": \"Specimen\",\n        \"id\": \"{{specimen_id}}\",\n        \"status\": \"available\",\n        \"subject\": { \"reference\": \"Patient/{{patient_id}}\" },\n        \"type\": {\n          \"coding\": [\n            { \"system\": \"http://snomed.info/sct\", \"code\": \"258529004\", \"display\": \"Throat swab\" }\n          ]\n        },\n        \"collection\": { \"collectedDateTime\": \"2026-08-24T09:00:00Z\" }\n      },\n      \"request\": { \"method\": \"PUT\", \"url\": \"Specimen/{{specimen_id}}\" }\n    },\n    {\n      \"fullUrl\": \"urn:uuid:{{service_request_id}}\",\n      \"resource\": {\n        \"resourceType\": \"ServiceRequest\",\n        \"id\": \"{{service_request_id}}\",\n        \"status\": \"active\",\n        \"intent\": \"order\",\n        \"subject\": { \"reference\": \"Patient/{{patient_id}}\" },\n        \"specimen\": [{ \"reference\": \"Specimen/{{specimen_id}}\" }],\n        \"code\": {\n          \"coding\": [\n            { \"system\": \"http://loinc.org\", \"code\": \"94500-6\", \"display\": \"SARS-CoV-2 RNA panel\" }\n          ]\n        }\n      },\n      \"request\": { \"method\": \"PUT\", \"url\": \"ServiceRequest/{{service_request_id}}\" }\n    },\n    {\n      \"fullUrl\": \"urn:uuid:{{task_id}}\",\n      \"resource\": {\n        \"resourceType\": \"Task\",\n        \"id\": \"{{task_id}}\",\n        \"status\": \"requested\",\n        \"intent\": \"order\",\n        \"basedOn\": [{ \"reference\": \"ServiceRequest/{{service_request_id}}\" }],\n        \"for\": { \"reference\": \"Patient/{{patient_id}}\" },\n        \"owner\": { \"reference\": \"Practitioner/{{practitioner_id}}\" },\n        \"requester\": { \"reference\": \"Practitioner/{{practitioner_id}}\" }\n      },\n      \"request\": { \"method\": \"PUT\", \"url\": \"Task/{{task_id}}\" }\n    }\n  ]\n}",

          "options": { "raw": { "language": "json" } }

        }

      },

      "event": [

        {

          "listen": "prerequest",

          "script": {

            "type": "text/javascript",

            "exec": [

              "function newGuid() { return pm.variables.replaceIn('{{$guid}}'); }",

              "pm.collectionVariables.set('patient_id', newGuid());",

              "pm.collectionVariables.set('specimen_id', newGuid());",

              "pm.collectionVariables.set('service_request_id', newGuid());",

              "pm.collectionVariables.set('task_id', newGuid());"

            ]

          }

        },

        {

          "listen": "test",

          "script": {

            "type": "text/javascript",

            "exec": [

              "pm.test('Transaction Bundle accepted', function () {",

              "    pm.expect([200, 201]).to.include(pm.response.code);",

              "});",

              "console.log('task_id=' + pm.collectionVariables.get('task_id'));",

              "console.log('Expected: OpenELIS polls this Task, creates the order, but the resulting');",

              "console.log('electronic_order carries no specimen data, and Add Sample shows no sample type.');"

            ]

          }

        }

      ]

    }

  ]

}

Expected: the order appears in Incoming Orders, and generating a Lab Number pre-fills the sample type from the Specimen we sent.
Actual: order appears correctly, but “Add Sample” → “Select sample type” is blank, same as if no Specimen had been sent at all.

Question for the community: is this expected/by-design (i.e., sample type is always meant to be a manual lab-side confirmation regardless of source), or is this a genuine gap where ServiceRequest/Specimen data should be threaded through to the order cache and pre-filled?

1 Like

thanks @Bhupesh_Gupta for the question, just to confirm what version of OE are you running ?

1 Like

I am using OpenELIS version 3.2.1.11, currently I am evaluating it for integrating it with our own EMR.

1 Like

Could u find this resource use full.

1 Like

Yes this is useful and this is working as expected however the demo is using OpenELIS version 2.8 whereas mine is version 3.2.1.11. Seems like it is either broken in 3.2.1.11 or may be my FHIR bundle is not properly configured. Can you please advise on how I can fix it?

You dont have any logs when you enter this command
docker logs openelisglobal-webapp,or docker logs external-fhir-api

if any please can share them

Server side there is no error, the error is in front end refer snapshot below:

However I verified the patient information is populated properly.

NOTE: I am trying this for the first time by creating sample FHIR bundle with the help of AI, if you can share a working example of a bundle which I can try out at my end so that I can rule out any issues in FHIR bundle, that will help to further close in on the cause and fix.

1 Like

here is our implementation guide for bundle resources

Can checkout the interoperability with openmrs here

1 Like

The documentation has individual resources like patient, specimen, task, practitioner etc. I need a bundle which contains a combination of these as they are linked together. Would appreciate if you can advise on issue in my original json which I posted while creating topic.

1 Like

Hello @Bhupesh_Gupta .

Here is an actual complete FHIR bundle generated from OpenMRS to OpenELIS
The Loinc System code associated to the ServiceRequest.code must match an existing Loic assoctiated to an actual test.

You can try out the OMRS-LIS set up preconfigured out of the box.

  • Full HIE setup with the Exchange going through OpenHIM to view and log the trasnactions
  • Minimal setup with the direct exachange between OpenMRS and OpenELIS
1 Like

Figured it out! It wasn’t a bad FHIR bundle after all—just a silly configuration mistake on my end.

ACCEPT_EXTERNAL_ORDERS was set to false in SystemConfiguration.properties. Looking at the front-end code, the Add Order page only pulls the order ID from the URL when ACCEPT_EXTERNAL_ORDERS is enabled. Since it was disabled, the entire external order workflow was skipped. Front End Debugger snapshot (for reference):

AI wasn’t much help here; it kept hallucinating fixes for reading patient data on the page instead of flagging the configuration setting. Manual debugging did the trick! Setting ACCEPT_EXTERNAL_ORDERS to true completely fixed it.

@ELAI It will be good if above video can be updated to point out configuration settings that need to be enabled to run that workflow.

1 Like