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 } }
go to post Jeffrey Drumm · Apr 1, 2022 Remove the field repetition value from the field number and you will get the desired result, i.e. "3().1" rather than "3(2).1" when using GetFieldNameFromNumber().
go to post Jeffrey Drumm · Mar 31, 2022 It should be pointed out that the RawContent property is not guaranteed to supply the entire message, as described here. Better to use the OutputToLibraryStream() method.
go to post Jeffrey Drumm · Mar 30, 2022 If you're trying to get the 4 digit year from an HL7-formatted time string (YYYYmmddHHMM), your method should look like this (using GetYear rather than DateTime as method name for clarity): ClassMethod GetYear(pDate As %String) As %String { If ($LENGTH(pDate) > 4) { Return $EXTRACT(pDate,1,4) } Return "" } } You would then call that class as follows: Set Year = ##class(CUSTSOM.Training.Functions).GetYear(source.GetValueAt("PIDgrpgrp(1).PIDgrp.PID:7.1")) The variable Year should then contain the 4 digit year, or the empty string if the value in PID:7.1 is 4 characters or less.
go to post Jeffrey Drumm · Mar 22, 2022 No, I don't think that's the issue. My suspicion is that somewhere in your BPL you're cloning a message body and then not sending it anywhere, meaning that it never gets "attached" to a message header record. The records in Ens.MessageHeader are queried for the message body IDs to delete in the purge process, so if there's no header record with that message's ID as its MessageBodyID, it's by definition an orphaned message and does not get purged. The source message is of course referenced by a header record, but a cloned message body doesn't get a header until you pass it to another process or operation.
go to post Jeffrey Drumm · Mar 21, 2022 If a message fails to match any rules in a routing rule, it gets marked as "Completed." It still went somewhere; its final destination was the Business Process running the routing rule
go to post Jeffrey Drumm · Mar 19, 2022 If you need to both route and take other actions based on data extracted in an HL7 message flow, you'll be better off doing it using a Business Process/BPL than a routing rule.
go to post Jeffrey Drumm · Mar 19, 2022 Hi Scott, You can get a list of message body IDs (and their associated event types) that have no corresponding header record with this query: SELECT HL7.ID, HL7.Name FROM EnsLib_HL7.Message HL7 LEFT JOIN Ens.MessageHeader hdr ON HL7.Id=hdr.MessageBodyId WHERE hdr.MessageBodyId IS NULL AND HL7.OriginalDocId IS NULL And yes, this query can take a very long time to run ... long enough that it will usually time out in the Management Console SQL UI. It shouldn't time out if you run it from the Caché (or IRIS) SQL Shell though. What would you want to use for WHERE or ORDER BY criteria? The list of "fields" (properties) available to reference directly via SQL can be viewed in the Body panel of an HL7 message displayed in the Message Viewer, but their usefulness in determining what made them orphans is limited. The problem with orphans is that knowing "where they came from" is a bit challenging. The source and destination services/processes/operations in the Production are stored in the message header table and not the body table; the reason the messages are orphans is because they're no longer linked (by MessageBodyId) to any records in the Message Header table. The most common reason for orphans is the configuration of the message purge task. There's a "bodies too" checkbox that, if left unchecked, will prevent message bodies from being deleted. The headers still get deleted, though, and that makes the bodies "orphans."
go to post Jeffrey Drumm · Mar 7, 2022 This looks like a job for a regular record map with a batch class rather than a complex record map ...
go to post Jeffrey Drumm · Mar 2, 2022 Are you using the private key you created at the time you generated the CSR, or one provided by your server folks? You need to use the one you generated. And I'm assuming your private key is encrypted, and therefore has the following header in the file: -----BEGIN ENCRYPTED PRIVATE KEY----- Have you tried decrypting it with openssl? openssl rsa -in /etc/pki/tls/private/ssl_vd01.key -text You should be prompted for a passphrase; use the one you provided when you generated the CSR. If it decrypts OK, you'll get something similar to this: RSA Private-Key: (2048 bit, 2 primes) modulus: 00:98:42:c5:37:28:e4:b9:69:e4:a0:45:86:b1:20: 39:5f:78:36:96:14:f8:e9:4f:49:7d:44:31:16:3c: <remainder elided> If you don't get something like this, the passphrase is wrong for the key file. If you do, verify that you've provided the proper passphrase in both the %SuperServer SSL configuration and the Web Gateway Server Access configuration. You'll also need to provide the passphrase when starting httpd, which may not be obvious if SELinux is blocking it; running the following command will allow the prompting for a password when starting/restarting httpd: setsebool -P httpd_read_user_content 1
go to post Jeffrey Drumm · Mar 1, 2022 I ran into this issue with a customer within the last few days. The customer provided me with a GoDaddy-supplied certificate (in PEM/x509 format) and a private key file. Unfortunately the private key wasn't anything recognizable by openssl (it definitely wasn't an RSA key at least), and it did not appear to be encrypted. The resolution was to regenerate an RSA private key and CSR ourselves with openssl, then submit the CSR to GoDaddy for generation of the certificate. The RSA key and the cert from GoDaddy were supplied as the certificate and private key for both the %SuperServer SSL configuration and the cert/private key in the Web Gateway server configuration.