Julian Matthews · Sep 6, 2019 go to post

Doesn't answer your question, but I use Winmerge with some tweaks to the settings to make the highlighting a little nicer:

http://forums.winmerge.org/viewtopic.php?f=4&t=1040

If I need to compare 1000s of messages from two sets of transforms, I then point their outbound to a single fileout (or since I upgraded to 2019.1, using the export) and then compare the two files.

Julian Matthews · Aug 29, 2019 go to post

Just to add to this - in a real world situation, you would be accessing the terminal from the cube menu as described by Robert. I think this is something created by Intersystems to facilitate the online learning.

Julian Matthews · Aug 29, 2019 go to post

Hi Marta.

I just took a look at the course to see what was what, and on the lab site generated, there is a link for the terminal on the home page:

This then prompts you to log in with the credentials provided when you first created the lab session, and you end up with an oversized terminal window the size of your browser smiley

Julian Matthews · Aug 28, 2019 go to post

It might be unrelated, but I recently had a similar issue when installing healthconnect on a windows 10 machine with Kaspersky Endpoint Security.

Kaspersky was being triggered by some temp files created by the installer, and placing them in quarantine. This was then leaving the installer showing it had completed, but with the progress bar still showing. I never did leave it for as long as you did to then get the error you didn't save.

The weird thing was that Kaspersky only reported a virus with the installer on specific versions of Windows 10.

I ended up submitting the installer to Kaspersky so that they could white list it. 

Long story short, check the reports section within Kaspersky and see if it interfered with your install. smiley

Julian Matthews · Aug 21, 2019 go to post

I did consider going the oldschool route, but your guidance above worked perfectly for me smiley

Julian Matthews · Aug 21, 2019 go to post

This looks really good!

Any idea how I'd be able to use this in a non-docker environment?

Julian Matthews · Aug 19, 2019 go to post

Hi David.

I raised this with WRC following my recent upgrade to IRIS, and the reason given was that the auto-refresh interferes with a new feature that logs out inactive users.

What you need to do (in a Terminal session) is set a global as follows:

>set ^%SYS("Portal","EnableAutoRefresh")=1

Julian Matthews · Aug 8, 2019 go to post

I have a task that deletes txt files  older than x number of days:

 Class PROD.Schedule.PurgeTxtFiles Extends %SYS.Task.Definition
{

Parameter TaskName = "Purge TXT Files";

Property Directory As %String;

Property Daystokeep As %Integer(VALUELIST = ",5,10,15,20,25,30,35,40,45,50,55,60") [ InitialExpression = "30" ];

Method OnTask() As %Status
{

Set tsc = ..PurgeSentFolder(..Directory,..Daystokeep,"txt")
Quit tsc
}

Method PurgeSentFolder(Directory As %String, DaysToKeep As %Integer, Extention As %String) As %Status
{
// Calculate the oldest date to keep files on or after
set BeforeThisDate = $zdt($h-DaysToKeep_",0",3)

// Gather the list of files in the specified directory
set rs=##class(%ResultSet).%New("%File:FileSet")
Set ext = "*."_Extention
do rs.Execute(Directory,ext,"DateModified")

// Step through the files in DateModified order
while rs.Next() {
set DateModified=rs.Get("DateModified")
if BeforeThisDate]DateModified {
// Delete the file
set Name=rs.Get("Name")
do ##class(%File).Delete(Name)
}
// Stop when we get to files with last modified dates on or after our delete date
if DateModified]BeforeThisDate 
set tSC = 1
}
quit tSC
}

}

Hopefully you can make this work for your needs smiley

Julian Matthews · Aug 1, 2019 go to post

Personally, I would use a DTL which removes the EVN, and then I would call the DTL class from objectscript:

Set tSC=$CLASSMETHOD("DEV.Transformations.DUMMY.A01toA01","Transform",request,.messageWithoutEVN)

So, "Transform" in quotes is the action, request is your original Enslib.HL7.Message coming in, and .messageWithoutEVN is the output from your DTL.

Does that help?

Julian Matthews · Jul 31, 2019 go to post

The method RemoveSegmentAt returns a status, not the message with the segment removed.

So your HL7 message with the EVN removed is still "newreq" and it is this that you want to pass on.

Julian Matthews · Jul 9, 2019 go to post

Assuming you're talking about the online backup function within ensemble/HS/etc - I use a task that will run a purge based on the age of the file, and then runs the backup. The order of the two methods is important if you set your retention period to 0, as you'll end up deleting the backup you just made (I'm neither confirming or denying if this happened to me).

Class Live.Schedule.BackupPurge Extends %SYS.Task.BackupAllDatabases{

Parameter TaskName = "Backup With Purge";

Property Daystokeep As %Integer(VALUELIST = ",0,1,2,3,4,5") [ InitialExpression = "1" ];

Method OnTask() As %Status{
    //Call PurgeBackup Method, Return Status
    Set tsc = ..PurgeBackups(..Device,..Daystokeep)
    Set tsc = ..RunBackup()
    Quit tsc
}

Method PurgeBackups(Directory As %String, DaysToKeep As %Integer) As %Status{
    // Calculate the oldest date to keep files on or after
    set BeforeThisDate = $zdt($h-DaysToKeep_",0",3)

    // Gather the list of files in the specified directory
    set rs=##class(%ResultSet).%New("%File:FileSet")
    do rs.Execute(Directory,"*.cbk","DateModified")

    // Step through the files in DateModified order
    while rs.Next() {
        set DateModified=rs.Get("DateModified")
        if BeforeThisDate]DateModified {
            // Delete the file
            set Name=rs.Get("Name")
            do ##class(%File).Delete(Name)
        }
        // Stop when we get to files with last modified dates on or after our delete date
        if DateModified]BeforeThisDate 
        set tSC = 1
    }
    quit tSC
}

