Here is a custom function that you may call from rules or transformations that will return the age in your choice of years, months, days.

Note that this is a complete export.

<?xml version="1.0" encoding="UTF-8"?>
<Export generator="Cache" version="25" zv="Cache for Windows (x86-64) 2017.2.1 (Build 801U)" ts="2020-03-16 16:31:49">
<Class name="Custom.GetAge">
Calculates and returns the age from the birthday passed in %Y%m%d format comparing to current date or passed in date.
ReturnUnits is "Y" (Default) for Years, "m" for Months, or "d" for Days
currentday in HL7 format, defaults to today if blank  </Description>

<UDLText name="T">
// ClassMethod GetAge(birthday As %String, ReturnUnits As %String, currentday As %String) As %String [ Final ]


<Method name="GetAge">
returns the current age in years with birtday passed in %Y%m%d format</Description>

    // convert date times into correct format
    set Tbirthformat = ##class(Ens.Util.Time).ConvertDateTime(birthday,"%Y%m%d","%q(3)" )
    if currentday '= ""
       set Tcurrentformat = ##class(Ens.Util.Time).ConvertDateTime(currentday,"%Y%m%d","%q(3)")
    {   set Tcurrentformat = $h
    set bmonth = $SYSTEM.SQL.DATEPART("mm",Tbirthformat)       
    set cmonth = $system.SQL.DATEPART("mm",Tcurrentformat)
    set bday = $system.SQL.DATEPART("dd",Tbirthformat)
    set cday = $system.SQL.DATEPART("dd",Tcurrentformat)
    set tretval = 0
    if (ReturnUnits = "Y") || (ReturnUnits = "y") || (ReturnUnits = "")
      // calculate the difference in years by subtracting the birthday from the currentday
      set difftimeYear = $SYSTEM.SQL.DATEDIFF("yy",Tbirthformat,Tcurrentformat) // get the years

      if bmonth = cmonth   //check day since the month is the same
         if cday < bday
           set difftimeYear = difftimeYear - 1
      {  if cmonth < bmonth
           set difftimeYear = difftimeYear - 1
      // return the age in years
      set tretval = difftimeYear
    { if (ReturnUnits = "M") || (ReturnUnits = "m")
          set difftimeMonth = $SYSTEM.SQL.DATEDIFF("mm",Tbirthformat,Tcurrentformat)  // get the months
          if bmonth = cmonth
          { if cday < bday
            {  set difftimeMonth = difftimeMonth - 1
           // return the age in months
           set tretval = difftimeMonth
      {  if (ReturnUnits = "D") || (ReturnUnits = "d")
         { set difftimeDay = $SYSTEM.SQL.DATEDIFF("dd",Tbirthformat,Tcurrentformat)  // get the days
           // return the age in days
           set tretval = difftimeDay
    quit tretval

How are you bringing the messages in?   I assume through an HL7 service.    The MessageSchemaCategory must be set correctly in the service and the DocType will get set correctly.

If parsed correctly according to the schema then the message will show as Blue in the contents tab of the the message viewer,  if any segments do not match the schema then the message will show as Black at the point of mismatch.   You need to get the message to show as all Blue or the paths (word or numerical) cannot be followed.

Your screenshots showed using the testing facility for the rules and you are using "User Input".   If you scroll down in the form you will find a field to enter the DocType manually.   This field needs to have the syntax I showed above with the schemaname:ORU_R01 in your case.

The DocType is not set in the message header.  

It should look more like the following:  Note that the example below is a custom schema ORUPDF.

Without this set the word paths cannot be used to retrieve the values because these depend on referencing the schema named in the DocType.  

This DocType is assigned within the service normally.

I believe you could also change all the paths to be numerical and it may work:  such as MSH:9.2

It is cleaner to send from the service to a BPL  process that does the validation.  The BPL returns the response to the service.  Then you can either directly route the message from the BPL or you could send it to a router.  So the BPL validation process would be the first to examine the message and make the decision if it is good or not.   When the message hits the routing rules you know it is good.

If you haven't done any BPL please visit InterSystems learning services or contact your sales engineer or service executive to help.

I have seen the same problem with using character streams and the "raw" get so needed to use the un-escaped get and decode into a binary stream.   It seems that something in the encoded PDF is interpreted as an escaped end marker.

I never like to have direct write to files inside of the rules or transformation so I return the decoded stream.  Usually I call this in a transformation that places it into a stream container.  That stream container is then sent to a Filepassthrough or FTPpassthrough operation to handle the actual dropping of the file.

Here is my similar function that has worked for very large embedded PDF files:

ClassMethod GetStreamDecodeFromHL7Field(pHl7Msg As EnsLib.HL7.Message, pPropPath As %String) As %Stream.Object
                #dim tSC as %Status = $$$OK
                #dim tRemainder as %String
                #dim tBinary as %String
                #dim tBase64 as %String
                // Extract Base64 encoded data to a temp stream, then
                // decode it as a second step.
                set tRemainder = ""
                set tBase64Stream = ##class(%Stream.TmpCharacter).%New()
                set tSC = pHl7Msg.GetFieldStreamUnescaped(.tBase64Stream, pPropPath, .tRemainder)
                set tStream = ##class(%Stream.GlobalBinary).%New()
                do tBase64Stream.Rewind()
                while ('tBase64Stream.AtEnd) {
                                set tBase64 = tBase64Stream.ReadLine()
                                set tBinary = $system.Encryption.Base64Decode(tBase64)
                                do tStream.Write(tBinary)
                return tStream

I have built a custom function that I call ListExists that handles checking if a List returned by the [] square bracket syntax has (any or all)  items in the lookup table.  Square bracket syntax works in a routing rule and returns a >< delimited list of all the values in a particular repeating field.

Here is the code:

Class CustomFunction.ListExists Extends Ens.Rule.FunctionSet
/// Test if the keys specified in the <var>List</var> are defined within the lookup table specified by <var>LookupTable</var>.<br/>
/// Can handle lists like &lt;key1&gt;&lt;key2&gt;&lt;...&gt; or other delimited lists by changing the <var>Delimeter</var>.<br/>
/// Return true (1) if "All" keys exists (default) or if any key exists by entering "Any" in <var>AnyAll</var>, and false (0) otherwise.<br/>
/// <var>IgnoreNullListItem</var> when 1 will ignore empty list items.
ClassMethod ListExists(LookupTable As %String = "", List As %String, Delimeter As %String = "><", AnyAll As %String = "All", IgnoreNullListItem As %Boolean = 1) As %Boolean
                if LookupTable = ""
                {  Quit 0
                set tAnyAll = ..ToUpper(AnyAll)
                set tListLen = $LENGTH(List,Delimeter)
                set tcount = 1
                While tcount <= tListLen
                  set tListItem = $PIECE(List,Delimeter,tcount)
                  if Delimeter = "><"
                  {  // strip off beginning and end half delemiters
                    if tcount = 1
                    {  set tListItem = $ZSTRIP(tListItem,"<","<")
                    // could be both first and last
                    if tcount = tListLen
                                  set tListItem = $ZSTRIP(tListItem,">",">")
                  if tListItem = ""
                  {  //list item is null
                     if IgnoreNullListItem
                                    set tcount = tcount + 1
                     // note that a null list item will never exist in the table so the "ALL" will fail if not ignored
                  if ..Exists(LookupTable,tListItem)
                  {  // this one exists in lookup table
                                if tAnyAll = "ANY"
                                   Return 1
                  //doesn't exist and we want all to exist
                    if tAnyAll = "ALL"
                                   Return 0
                  set tcount = tcount + 1
   // if comes out of loop then
   if tAnyAll = "ANY"
   {  Quit 0 // didn't find any
   else //assume in "ALL" so must have found them all to get here
   {  Quit 1

I believe this would be easier to build in a BPL instead of routing rules.   The validation logic can be built directly in the BPL or even done in a validation transformation. (The source is the HL7 message, the target is the Response message.)  If the response message comes back to the BPL empty or "all good" then you could proceed to process the HL7 message and send the good response, otherwise send the combined response from the transformation.

You can stop this behavior with the following commands but be aware that this may cause screens such as the production configuration and the production monitor to not automatically refresh when connections are lost, etc.    Therefore it is not recommended to do this on a production instance.   

The issue was initially seen with multiple tabs/windows on the same user, but has now also been seen with multiple users in the management portal into the same namespace.

For a workaround you'll need to set the following global. In all namespaces that you are developing within. 

SET ^%SYS("Portal","EnableAutoRefresh")=0

We have seen some instances where that doesn't completely work. If there are still issues you can disable the inactivity timeout. (I  suspect that a timeout on one portal screen is causing all screens to refresh)

 SET ^EnsPortal(“DisableInactivityTimeout”,”Portal”)=1   

You may pass in a filename from a BPL by setting the %Source of the message being passed from the BPL to the Operation.  Then in the filespec use the %f to pick up this name.   Note that you may still add timestamps, etc. in the filespec so the passed name in %Source may be a partial of the final filename.   

If you have used a recordmap service to read the file the %Source within the message from the service will be set to the original filename and usually includes the full path as well.  One usefulness for this original filename is to utilize it to have corresponding names for processed batches on the output files.

This will NOT allow the passing of a File Path or even a partial path.  If a path is included with the filename it will be striped before applying to the %f in the filespec of the operation.  A custom operation would need to be coded in order to dynamically set the path.

You need to be very specific when utilizing this with Batch operations because if the filename is changed mid batch it may be considered as a different batch and thus not properly write out if "Batch rollover" is used.   If an "End of Batch" message is being sent from the BPL instead of utilizing the rollover time then it would end the batch for the filename in %Source.   (Note that some testing would be needed to confirm this behavior)

If sending to a different path it is easiest to have a different operation and route to the correct operation within the BPL.

First, make sure you are reading the file through a Recordmap service, this will parse the file correctly into the recordmap.  Second,  are you processing the file as one record at a time or as an entire file (batch).  If as a batch then you need to declare a batch class in the record mapper and read the file utilizing a recordmap batch service.

Inside of the BPL, in the context area change the class of the request to be either the recordmap record class, or the recordmap batch class, depending on which you are using.

As for the Transformation, the source is now declared to be either the recordmap record class or the recordmap batch class, the target is then the HL7, and you pass in the "request" as the source and a context HL7 message class variable as the target.