go to post Jeffrey Drumm · Jun 23, 2022 I see that the extension documentation discusses the issue I mentioned in my previous comment. So it looks like this may not work with a standalone web gateway server that hosts multiple instances using the conventional implementation method (instance prefixes). I'd love to solve this issue, but it's a bit outside of my wheelhouse.
go to post Jeffrey Drumm · Jun 23, 2022 I wanted to try it, but it appears the bug/incompatibility with instance prefixes is still on the issues list (at least for the main branch of WebTerminal). Does this extension include a fix/workaround for that?
go to post Jeffrey Drumm · Jun 21, 2022 HL7 Message bodies are also referenced from the IO Log tables (ACKs/NAKs). Technically, their headers exist, but not in Ens.MessageHeader ;)
go to post Jeffrey Drumm · Jun 8, 2022 Thanks, @Jolyon Smith, that does give me something to go on. This is the error I'm seeing on each connection attempt: Error: unable to verify the first certificate at TLSSocket.onConnectSecure (node:_tls_wrap:1530:34) at TLSSocket.emit (node:events:390:28) at TLSSocket._finishInit (node:_tls_wrap:944:8) at TLSWrap.ssl.onhandshakedone (node:_tls_wrap:725:12) The cert shows no issues when using Chrome, but what I've read in researching this error is that AV software may be a contributor. Unfortunately, I don't have the ability to turn it off on the system I'm testing with, so I'll need to work with the customer's PC support team to see if that makes a difference. I've already tried setting http.proxyStrictSSL and http.systemCertificates to false, and set http.proxySupport to off.
go to post Jeffrey Drumm · Jun 6, 2022 Yes, in retrospect I should have realized that the DocType Structure was what the constraint required rather than the calculated value in the Name property. Sorry for any head-scratching I might have caused
go to post Jeffrey Drumm · Jun 6, 2022 You shouldn't need to ... DEV>Set msg = ##class(EnsLib.HL7.Message).%OpenId(29485840) DEV>Write msg.Name ADT_A11 DEV>Write msg.GetValueAt("MSH:9") ADT^A11 DEV>Do msg.SetValueAt("A08","MSH:9.2") DEV>Write msg.GetValueAt("MSH:9") ADT^A08 DEV>Write msg.Name ADT_A08 But I guess it wouldn't hurt Is it possible that there's an action somewhere in the DTL that clears MSH:9?
go to post Jeffrey Drumm · Jun 6, 2022 The Name property in a message object is actually calculated from the contents of MSH:9 and is what the constraint editor evaluates. Is MSH:9 in the target message being set using some unconventional method in the Target message? EDIT: The constraint editor uses the DocTypeName, not the Name property, as Scott points out in followup comments.
go to post Jeffrey Drumm · Jun 6, 2022 If you're using New as the Create selection in the Transform tab, the target message should be set to the Target Doc Type specified in that same tab. If you're using Copy or Existing, the Target's Doc Type will be the same as the Source's. Are you seeing instances where the Doc Type is not set at all, or is it set to the wrong Doc Type?
go to post Jeffrey Drumm · Jun 2, 2022 There are a number of examples at Defining and Using Stored Procedures | Using InterSystems SQL | InterSystems IRIS Data Platform 2021.2. The SP I wrote for fetching the message body using its object ID probably won't be much help, since it doesn't actually execute an SQL query ... it's just an ObjectScript classmethod that returns a string, and it's called for every row returned in the containing query. It's available at https://hl7spy.ca/downloads/HICG_HL7.xml if you want to look at it.
go to post Jeffrey Drumm · Jun 1, 2022 I've written a query for HL7Spy's SQL Loader that extracts ACKs/NAKs from the IOLog: Here's the SQL in text form. The method HICG.GetMsg() is an ObjectScript stored procedure written specifically for HL7Spy that returns the message body as a stream for delivery via ODBC. You could adapt the SQL for use with the %SQL.Statement class to return a result set containing the message body IDs, Next() your way through that, open each message with %OpenId() and write it out to a file. Getting just the NAKs will require a bit of message parsing. SELECT head.ConfigName As ConfigName, body.DocType As DocumentType, body.Name As BodyName, HICG.GetMsg(body.ID) As Message FROM Ens_Util.IOLogObj head INNER JOIN EnsLib_HL7.Message body ON head.InObjectId = body.%ID WHERE -- specify start and end time for search here head.ID >= (SELECT TOP 1 ID FROM Ens_Util.IOLogObj WHERE TimeReceived >='2022-06-01 00:00:00.000' ORDER BY TimeReceived ASC) AND head.ID <= (SELECT TOP 1 ID FROM Ens_Util.IOLogObj WHERE TimeReceived <='2022-06-02 00:00:00.000' ORDER BY TimeReceived DESC) AND head.IsInbound = 0 AND head.InObjectClass = 'EnsLib.HL7.Message' AND head.ConfigName = 'To_Outbound_Operation' -- substitute operation name here
go to post Jeffrey Drumm · Apr 29, 2022 Assuming you cut and pasted from your DTL, the double-quote characters around the 2nd dash are incorrect. They appear to be the distinct open and close quote characters that Word automatically substitutes for the "standard" double-quote character: set tSSN source.{PID:SSNNumberPatient} set target.{PID:SSNNumberPatient} $E(tSSN,1,3)_"-"_$E(tSSN,4,5)_”-“_$E(tSSN,6,9)
go to post Jeffrey Drumm · Apr 29, 2022 Or you could use $E()! To @John Klahn, My reason for suggesting the classmethod is that this type of thing is something that's done somewhat frequently, so having a reusable method can be a timesaver. Alas, it does take a bit of investment in time to learn ObjectScript and Studio, but it can be very beneficial to your productivity even though you spend most of your time working on integrations through the management console.
go to post Jeffrey Drumm · Apr 28, 2022 If you create the following class in IRIS Studio, a "FormatSSN()" function will be available in the DTL editor's expression editor, and you can use it in your set rules: Class Misc.Util.StringFunction Extends Ens.Rule.FunctionSet { ClassMethod FormatSSN(pStr As %String) As %String { Set tStr = $ZSTRIP(pStr,"*AWP") Return $E(tStr,1,3)_"-"_$E(tStr,4,5)_"-"_$E(tStr,6,9) } } The method strips all non-numeric characters from the value passed to it, then formats it per the SSN format. It doesn't verify that the proper number of digits are present, but that's something that can be easily added. In a DTL action, it would look like this:
go to post Jeffrey Drumm · Apr 27, 2022 <assign value='$PIECE($ZCVT(source.{ibex_medical_chart.patient_info.admdoc.name},"i","XML"),",",1)' property='target.{PV1:AdmittingDoctor(1).FamilyName}' action='set' /> <assign value='$PIECE($ZCVT(source.{ibex_medical_chart.patient_info.admdoc.name},"i","XML"),",",2)' property='target.{PV1:AdmittingDoctor(1).GivenName}' action='set' /> Or a bit more efficiently: <assign value='$ZCVT(source.{ibex_medical_chart.patient_info.admdoc.name},"i","XML")' property='tFullName' action='set' /> <assign value='$PIECE(tFullName,",",1)' property='target.{PV1:AdmittingDoctor(1).FamilyName}' action='set' /> <assign value='$PIECE(tFullName,",",2)' property='target.{PV1:AdmittingDoctor(1).GivenName}' action='set' /> Note that this isn't actually replacing the comma character so much as it's splitting the full name value supplied in the source path on that character and assigning the individually extracted values to their associated HL7 components in the Admitting Doctor field.
go to post Jeffrey Drumm · Apr 27, 2022 Assuming Caché Terminal is working, you should be able to access these settings via the ^SECURITY menu. Sign on via Terminal with an administrative account (SuperUser, cacheusr, _SYSTEM) using the password you provided during installation. Change to the %SYS namespace using the command zn "%SYS" Issue the command do ^SECURITY at the %SYS> prompt. Choose System Parameter Setup Choose Edit system options Press Enter until "SSLServer connect type" displays with 3 options Choose 1 to disable SSL (the current setting may be displayed near the end of the prompt) Press Enter to step through the remaining prompts, and confirm changes to the security parameters. Exit from the menu, and type h followed by Enter to exit the session.
go to post Jeffrey Drumm · Apr 27, 2022 I noticed that the original title of this post was "Can I run Caché using SSL?," so I'm wondering if you have SSL/TLS set as Required in System-wide Security Parameters in the Management Console, or even Enabled with an incorrectly configured CSP Gateway ...?
go to post Jeffrey Drumm · Apr 27, 2022 The "file" is a bag of bytes embedded in the received email message, and represented in the %Net.MailMessagePart as a stream object (based on your example, Part.BinaryData for a binary attachment). It's up to you to take that stream object and save it as a file somewhere, which is shown by the suggested CopyFrom method and "/path/to" string in its argument in my response above.
go to post Jeffrey Drumm · Apr 26, 2022 Depends on how the attachment is stored by the sender. If it's a binary attachment, the file data will be represented as a stream object in Part.BinaryData. If it's text data, Part.TextData. You just need to create a %Stream object and copy Part.BinaryData (or Part.TextData) to it: Set stream=##class(%Stream.FileBinary).%New() Set sc=stream.LinkToFile("/path/to/"_Part.FileName) Do stream.CopyFrom(Part.BinaryData) Do stream.Flush() // may not be necessary Do stream.%Save() // ditto, but better safe than sorry ya know? You can determine the type of data in the Part via the IsBinary boolean property ...
go to post Jeffrey Drumm · Apr 4, 2022 I certainly will, Ana. I've unfortunately been conditioned by most other websites that the "Feedback" button is roughly as useful as the "Close Door" button on an elevator. I should have known better!
go to post Jeffrey Drumm · Apr 1, 2022 You would only need to remove the repetition value from the argument passed to GetFieldNameFromNumber(); you would still continue to pass the full field index to GetValueAt(). Something like this: set segment = msg.getSegmentByIndex(3) Set fieldIndex = "3(2).1" Set fieldNameIndex = ##class(User.Util.StringFunctions).ChangePattern(fieldIndex,"(\d)","()") set fieldName = ##class(EnsLib.HL7.Schema).GetFieldNameFromNumber("2.5", segment.Name, fieldNameIndex) set fieldValue = segment.GetValueAt(fieldIndex) The ChangePattern method: Class User.Util.StringFunctions Extends Ens.Util.FunctionSet { ClassMethod ChangePattern(pStr As %String, pPat As %String, pRep As %String) As %String { Set tOut = pStr Do { Set tLoc = $LOCATE(tOut,pPat,,,tFnd) Set:$DATA(tFnd) tOut = $REPLACE(tOut,tFnd,pRep) } While tLoc '= 0 Return tOut } }