Hey Community,
Watch this video to get an introduction to the components of an HL7 V2 production in InterSystems products, which works as an integration engine to connect healthcare systems:
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
Hey Community,
Watch this video to get an introduction to the components of an HL7 V2 production in InterSystems products, which works as an integration engine to connect healthcare systems:
I am using Intersystems Iris Community Edition. I have created a Rest Api to post HL7 message directly through postman. It is working fine, But I want to create the business service to read the HL7 message from Rest- Api. I tried to create this, but I am not understanding how to do that. Can anybody help me?
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.
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?
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.
Within a DTL is it possible to access and update the Message Header properties of an EnsLib.HL7.Message?
Currently we have multiple EMR Services for each environment sending to 1 Business Process to Normalize the data, then it is sent to another Business Process to route the data.
I would like to strip the , at the end of a string. I'm able to find the start of the string using ..StartsWith(String,",") but not able to strip the "," at the end of a string.
I've tried:
Str="Addr1,Addr2,"
Piece(Str,"",1,Length(Str)-1)
Piece(Str,"",1,Length(Str)-2)
Extract(Str, Length(Str)-1)
Extract(Str, Length(Str))
But nothing works as expected.
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
d msg.OutputToLibraryStream(.streammsg)
s 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.
Does anyone have an effective tool for anonymizing/deidentifying CCDAs for testing purposes?
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.
Hi all
I'm having trouble defining the mapping needed to take the very large base64 string in OBX:5.5, and map it to an XML virtual document property that supports Stream.GlobalCharacter. I know from within the DTL you have to use custom code to manage the segment due to its size.
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
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.
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.

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"
}
}
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.
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.

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.
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 😀!
How can i modify file extention on output file leaving Busness Operation
Ex..changing "output.txt" to "output.hl7"
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.
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
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.
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:
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.
Hello Community,
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
}
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
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
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
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.
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.
Did you know that with InterSystems IRIS for Health™, you can create a FHIR Facade that enables healthcare apps to send and receive HL7® FHIR® data?
Find out how in this learning path (3h 30m), which includes a hands-on exercise (20m).
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
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")))
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.