0 Followers · 498 Posts

Health Level-7 or HL7 refers to a set of international standards for the transfer of clinical and administrative data between software applications used by various healthcare providers

Learn more

Job Preston Brown · Jan 19, 2024

Job Description

Planning, building, training, and manage (Program and Project) to convert HL7 inbound messages (coming from primarily Epic) to InterSystems FHIR.

Looking for a person who can develop (well versed in InterSystems FHIR experience), demo, train/mentor the team, manage the project. 

0
0 201
Question Brian Schoen · Jan 12, 2024

I am trying to pull out something similar to an HL7 date/time stamp in a custom zen page , in a javascript code section.

var d new Date();

(Fri Jan 12 2024 16:58:30 GMT-0500 (Eastern Standard Time)

but,
var year = d.getFullYear();

<Error>

d.<formatcmd>  doesn't seem to work.  (d.getmonth, etc.)

Is there and date formatting I can use inside a javascript routine?

3
0 256
Question Oliver Wilms · Jan 11, 2024

Hello, I tried to convert HL7 message to JSON in a business process and I got errors. Has anybody converted HL7 to JSON? Are certain characters not allowed in JSON?

I just tried to set a property to quote request.RAWContent and quote. I will try to put example in GitHub and share here later.

5
0 1156
Question Jimmy Christian · Dec 21, 2023

Hello community,

I am trying to see the complete HL7 message for the class EnsLib.HL7.Message.

But it is showing the truncated version only.

I also tried to convert to stream

msg.OutputToLibraryStream(.streammsg)
newmsg=##class(EnsLib.HL7.Message).ImportFromLibraryStream(streammsg)

While (streammsg.AtEnd = 0) {
     Set len = 1000
        Set tPrintMessage=newstream.Read(.len)
     Write tPrintMessage
}

But when i print it, its not showing complete message.

Any idea or suggestions?

Thank you in advance.

Jimmy Christian.
 

2
1 321
Article Yuri Marx · Dec 12, 2023 7m read

In part I of this article, we have already learned more about HL7, its messages, structure, segments, and fields. In this part II, we will show you how to transform proprietary/custom data into HL7 using IRIS for Health. For our sample, we used the data generated by the SYNTHEA bulk data generation project (https://synthea.mitre.org/downloads). So, we will show you how to convert 1000 patients from a CSV file to HL7 v2, using the Interoperability features of IRIS for Health.

Article support application – custom2hl7

0
0 669
Question Mary George · Nov 29, 2023

Hi Community, 

Can I please check if any one is aware of any functionality in HealthShare to verify NHS Number check digit.

We are trying to implement the NHS Number check digit validation using Modulus 11 Algorithm ( described here : NHS NUMBER (datadictionary.nhs.uk) ) 

I wanted to check if there is any built in option available or if anyone has implemented something similar using Object Script. 

Thank you for your help.  

Mary

3
0 354
Article Davi Massaru Teixeira Muta · Nov 26, 2023 8m read

Introduction

This article aims to explore how the FHIR-PEX system operates and was developed, leveraging the capabilities of InterSystems IRIS.

Streamlining the identification and processing of medical examinations in clinical diagnostic centers, our system aims to enhance the efficiency and accuracy of healthcare workflows. By integrating FHIR standards with InterSystems IRIS database Java-PEX, the system help healthcare professionals with validation and routing capabilities, ultimately contributing to improved decision-making and patient care.

how it works

  • IRIS Interoperability: Receives messages in the FHIR standard, ensuring integration and compatibility with healthcare data.

  • Information Processing with 'PEX Java': Processes FHIR-formatted messages and directs them to Kafka topics based on globally configured rules in the database, facilitating efficient data processing and routing, especially for examinations directed to quarantine.

  • Handling Kafka Returns via External Java Backend: Interprets only the examinations directed to quarantine, enabling the system to handle returns from Kafka through an external Java backend. It facilitates the generation of prognostic insights for healthcare professionals through Generative AI, relying on consultations of previous examination results for the respective patients.

Development

Through the PEX (Production EXtension) by InterSystems, a extensibility tool enabling enhancement and customization of system behavior, we crafted a Business Operation. This component is tasked with processing incoming messages in the FHIR format within the system. As example follows:

import com.intersystems.enslib.pex.*;
import com.intersystems.jdbc.IRISObject;
import com.intersystems.jdbc.IRIS;
import com.intersystems.jdbc.IRISList;
import com.intersystems.gateway.GatewayContext;

import org.apache.kafka.clients.producer.*;
import org.apache.kafka.common.serialization.*;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;

import java.io.FileInputStream;
import java.io.IOException;
import java.util.Properties;

public class KafkaOperation extends BusinessOperation {
// Connection to InterSystems IRIS
private IRIS iris;

// Connection to Kafka
private Producer<Long, String> producer;

// Kafka server address (comma separated if several)
public String SERVERS;

// Name of our Producer
public String CLIENTID;

/// Path to Config File
public String CONFIG;

public void OnInit() throws Exception {
[...]
}

public void OnTearDown() throws Exception {
[...]
}

public Object OnMessage(Object request) throws Exception {
    IRISObject req = (IRISObject) request;
    LOGINFO("Received object: " + req.invokeString("%ClassName", 1));

    // Create record
    String value = req.getString("Text");
    String topic = getTopicPush(req);
    final ProducerRecord<Long, String> record = new ProducerRecord<>(topic, value);

    // Send new record
    RecordMetadata metadata = producer.send(record).get();

    // Return record info
    IRISObject response = (IRISObject)(iris.classMethodObject("Ens.StringContainer","%New",topic+"|"+metadata.offset()));
    return response;
}

private Producer<Long, String> createProducer() throws IOException {
[...]
}

private String getTopicPush(IRISObject req) {
[...]
}

[...]
}

`

Within the application, the getTopicPush method takes on the responsibility of identifying the topic to which the message will be sent.

The determination of which topic the message will be sent to is contingent upon the existence of a rule in the "quarantineRule" global, as read within IRIS.

String code = FHIRcoding.path("code").asText();
String system = FHIRcoding.path("system").asText();

IRISList quarantineRule = iris.getIRISList("quarantineRule",code,system);

 String reference = quarantineRule.getString(1);
 String value = quarantineRule.getString(2);

 String observationValue = fhir.path("valueQuantity").path("value").asText()

When the global ^quarantineRule exists, validation of the FHIR object can be validated.

private boolean quarantineValueQuantity(String reference, String value, String observationValue) {
    LOGINFO("quarantine rule reference/value: " + reference + "/" + value);
    double numericValue = Double.parseDouble(value);
    double numericObservationValue = Double.parseDouble(observationValue);

    if ("<".equals(reference)) {
        return numericObservationValue < numericValue;
    }
    else if (">".equals(reference)) {
        return numericObservationValue > numericValue;
    }
    else if ("<=".equals(reference)) {
        return numericObservationValue <= numericValue;
    }
    else if (">=".equals(reference)) {
        return numericObservationValue >= numericValue;
    }
    
    return false;
}

Practical Example:

When defining a global, such as:

Set ^quarantineRule("59462-2","http://loinc.org") = $LB(">","500") 

This establishes a rule to "59462-2" code and ""http://loinc.org"" system in the global ^quarantineRule, specifying a condition where the value when greater than 500 is defined as quarantine. In the application, the getTopicPush method can then use this rule to determine the appropriate topic for sending the message based on the validation outcome.

Given the assignment, the JSON below would be sent to quarantine since it matches the condition specified by having:

 {
          "system": "http://loinc.org",
          "code": "59462-2",
          "display": "Testosterone"
}

"valueQuantity": { "value": 550, "unit": "ng/dL", "system": "http://unitsofmeasure.org", "code": "ng/dL" }

FHIR Observation:

{
    "resourceType": "Observation",
    "id": "3a8c7d54-1a2b-4c8f-b54a-3d2a7efc98c9",
    "status": "final",
    "category": [
      {
        "coding": [
          {
            "system": "http://terminology.hl7.org/CodeSystem/observation-category",
            "code": "laboratory",
            "display": "laboratory"
          }
        ]
      }
    ],
    "code": {
      "coding": [
        {
          "system": "http://loinc.org",
          "code": "59462-2",
          "display": "Testosterone"
        }
      ],
      "text": "Testosterone"
    },
    "subject": {
      "reference": "urn:uuid:274f5452-2a39-44c4-a7cb-f36de467762e"
    },
    "encounter": {
      "reference": "urn:uuid:100b4a8f-5c14-4192-a78f-7276abdc4bc3"
    },
    "effectiveDateTime": "2022-05-15T08:45:00+00:00",
    "issued": "2022-05-15T08:45:00.123+00:00",
    "valueQuantity": {
      "value": 550,
      "unit": "ng/dL",
      "system": "http://unitsofmeasure.org",
      "code": "ng/dL"
    }
}

The Quarkus Java application

After sending to the desired topic, a Quarkus Java application was built to receive examinations in quarantine.

@ApplicationScoped
 public class QuarentineObservationEventListener {

@Inject
PatientService patientService;

@Inject
EventBus eventBus;

@Transactional
@Incoming("observation_quarantine")
public CompletionStage<Void> onIncomingMessage(Message<QuarentineObservation> quarentineObservationMessage) {
	var quarentineObservation = quarentineObservationMessage.getPayload();
	var patientId = quarentineObservation.getSubject()
			.getReference();
	var patient = patientService.addObservation(patientId, quarentineObservation);
	publishSockJsEvent(patient.getId(), quarentineObservation.getCode()
			.getText());
	return quarentineObservationMessage.ack();
}

private void publishSockJsEvent(Long patientId, String text) {
	eventBus.publish("monitor", MonitorEventDto.builder()
			.id(patientId)
			.message(" is on quarentine list by observation ." + text)
			.build());
}
 }

This segment of the system is tasked with persisting the information received from Kafka, storing it in the patient's observations within the database, and notifying the occurrence to the monitor.

The monitor

Finally, the system's monitor is responsible for providing a simple front-end visualization. This allows healthcare professionals to review patient/examination data and take necessary actions.

Implementation of langchainPT

Through the monitor, the system enables healthcare professionals to request recommendations from the Generative AI.

@Unremovable
@Slf4j
@ApplicationScoped
public class PatientRepository {
	@Tool("Get anamnesis information for a given patient id")
	public Patient getAnamenisis(Long patientId) {
		log.info("getAnamenisis called with id " + patientId);
		Patient patient = Patient.findById(patientId);
		return patient;
	}

	@Tool("Get the last clinical results for a given patient id")
	public List<Observation> getObservations(Long patientId) {
		log.info("getObservations called with id " + patientId);
		Patient patient = Patient.findById(patientId);
		return patient.getObservationList();
	}

}

segue implementação de langchain4j

@RegisterAiService(chatMemoryProviderSupplier = RegisterAiService.BeanChatMemoryProviderSupplier.class, tools = {PatientRepository.class})
public interface PatientAI {

	@SystemMessage("""
			You are a health care assistant AI. You have to recommend exams for patients based on history information.
			""")
	@UserMessage("""
			 Your task is to recommend clinical exams for the patient id {patientId}.

			 To complete this task, perform the following actions:
			 1 - Retrieve anamnesis information for patient id {patientId}.
			 2 - Retrieve the last clinical results for patient id {patientId}, using the property 'name' as the name of exam and 'value' as the value.
			 3 - Analyse results against well known conditions of health care.

			 Answer with a **single** JSON document containing:
			 - the patient id in the 'patientId' key
			 - the patient weight in the 'weight' key
			 - the exam recommendation list in the 'recommendations' key, with properties exam, reason and condition.
			 - the 'explanation' key containing an explanation of your answer, especially about well known diseases.

			Your response must be just the raw JSON document, without ```json, ``` or anything else.
			 """)
	String recommendExams(Long patientId);
}

In this way, the system can assist healthcare professionals in making decisions and carrying out actions.

Video demo

VIDEO

Authors

NOTE:

The application https://openexchange.intersystems.com/package/fhir-pex is currently participating in the InterSystems Java Contest 2023. Feel free to explore the solution further, and please don't hesitate to reach out if you have any questions or need additional information. We recommend running the application in your local environment for a hands-on experience. Thank you for the opportunity 😀!

3
0 441
Question Chris Lambert · Nov 30, 2023

This question originally appeared in the comments of the post: Making use of Multiple Sub Transforms in a main map || HL7
 

I'm having a similar problem trying to get PRD(1) into PV1:ReferingDoctor and PRD(2) into PV1:ConsultingDoc
Running the subtransform will populate referring doctor for the first PRD, and then the second running will delete the PV1, make a new one with only the consulting doctor populated.

Was hoping I could use a subtransform to populate the information, but looks like it has to be done at the transform level.

1
0 232
Question Ilenia Centonze · Nov 20, 2023

Hi everyone,

It could be great if some of you have had experience in hl7 v2 messages. The question is about FHIR to hl7 v2.5 conversion. I have to translate a binary resource, encoded in base64 into an orl_o22 message. Do you have advices? Which field could be used for that datatype? 
I have found some implementation using nte segment but it is limited in characters.

Thank you

5
0 449
Question Yone Moreno · Nov 6, 2023

Good morning,

First of all we would like to thank you for your time reading, thinking and aswering this question.

We have been developing a Transformation to convert a source ORU_R01 to a target ORU_R01. For each OBX segment we need to check an if, and then, if it is true we just need to put this OBX and continue to the next iteration, otherwise, if it is false, we need to put (copy) the ORC + OBR + TQ1 before this OBX, and then put this OBX, and after that, the SPM.

4
0 310
Question Yone Moreno · Oct 17, 2023

Hello,

First of all, thanks for your help, and time, reading this questions, and answering to this doubt.

We have the following use case: to convert a HL7 ER7 ORU_R01 v2.5 message, to a Ens.Request Message which represent it with a custom data structure (each segment is a group of Properties).

To be more precise, the target Ens.Request Message's structure looks like:

5
0 596
Article Zhong Li · Feb 15, 2023 11m read

A "big" or "small" ask for ChatGPT?


I tried OpenAI GPT's coding model a couple of weeks ago, to see whether it can do e.g. some message transformations between healthcare protocols. It surely "can", to a seemingly fair degree. 
It has been nearly 3 weeks, and it's a long, long time for ChatGPT, so I am wondering how quickly it grows up by now, and whether it could do some of integration engineer jobs for us, e.g. can it create an InterSystems COS DTL tool to turn the HL7 into FHIR message? 

Immediately I got some quick answers, in less than one minute or two.


Test

7
1 2738
Question Adrian Howe · Oct 16, 2023

Hello,

I have a problem attempting to store a base 64 encode stream into the OBX:5 field of a HL7 message, by using the StoreFieldStreamBase64 method.

I'm using a transformer to input the contents of a pdf within a stream container (Ens.StreamContainer). The output is a HL7 message (EnsLib.HL7.Message 2.5:ORU_R01).

The transformer is being used in a business process.

This is the code used in the transformer to encode the stream to base 64:

Try {
     Set pdfStreamObj = source.StreamGet()
   } Catch {
      Quit
   }

2
0 485
Question ED Coder · Jul 31, 2019

Hi,

I have a ORU message, which has a EVN segment that I want to remove and send the message across.

I tried to clone the request as below:

s newreq = request.constructClone

s changreq = newreq.RemoveSegmentAt("EVN")

Set request  = changereq

but it fails. Is there a way that I can safely remove a segment and pass it on?

Would appreciate your help in this

Regards,

Eric

13
0 2144
Question Smythe Smythee · Aug 8, 2023

Hi community,

I am trying to map <assign value='source.{ORCgrp(1).RXE:7.1}' property='target.{ORCgrp(1).RXE:7.1}' action='set' /> in data transformation 

My input value for source RXE isRXE:7.1 will be like Keep orders~New orders  ~       ~ new orders

 After mapping i am getting only First repetition  value i,e is only Keep orders value  

I have tried using $EXTRACT like this <assign value='$EXTRACT(source.{ORCgrp(1).RXE:7.1},1,*)' property='target.{ORCgrp(1).RXE:7.1}' action='set' /> in data transformation  still getting First repetition value in target message

3
0 248
Question Mark OReilly · Aug 15, 2023

We have this intermittent issue with a particular supplier message , just wondering if anyone has further insight around the two errors we get when we see this. 

We use the out of the box TCP hl7 adapter. 

We first seem to get this incomplete hl7 message resulting in an error like 

Discarding leftover input 'MSH|

This is not unexpected as the final obx has not dot the description of OBX:2.2 ect. 

OBX|53|TX|NCDAC^

The next message will have the error 

2
0 280
Announcement Emily Geary · Aug 11, 2023

If you hold the InterSystems HL7 Interface Specialist certification, you can potentially get recertified and have your certification expiration date extended by five years by beta testing our new InterSystems HL7 Interface Specialist Recertification project. The project includes hands-on exercises to validate core skills for developers who use InterSystems products to build and test HL7 v2.x productions. During the beta period, which extends until October 31, 2023, anyone who holds the credential is eligible to try the project, and the standard $150 fee is waived for candidates.

0
2 200
Question Jimmy Christian · Aug 7, 2023

Greetings.

I have a scenario in ENSEMBLE, where a business process router A is dependent on another business process router B.  If B shuts down for some reason, A has to be disabled as well.

Do i need to write a custom process for B and call the call back method onShutdown or something?

Any suggestions would be appreciated.

Thanks,

Jimmy Christian.

0
0 141
Question Minn Bo Bo · Jul 27, 2023

I have been successfully able to transform hand-written medical test results documents to HL7 ORU_R01 v2.x, then to SDA, which will be trasformed to FHIR or C-CDA.
However, I have a category of documents which contains reference range in multiple date formats, which are measured for each gestation period. 
For example, below is one of the documents.
 

Analyte: HCG, Value: 1968, Unit: mlU/mL 

Reference Range:
Week of gestation: 3, Range: 5.8-71.2
Week of gestation: 4, Range: 9.5-750
Week of gestation: 5, Range: 217-7138
Week of gestation: 6, Range: 158-31795

4
0 338
Question John Nurmi · Jul 27, 2023

In an HL7 Business rule I am trying to block ONLY ORM messages that have a PV1:3.4 of 105 or 205 and a OBR:4 value of EP22 or CATH01.

I created the logic below but it appears to be evaluating the two fields independently instead of combined?

Here is what I had.

(((HL7.{MSH:SendingApplication.NamespaceID}="Epic_Cupid")&&(HL7.{ORCgrp(1).ORC:OrderControl} IN "NW,CA")))&&(((HL7.{PIDgrp.PV1grp.PV1:AssignedPatientLocation(1).Facility.NamespaceID} NotIn "105,205")&&(HL7.{ORCgrp(1).OBRuniongrp.OBRunion.OBR:UniversalServiceIdentifier.Identifier} NotIn "CATH01,EP22")))

1
0 254
Question Jon Astle · Jul 20, 2023

Hi

We've been asked to develop a HL7 interface, but the end system has very different needs than any we've ever interfaced with before. We need assistance to determine if these needs are things HealthShare can support that we're just not aware of, or whether we'll need to develop some custom code to accomplish this.

This end system wants us to send HL7 messages completely asynchronously, one after the other without waiting for any form of ACK or NAK. My first thought was that we could have an outbound HL7 operation which set the session to deferred, with a separate inbound listener service on a separate port that brought the ACKs and NAKs back in. We could then write a custom process that would link the ACKs/NAKs back to the original deferred session. Is there an out of the box option for that sort of deferred HL7 sending operation?

However, there's an additional complication. The end system supplier isn't sure they can send the ACKs and NAKs back on a separate port. They want to receive all messages asynchronously, but also ideally they'd want to send the ACKs and NAKs back on the same port the original messages were sent out from. We know that, at least in all the synchronous interfaces we've configured before, that HealthShare sends a message, waits for a response and moves onto the next message once it's received a response. If a message comes back when there isn't an active session listening for, that ACK gets purged as "unexpected data in buffer" when the next message is sent.

If a message comes back when there's a different active session listening for a response, it gets processed as if it were in response to the current session (depending on the :I? reply code action config). When we asked them how the ACKs or NAKs should be linked back to the correct original message if it was all asynchronous, they believed the Message Control ID should suffice. Is there an out of the box option for a HL7 sending operation to operate in that way, i.e. where messages are sent out without waiting for a response and responses can come back on that same port at any time? (The end system supplier are going to investigate if they can send ACKs and NAKs on a separate port to support my first idea above, but they're not sure they can accommodate that, so we need to explore both scenarios on our side).

Thirdly, as above, they believe the Message Control ID should be sufficient to match ACKs/NAKs to original messages, but I pointed out that would fail in the event of any message resends. I explained how HealthShare can be configured resend a message multiple times, e.g. in a synchronous interface if there was a timeout, or in either sync or async if there was an AE NAK for example. The end system supplier was perplexed. Their assertion is that the HL7 standard dictates that a Message Control ID should never be repeated. If a message is resent, it should be resent with a unique ID. I explained that to the best of my knowledge, the out of the box HL7 sending operations don't have any facility coded for amending the content of the message in any way. Am I right about that, or is there an out of the box option to support that? (e.g. perhaps appending a _1, _2, etc to the end of the message control ID that increments up on each send?)

Any advice would be much appreciated.

4
0 517