Do these files require any transformation or are they just being copied/moved to the target filesystem? Do they need to be removed from the sftp server once transferred?

Ensemble's stock file transfer business service classes don't persist the directory recursed into as a property of the message object, so COS coding and a custom business service would be required, and likely a custom adapter as well. Assuming the complete file path is populated in the message's Source property, a custom File business operation would be needed to create the target path and file using the same name as the source.

The free WinSCP utility has a scripting interface that will perform a recursive transfer and deletion and could be scheduled to run under the Windows scheduler; if the intent is to simply move the files without transformation, this would likely be much faster to implement.

I just tested this using the standard HL7 File Service and was able to use multiple wildcards to select files. In my testing I used a File Spec of *Test*.hl7 and the service picked up both RadTest01.hl7 and LabTest01.hl7. I also tried a File Spec of LabTest*.hl7;RadTest*.hl7 with the same net result.

The file adapters all use the same core methods for searching the specified directory path, so it should work unless you're using a custom service/adapter.

What version of Ensemble/HSConnect are you using?

You'll find the Message Structure as the value after the colon in the message body's DocType property. The Name property is used to look up the associated message structure in the schema (the portion before the colon in the DocType property).

HICG > set msg=##class(EnsLib.HL7.Message).%OpenId(26872)

HICG > w msg.DocType

2.3.1:ADT_A01

HICG > w msg.Name

ADT_A04

The DocType is not automatically set by the ImportFromFile() method. You would need to set it to whatever DocType (i.e. DocTypeCategory:DocTypeName) is required to properly parse the message.

In a Production, the Business Service that receives messages uses the value in the Message Schema Category field to set the DocType for subsequent processing, and if both a DocTypeCategory and DocTypeName are present it will override the automatic selection of the DiocTypeName determined by the HL7 message's MSH:9 value.

If the message you wish to test is saved in a separate file outside of Ensemble, you can create a new message object with the following:

JEFF > set tMsg=##class(EnsLib.HL7.Message).ImportFromFile("/path/to/file/filename.ext")

You'll need to set the DocType manually; for messages already received by Ensemble, that was likely taken care of by the business service:

JEFF > set tMsg.DocType="2.3.1:ORU_R01"

Something to keep in mind is that methods expecting a message class as an argument (ex. EnsLib.HL7.Message) work on message objects rather than strings. The tMsg variable created by both the %OpenId() and ImportFromFile() methods are such objects. These objects have a rich set of methods for inspecting, transforming and otherwise working with messages.

The easiest way is to use an existing message that's already in the Ensemble message store. Locate the MessageBodyId value in the header tab of the message viewer, and execute the following commands in the same namespace as the production:

JEFF > Set tMsg = ##class(EnsLib.HL7.Message).%OpenId(BodyID)

JEFF > Write ##class(Package.Name).MethodName(tMsg,"Identifier") 

Substitute the numeric Message Body ID for BodyID, the package name for your class for Package.Name, the method for MethodName and the identifier you want to test with for Identifier. The method you mentioned appears to return a string, so you should see the value displayed once you press enter on the 2nd command.

If you don't want to modify the existing class, write a new one that extends it:

/// Custom functions for this installation
Class User.Rule.MyFunctionSet Extends Ens.Rule.FunctionSet
{

/// Stupid, redundant method provided as an example
/// Accepts a string <var>pString</var> and regular expression pattern <var>pPattern</var>
/// as arguments; returns 0 for no match, and a positive integer indicating the match's
/// position if there is a match.
ClassMethod REMatch(pString As %String, pPattern As %String) As %Integer
{
    Return $LOCATE(pString,pPattern)
}

}

As long as you don't define a method that overrides a previous method, you're completely safe.

EDIT: Eduard's example beat me to it and does exactly the same thing. The point, though, is that you're not adding methods to the existing class, you're creating new methods outside of it that are accessible from within your rule definitions.

The conventional mechanism for generating multiple outbound messages from a single inbound is via a BPL. It can also be done in a custom BP using ObjectScript, and I've also seen it done using the rule editor (but wouldn't recommend it ... it's not exactly intuitive).

In a BPL, you'd assign a context variable to the list of values extracted from ZCO:2 (using $LISTFROMSTRING()), then iterate over the list with an <until> action. You'll also need to create some other context variables for list length, iteration and element selection.

Inside the <until> you would:

  1. Increment the iterator and obtain the current list value using <assign> actions
  2. Invoke a DTL with a <transform> action that copies the relevant fields/segments from the source message to the target
  3. In the same DTL, use the current list iteration value to populate FT1:7.1
  4. Send the resulting message to the downstream Business Operation with a <call> action

You'll need to override the OnGetConnections method by inserting the snippet below in your custom business process(es):

ClassMethod OnGetConnections(Output pArray As %String, pItem As Ens.Config.Item)
  {
                Do ##super(.pArray,pItem)
                If pItem.GetModifiedSetting("TargetConfigName",.tValue) {
                                For i=1:1:$L(tValue,",") { Set tOne=$ZStrip($P(tValue,",",i),"<>W")  Continue:""=tOne  Set pArray(tOne)="" }
                }
  }