Question
· Mar 13, 2023

How to create a business service for reading JSON input into the Ensemble production

Hi Community,

I am receiving a JSON file as input in ensemble and i need to convert the JSON message to HL7 message.

Can anyone share few points how to read a JSON file into Ensemble production by creating a Custom Business service?

I have created a custom business service as below but i am not aware which parameters i need to pass in  OnProcessInput method?

Method OnProcessInput(pInput As Ens.Request, Output pOutput As %RegisteredObject) As %Status

Do i need to Ens.Request or RegisteredObject or  Ens.StreamContainer?

 

Thanks,

Joe

Product version: Ensemble 2018.1
$ZV: Cache for Windows (x86-64) 2018.1.1 (Build 312_1_18937U) Fri Apr 26 2019 17:58:36 EDT
Discussion (13)2
Log in or sign up to continue

***Disclaminer, I consider myself to be a fairly new Cache Objectscript developer. If any developers with more experience have suggestions for how to do this easier, more efficient, etc. Please share. I am eager to learn more that will help me in the future. :) 

I have done this in the past, I created a business service with the EnsLib.HTTP.InboundAdapter to receive the JSON message on a REST end point. I also created a class for the JSON message structure. In the business service, I receive the JSON message and pass it to a business operation. In the business operation I have a transform that transforms the JSON to HL7 message, then the business process passes the HL7 message to a business operation to send to a new HL7 end point. This code was created in Ensemble 2017. If you are using IRIS, there are more classes for JSON message handling you might be able to use.

My business service handles several different JSON messages, this is the one of the methods I have for one of the messages. In the method I convert the JSON object that was received into a new object of type TMP.AppointmentReqMsg. TMP.AppointmentReqMsg is the class that defines the JSON message structure. 

The new JSON object is passed to a business process to process the message. In the business process, I have a transform that transforms the JSON object to HL7. Then the business process will call the business operation that sends the HL7 message on to an HL7 end point.

Hope this helps.

Method appointmentAction1(pInput As %Library.AbstractStream, Output pOutput As %Stream.Object, pAppointment As %Stream.Object) As %Status
{  $$$LOGWARNING("In processing appointments")  #dim ApptArray As %List
 #dim tSC,tSC1,tSC2 As %Status = $$$OK  #dim processingFlag As %String
 #dim patientFacility As %String
 #dim providerFacility As %String
 #dim pFlag,provFlag,patFlag AS %Numeric = 0
 
 
 pInput.Rewind()
 pJSON=pInput.Read()  set sc=##class(%ZEN.Auxiliary.jsonProvider).%ConvertJSONToObject(pJSON,"TMP.AppointmentReqMsg",.pRequestBody,1)
 s:##class(Ens.Util.FunctionSet).Lookup("CernerSites",pRequestBody.ProviderFacility)>0 provFlag=1
 S:##class(Ens.Util.FunctionSet).Lookup("CernerSites",pRequestBody.PatientFacility)>0 patFlag=1
     pFlag=provFlag+patFlag   ;pFlag=0;VistA only, pFlag=2;Cerner only, pFlag=1;Cerner and VistA
     pRequestBody.ProcessingFlag=(provFlag+patFlag)
 $$$LOGWARNING("checking json")
 s:##class(Ens.Util.FunctionSet).Lookup("CernerSites",pRequestBody.PatientResources.Facility)'>0 tSC2 = ..checkJSON(pRequestBody.PatientResources.Resources)
 $$$LOGWARNING("checking json returned "_tSC2)
 $p(tSC2,"^",1)=2 tSC=..ReturnJSONAckMsg(.pRequestBody,tSC2)
 q:$p(tSC2,"^",1)=2 200
 s:##class(Ens.Util.FunctionSet).Lookup("CernerSites",pRequestBody.ProviderResources.Facility)'>0 tSC2 = ..checkJSON(pRequestBody.ProviderResources.Resources)
 $$$LOGWARNING("checking json returned "_tSC2)
 $p(tSC2,"^",1)=2 tSC=..ReturnJSONAckMsg(.pRequestBody,tSC2)
 q:$p(tSC2,"^",1)=2 200
 
 badResponse=##class(AppointmentResponseMsg).%New()
 badResponse.ControlId = pRequestBody.ControlId
 badResponse.MessageId = pRequestBody.MessageId
 badResponse.OrganizationName = "CVT15"
 badResponse.Status="AA"
 badResponse.FailureReason=""
 if +$L(patientFacility)>0
 {
   VistABO=##class(Ens.Util.FunctionSet).Lookup("TMP_VistA_Systems",patientFacility),^zzphil("p1")=VistABO
   
 s:$g(VistABO)="" badResponse.FailureReason="Patient Site is not configured in HealthConnect"
 }
 
 
 
 if $L(providerFacility)>0
 {
  VistABO1=##class(Ens.Util.FunctionSet).Lookup("TMP_VistA_Systems",providerFacility)
  s:##class(Ens.Util.FunctionSet).Lookup("CernerSites",providerFacility)>0 provprocessingFlag="Cerner"
  s:$g(VistABO1)="" badResponse.FailureReason="Provider Site is not configured in HealthConnect"
 }
 
 
 if badResponse.FailureReason'="" 
 
    set tSC=..SendRequestSync("ProcessBadApptRequest",.badResponse,.pResponse) Quit:$$$ISERR(tSC)
 }
 
 else
 {
 
 if pFlag=0
 {
  tSC1 = ..SendRequestSync("ProcessVistAAppointments",.pRequestBody,.pResponse)
 }
 
 if pFlag=1
 {
  tSC1 = ..SendRequestSync("ProcessCernerAndVistAAppointments",.pRequestBody,.pResponse)
 }
 if pFlag=2
 {
  tSC1 = ..SendRequestSync("ProcessCernerOnlyAppointments",.pRequestBody,.pResponse)
 }  }  
 Quit tSC1
}