Method RunBackup() As %Status{
    d $zu(5,"%SYS")
    Set jobbackup = 0
    Set quietflag = 1
    Set Device = ..Device
    Set tSC = ##class(Backup.General).StartTask("FullAllDatabases", jobbackup, quietflag, Device, "0")
    Quit tSC
 }

}

The downside to this is you will end up with an extra backup file in your backup location if you run the backup manually as the purge is based on the file age. Not a massive problem unless you're storing in a location with a finite amount of disk space.

Julian Matthews · Jul 9, 2019 go to post

After working with WRC, I now have an answer.

If the DataSet property points to the MutabaleDateSet property then GetValueAt will return a stream if more than 32k.

If (as in my situation) the DataSet property points to the FixedDateSet property then GetValueAt will return a string of 32648.

The workaround provided by WRC did the trick for me:

Try {
    Set setStatus = $$$OK, getStatus = $$$OK
    If 'pInput.Modified{
        Set setStatus = pInput.SetValueAt(pInput.GetValueAt("DataSet.DocumentTitle",,.getStatus),"DataSet.DocumentTitle")
        }
    }
    Catch e {
        Set setStatus = e.AsStatus()
}
If setStatus && getStatus{
    Set X = pInput.GetValueAt("DataSet.EncapsulatedDocument",,.tSC)
}

However there was an alternative of using the CreateFromDataSetFileStream method of the class EnsLib.DICOM.Document:

set tSC = ##class(EnsLib.DICOM.Document).CreateFromDataSetFileStream(pInput.DataSet.FileStream,pInput.DataSet.TransferSyntax,.dicomDocFromStream)

If tSC Set X = dicomDocFromStream.GetValueAt("DataSet.EncapsulatedDocument",,.tSC)

In both of these options, the next step is to then check tSC to see if X is a stream or string and then work from there.

Julian Matthews · Jul 2, 2019 go to post

That's odd - when I am using GetValueAt("DataSet.(0042,0011)"), it is returning a string and not a stream object.

I have an open ticket with WRC to see what's going on. I'm 99% sure this is user error, but we'll see.

Julian Matthews · Jun 19, 2019 go to post

I took a look at the error and it doesn't seem to be truncating at the linebreaks (which are represented as \.br\). 

I think your suggestion of a custom operation is going to be my best approach. Fingers crossed!

Julian Matthews · Jun 6, 2019 go to post

Just as a note - I naively followed that link and got a warning from the WRC portal that I was attempting to access data that my organisation should not have access to, and that repeated attempts to access the link may suspend my WRC account.

Whoops smiley

Julian Matthews · Jun 4, 2019 go to post

I'm not too sure if that would be the case, but it's something worth trying out to see how the system reacts.

Julian Matthews · Jun 3, 2019 go to post

Hi Cedric.

I think you should be able to achieve this using the routing rules by doing something like this: (Please ignore my blank condition in the example)

It should complete the first send (which is your transform to A04) and then it should send your source ORM message on the second send.

Julian Matthews · May 31, 2019 go to post

Hi Murillo.

From that screenshot - an ORU_R01 should go to ManageRIS every time, and go to ManageEDM as well if the OrderStatus is 160, so I'm at a loss as to why it isn't working as intended.

My next steps would be checking the general tab to be sure the rule type is set to "HL7 Message Routing Rule" or, if that fails, creating a new rule to make sure nothing has gone weird in the background for this specific rule.

Otherwise - if no one else is able to point you in the right direction here it might be worth raising with WRC as it could be a weird bug with the version of Ensemble.

Julian Matthews · May 31, 2019 go to post

Hi Murillo.

You will need a when to specify when the action should be triggered, and using WHEN 1 is the easiest way of achieving what you need, however I think I see your problem with the ordering.

The reason why your rule only sends to ManageRIS when the ManageRIS item is above the OrderStatus check is because of the RETURN action.

What the RETURN does is stop any actions beyond that point from being processed if the conditions of the WHEN are met. So in your case: When Orderstatus =160, transform and send, and then do not process anything else and move on to the next message.

So what you will want to do is remove the RETURN block to allow the second WHEN in rule two to be run regardless of the outcome of the first WHEN.

Julian Matthews · May 3, 2019 go to post

You might have some luck using wireshark to see if there's anything that stands out in the communication between Ensemble and the remote system?

Julian Matthews · May 2, 2019 go to post

Within the Production under Production Settings, you should currently find a Document button which will produce a report of everything within your production. However, depending on the production size, this could easily be overkill.

2019 brings a new option called "Interface Maps" where you can get a graphical view of message flows, along with the processes, routers, and rules for the individual sections of your production. It's a lot cleaner than using the Documentation generator, but if you're needing to show multiple routes, you're likely to want to go through each one and take a screenshot. I also found that where I have a router with lots of rules/transforms, I need to scroll the screen to see the bottom of the display.

Information on this can be found here.

Julian Matthews · May 1, 2019 go to post

I haven't come across anything built in as standard that would do this in itself, but I guess it's something you could create within your environment.

I have something a bit similar, but the index is populated by a CSV received daily from another organisation, and then the process compares the HL7 messages against the index and sends if the patient is present in that table before sending.

Julian Matthews · Apr 23, 2019 go to post

I had this exact issue last week, and this is how I got around it. For clarity, I wanted to pass the Dynamic Object from a process to an operation.

I created my dynamic object within the Process, and then used the %ToJSON Method to put the JSON within a GlobalBinaryStream (which can be passed through the request).

In the Operation, I then use the %FromJSON Method of DynamicAbstractObject to then have the Dynamic Object within the operation.