Class TMP.AppointmentReqMsg Extends Ens.Request
{ // ProcessingFlag property is used to determine if the appt is for Cerner, Cerner and VistA or just VistA. // This flag is used by the BP Property ProcessingFlag As %String; Property MessageId As %String; Property ControlId As %String; Property LogicAppRunId As %String(MAXLEN = 150); Property AppointmentID As %String(MAXLEN = 150); Property AppointmentType As %String; Property StartTime As %String; Property Duration As %String; Property VisitStatus As %String; Property CancelCode As %String; Property CancelReason As %String; Property CancelRemarks As %String(MAXLEN = 160); Property ClinicallyIndicatedDate As %String; Property Comments As %String(MAXLEN = 160); Property VvdUrl As %String(MAXLEN = 500); Property SchedulerInfo As array Of SchedulerInfo; Property PatientInfo As TMP.PatientInfo; Property ProviderFacility As %String; Property PatientFacility As %String; // Property PatientResources As list Of AppointmentResources; Property PatientResources As TMP.AppointmentResources; Property ProviderResources As TMP.AppointmentResources;

Thank you ,

I have tried the steps mentioned in the below post but i am not sure what values i need to use in few variables

https://community.intersystems.com/post/parse-hl7-content-json-request-e...

This is example mentioned in the link

SET tContent = %request.Content.Read()---->in %request do we need to declare any variable

WHILE '%request.Content.AtEnd {

SET tContent = tContent + %request.Content.Read()

}

SET tReq = {}.%FromJSON(tContent)

SET tInput = tReq.Message

// Remove your %New() statement and set tMsg like this

SET tMsg = ##class(EnsLib.HL7.Message).ImportFromString(tInput)

// Then you can either set the doctype manually or use PokeDocType()

Let me know  if you have any ideas on this one?

Joe,

I created a HL7 production, added JSON Passthrough File Service. Use BPL and DTL to transform Ens.StreamContainer to HL7 Message. Code is here:

https://github.com/oliverwilms/HL7

Input test file I use this (no double double quotes):

{"Doctype":"ADT^A01","PatientId":"123","PatientName":"Alex"}

I see PatientId in HL7 message, but not PatientName. Need to review the DTL ...

I'm not sure whether this will work in Ensemble 2018.1, but it does seem to work fine in IRIS for Health Interoperability 2022.2.

I'm testing with a simple JSON file that looks like this:

{
    "mrn": 12345678,
    "name": "Johann Smythe",
    "firstname": "Johann",
    "lastname": "Smythe",
    "dob": "1989-03-21 14:20:00",
    "phone": "(555) 555-4917",
    "mobile": "(555) 555-6401",
    "email": "johann@smythe.com",
    "address": "123 Anystreet St",
    "city": "Anytown",
    "state": "ME",
    "zip": "04121"
}

I've used the File Passthrough Service (EnsLib.File.PassthroughService) to read the JSON document into a stream, message class Ens.StreamContainer. Because this isn't an HL7 object, my router is based on the "General Message Routing Rule" rule type, and my constraint consists of the source service name with a message class of Ens.StreamContainer.

In the DTL called by the send action, I use Ens.StreamContainer as the source message type. The target message type is EnsLib.HL7.Message with whatever Document Category and Type is needed.

The first rule in the DTL is this:

After setting a number of default values for the target HL7 message (Event Type/Trigger, Date/Time of message, etc.) I populate the PID fields as follows:

And I now have an HL7 message created from JSON.

This isn't going to work with a batch of patient records in a JSON array; you'd need to create a BPL to process that. But for input that consists of a simple structure like the example I used, you can accomplish what you need without building a custom service or creating a BPL.