rebuild IN1 segment order based on IN1.22 replacing IN1.1

Homepage Clovertech Forums Read Only Archives Cloverleaf Tcl Library rebuild IN1 segment order based on IN1.22 replacing IN1.1

  • Creator
    Topic
  • #49511
    Cesario Perez
    Participant

    I have been asked to rebuild an hl7 message insurance segment grouping  based on IN1.22 (coordination of benefits) mapped to IN1.1 (setid) and resequence the IN1 segments based on the mapping change value. Example:

    Input:

    IN1.1 = 1

Viewing 10 reply threads
  • Author
    Replies
    • #62263
      Russ Ross
      Participant

      I have to do the same thing for a project just assigned to me for an intergration to AuditLogix.

      Just curious which vendor you are doing this for, especially if it is for AuditLogix.

      I did not get to the nitty gritty yet with some many projects to work on, but think I know enough to do the resequencing especially since Jim Kosloskey (Mr Iteration) is on our team if I need to call on him.

      I did take a quick look and found out the IN# segments are groups including IN1, IN2, IN3 so keep that in mind when you reorder them you likely will be dealing with reordering the entire group and not just a single segment.

      At least I will have to deal with that.

      Here is a more visual look at the grouping I’m talking about as it is defined in the variant

        {

           IN1

           [ IN2 ]

           [ IN3 ]

        }

      I also noticed my problem includes a challenge of a redundant nature where my ascending codes are sometimes the same, for example:

      IN1-1 = 1; IN1-22 = 3

      IN1-1 = 2; IN1-22 = 2

      IN1-1 = 3; IN1-22 = 2

      IN1-1 = 4; IN1-22 = 1

      You may also want to bring this up for discusion as to how to handle this situation even if they say it doesn’t happen becuase they told me it doesn’t happen hear and I found out otherwise, so best to handle the reality of it.

      One trick that I will be looking to exploit is to do math on a basis counter you are iterating over is to reference it as $%g1 for example or something like that.

      If all else fails I can write an xlt proc to use xpm to do just about anything I would imagine.

      With so many projects to work on you may not want to wait on me to get started or better yet you figure it out and give it to me.

      Here is a xlt proc ( xlt_create_NTE_from_OBX7 ) that illustrates how I used xmp for another integration I wrote to create extra NTE segment(s) which might have concepts useful to this integration:

      Code:

      # Begin Module Header ==========================================================
      #
      #——
      # Name:
      #——
      #
      # xlt_create_NTE_from_OBX7.tcl
      #
      #———
      # Purpose:
      #———
      #
      # If any of these conditions are true:
      #
      #    OBX 7 contains the character “<" #    OBX 7 contains the character ">”
      #
      # then delete the OBX 7 field
      # and create the next NTE segment
      # with the observation results in OBX 7
      # for example, if OBX 7 = |<0.25| then create:
      #
      # NTE|01||<0.25
      #
      #--------
      # Inputs:
      #--------
      #
      # xlateInVals 0 = OBX 7 (observation results)
      # xlateInVals 1 = turns on debugging if it exists
      #
      #---------
      # Outputs:
      #---------
      #
      # xlateOutVals 0 = OBX 7 (observation results)
      #
      #-------
      # Notes:
      #-------
      #
      # PICIS requires that OBX 7 (observation results) contains a range of numbers
      # with a minimum and maximum value like |22-33| or |-33 - -22|; however,
      # our lab system might send ranges like |<0.25| or |>-44| which PICIS can’t handle
      #
      #———
      # History:
      #———
      #
      # 2001.04.04 Russ Ross
      #          – wrote initial version
      #
      # End Module Header ============================================================

      proc xlt_create_NTE_from_OBX7 {} {
         upvar xlateId       xlateId
       xlateInList   xlateInList
       xlateInTypes  xlateInTypes
       xlateInVals   xlateInVals
       xlateOutList  xlateOutList
       xlateOutTypes xlateOutTypes
       xlateOutVals  xlateOutVals

         #————————————————–
         # save the current datum list
         # that will need to be reset when this proc is done
         #————————————————–

         set datum_list [datlist]

         #————————————————–
         # initialize the variables that this proc will need
         #————————————————–

         set module “xlt_create_NTE_from_OBX7”

         set OBX7_observation_results [lindex $xlateInVals 0]

         set dh_g1 [xpmfetch $xlateId @g1]
         set dh_g2 [xpmfetch $xlateId @g2]
         set dh_g3 [xpmfetch $xlateId @g3]
         set dh_s1 [xpmfetch $xlateId @s1]

         set g1 [datget $dh_g1 VALUE]
         set g2 [datget $dh_g2 VALUE]
         set g3 [datget $dh_g3 VALUE]
         set s1 [datget $dh_s1 VALUE]

         #——————————————–
         # see if any of these conditions are true:
         #
         #    OBX 7 contains the character “<"    #    OBX 7 contains the character ">”
         #——————————————–

         if {    [regexp   (<+)   "$OBX7_observation_results"]        ||  [regexp   (>+)   “$OBX7_observation_results”] } {

      #——————————————————————
             # create the next NTE segment with the observation results in OBX 7
      #——————————————————————

             set next_s1 [incr s1]
      set NTE_counter [incr s1]

             xpmstore $xlateId   1($g1).1($g2).1($g3).NTE($next_s1).#1   c $NTE_counter
             xpmstore $xlateId   1($g1).1($g2).1($g3).NTE($next_s1).#3   c “Normal Range $OBX7_observation_results”

      #———————–
             # delete the OBX 7 field
      #———————–

      set xlateOutVals [list “”]

      #————————————
      # see if debugging has been turned on
      #————————————

      if { [llength $xlateInVals] > 1 } {
         set MSH_date_time   [datget [xpmfetch $xlateId 0(0).MSH(0).#7 ] VALUE]
         set MSH_seq         [datget [xpmfetch $xlateId 0(0).MSH(0).#10] VALUE]
         set PID_mrn         [datget [xpmfetch $xlateId 1($g1).0(0).PID(0).#3] VALUE]
         set PID_last_name   [datget [xpmfetch $xlateId {1($g1).0(0).PID(0).00041(0).[0]}] VALUE]
         set PID_first_name  [datget [xpmfetch $xlateId {1($g1).0(0).PID(0).00041(0).[1]}] VALUE]
         set PID_middle_name [datget [xpmfetch $xlateId {1($g1).0(0).PID(0).00041(0).[2]}] VALUE]
         puts “($module): =========================”
         puts “($module): MSH_date_time            ($MSH_date_time)”
         puts “($module): MSH_seq                  ($MSH_seq)”
         puts “($module): PID_mrn                  ($PID_mrn)”
         puts “($module): PID_first_name           ($PID_first_name)”
         puts “($module): PID_middle_name          ($PID_middle_name)”
         puts “($module): PID_last_name            ($PID_last_name)”
         puts “($module): OBX7_observation_results ($OBX7_observation_results)”
         puts “($module): =========================”
      }
         }

         #——————————————————————-
         # reset the datum list back to what is was when this proc was called
         #——————————————————————-

         hcidatlistreset $datum_list
      }

      Below is a screen shot showing the xlate that calls this proc.

      Russ Ross
      RussRoss318@gmail.com

    • #62264
      Russ Ross
      Participant

      Here is another URL that could be useful to this integration that I will put some time into understanding as I proceed.

      http://clovertech.infor.com/viewtopic.php?t=2091” class=”bbcode_url”>http://clovertech.infor.com/viewtopic.php?t=2091

      Russ Ross
      RussRoss318@gmail.com

    • #62265
      James Cobane
      Participant

      Cesario,

      You could just simply use IF statements (in the Xlate) within the iteration of the insurance, and based on the value in IN1:22 map to the respective outbound repetition of the IN1. i.e. see the attached translation snippet (which assumes up to 4 insurances), and I used simple PATHCOPY’s for illustration purposes.

      FYI – change the extension back to .xlt – I just changed it to .xls to allow it to upload.

      Hope this helps.

      Jim Cobane

      Henry Ford Health

    • #62266
      Cesario Perez
      Participant

      Thank you very much for the different angles. The current setup is an xlate and a outbound tps tcl which matches up an insurance code across systems. I tried inserting a map in1.22 to in1.1 with a iterate copy % variable and then execute the ins code crosswalk tcl but that xlate really clobbered the output because when the tcl executed it lost track of which in1 segment it was working with. Or say I lost control of the situation and the user needed to move forward on general testing. So I backed out of it and feel that I will be given this assignment in the near future and I will keep you posted of the results. The bottom line is I hope I can accomplish this without changing too much of the configuration which exists now. And no Russ it’s not that vendor it’s a user request. I just don’t understand how that will make an improvement but oh well.

    • #62267
      David Barr
      Participant

      Here’s how to handle the problem in a TPS proc:

      Code:

             run {
                 # ‘run’ mode always has a MSGID; fetch and process it
                 keylget args MSGID mh
                 set msg [msgget $mh]
                 set segs [split $msg “r”]
                 set pipe [string range $msg 3 3]
                 set in1segs [lsearch -all -inline -regexp $segs {^IN1}]
                 set in1nums [lsearch -all -regexp $segs {^IN1}]

                 # create a list for sorting that has in1 field 22 followed
                 # by the in1 segment number
                 set in1sortlist {}
                 for { set num 0 } { $num < [llength $in1nums] } { incr num } {                set in1 [lindex $in1segs $num]                set in1_22 [lindex [split $in1 $pipe] 22]                lappend in1sortlist [list $in1_22 $num]            }            set in1sortlist [lsort -integer -index 0 $in1sortlist]            # put the segments back into the message in the order            # specified by the sorted list            for { set num 0 } { $num < [llength $in1nums] } { incr num } {                set num2 [lindex [lindex $in1sortlist $num] 1]                set in1num [lindex $in1nums $num]                set segs [lreplace $segs $in1num $in1num                              [lindex $in1segs $num2]]            }            set msg [join $segs r]            msgset $mh $msg            lappend dispList "CONTINUE $mh"        }

    • #62268
      Tom Rioux
      Participant

      David,

      That puts the IN1 in the correct order, but you will need some additional coding to handle the possible IN2 and IN3 segments that may accompany them.

      Tom

    • #62269
      Russ Ross
      Participant

      Thanks James Cobane:

      I looked at your downlaodable XLT and was able to use your outlined method to reorder the IN1 groups as needed quite nicely.

      Since I will never have more than 4 IN1 groups I don’t have to have logic to handle infinite IN1 groups.

      Now all I will need is to find out how they want me to deal with duplicate priorities.

      You may have noticed I added a check for a null priority since that comes across sometimes in my case.

      Here is the test xlate I have so far which is almost identical to yours with a bit of exapansion to copy the entire IN1 group:

      Code:

      prologue
         xlt_infile: hl7 2.3 global_super_adt ADT_A01
         who: RRoss
         date: September 13, 2007 7:48:58 PM CDT
         xlt_outfile: hl7 2.3 global_super_adt ADT_001
         type: xlt
         version: 5.0
      end_prologue

      { { OP ITERATE }
         { BASIS 3(0).0 }
         { VAR %g1 }
         { TYPE group }
         { BODY {
             { { OP IF }
                 { ERR 0 }
                 { COND {3(0).0(%g1).IN1.#22.[0] ne @null} }
                 { THENBODY {
                     { { OP IF }
                         { ERR 0 }
                         { COND {3(0).0(%g1).IN1.#22.[0] eq =1} }
                         { THENBODY {
                             { { OP PATHCOPY }
                                 { ERR 0 }
                                 { IN 3(0).0(%g1).IN1 }
                                 { OUT 3(0).0(0).IN1 }
                             }
                             { { OP PATHCOPY }
                                 { ERR 0 }
                                 { IN 3(0).0(%g1).IN2 }
                                 { OUT 3(0).0(0).IN2 }
                             }
                             { { OP PATHCOPY }
                                 { ERR 0 }
                                 { IN 3(0).0(%g1).IN3 }
                                 { OUT 3(0).0(0).IN3 }
                             }
                         }}
                         { ELSEBODY {
                         }}
                     }
                     { { OP IF }
                         { ERR 0 }
                         { COND {3(0).0(%g1).IN1.#22.[0] eq =2} }
                         { THENBODY {
                             { { OP PATHCOPY }
                                 { ERR 0 }
                                 { IN 3(0).0(%g1).IN1 }
                                 { OUT 3(0).0(1).IN1 }
                             }
                             { { OP PATHCOPY }
                                 { ERR 0 }
                                 { IN 3(0).0(%g1).IN2 }
                                 { OUT 3(0).0(1).IN2 }
                             }
                             { { OP PATHCOPY }
                                 { ERR 0 }
                                 { IN 3(0).0(%g1).IN3 }
                                 { OUT 3(0).0(1).IN3 }
                             }
                         }}
                         { ELSEBODY {
                         }}
                     }
                     { { OP IF }
                         { ERR 0 }
                         { COND {3(0).0(%g1).IN1.#22.[0] eq =3} }
                         { THENBODY {
                             { { OP PATHCOPY }
                                 { ERR 0 }
                                 { IN 3(0).0(%g1).IN1 }
                                 { OUT 3(0).0(2).IN1 }
                             }
                             { { OP PATHCOPY }
                                 { ERR 0 }
                                 { IN 3(0).0(%g1).IN2 }
                                 { OUT 3(0).0(2).IN2 }
                             }
                             { { OP PATHCOPY }
                                 { ERR 0 }
                                 { IN 3(0).0(%g1).IN3 }
                                 { OUT 3(0).0(2).IN3 }
                             }
                         }}
                         { ELSEBODY {
                         }}
                     }
                     { { OP IF }
                         { ERR 0 }
                         { COND {3(0).0(%g1).IN1.#22.[0] eq =4} }
                         { THENBODY {
                             { { OP PATHCOPY }
                                 { ERR 0 }
                                 { IN 3(0).0(%g1).IN1 }
                                 { OUT 3(0).0(3).IN1 }
                             }
                             { { OP PATHCOPY }
                                 { ERR 0 }
                                 { IN 3(0).0(%g1).IN2 }
                                 { OUT 3(0).0(3).IN2 }
                             }
                             { { OP PATHCOPY }
                                 { ERR 0 }
                                 { IN 3(0).0(%g1).IN3 }
                                 { OUT 3(0).0(3).IN3 }
                             }
                         }}
                         { ELSEBODY {
                         }}
                     }
                 }}
                 { ELSEBODY {
                 }}
             }
         }}
      }

      Attached is a screen shot of the Xlate to help illustrate for those that may not want to go through the hassel of improting the xlate into cloverleaf and launching the IDE to get the drift.

      Russ Ross
      RussRoss318@gmail.com

    • #62270
      Russ Ross
      Participant

      I’ve always wanted to use and understand the notation $%g2 so I took my previous xlate and applied that $%g2 notation to make a sleeker version to accomplish the same logic of regrouping the IN1 groups as desired.

      Thanks to Jim Kosloskey for telling me exactly how to use the $%g2 notation which I was aware of for a long time but until I used it today kept putting off understanding it enough to benifit.

      As you will see this creates an amazingly simple solution.

      The reason I did a math subtract was the IN1-22 codes start with 1 and the %g2 pathing needs to start with zero.

      Here is the Xlate:

      Code:

      prologue
         xlt_infile: hl7 2.3 global_super_adt ADT_A01
         who: RRoss
         date: September 14, 2007 3:08:11 PM CDT
         xlt_outfile: hl7 2.3 global_super_adt ADT_001
         type: xlt
         version: 5.0
      end_prologue

      { { OP ITERATE }
         { BASIS 3(0).0 }
         { VAR %g1 }
         { TYPE group }
         { BODY {
             { { OP IF }
                 { ERR 0 }
                 { COND {3(0).0(%g1).IN1.#22.[0] ne @null} }
                 { THENBODY {
                     { { OP SUB }
                         { ERR 0 }
                         { IN {{3(0).0(%g1).IN1.#22.[0]} =1} }
                         { OUT {{$%g2}} }
                         { FUNCTION SUB }
                     }
                     { { OP PATHCOPY }
                         { ERR 0 }
                         { IN 3(0).0(%g1).IN1 }
                         { OUT 3(0).0(%g2).IN1 }
                     }
                     { { OP PATHCOPY }
                         { ERR 0 }
                         { IN 3(0).0(%g1).IN2 }
                         { OUT 3(0).0(%g2).IN2 }
                     }
                     { { OP PATHCOPY }
                         { ERR 0 }
                         { IN 3(0).0(%g1).IN3 }
                         { OUT 3(0).0(%g2).IN3 }
                     }
                 }}
                 { ELSEBODY {
                 }}
             }
         }}
      }

      Below is the screen shot of this xlate to help see how %g2 gets set and used which is the key concept of this post.

      Russ Ross
      RussRoss318@gmail.com

    • #62271
      Russ Ross
      Participant

      Now the real fun begins.

      I just finished a discussion about how to handle duplicate priority codes when doing the IN1 regrouping.

      Here we believe in using the Xlate if possible before resorting to TCL code to give a level one person a better chance of understanding and supporting the integration.

      Obviously I could resort to TCL and take care of my extra conditions described below.

      Attached is the email I sent that describes an overview of the logic to handle duplicate priority codes that I will be working towards for those that want to follow along.

      If anyone has ideas on how to use the xlate to approach this problem then I’m listening and thanks.

      My first thought is it will probably require more than one iteration pass over the IN1 groups (ex: the first pass might be to determine if there are any duplicates).

      Russ Ross
      RussRoss318@gmail.com

    • #62272
      Russ Ross
      Participant

      After more discussion it turns out that if I have a duplicate priority then if IN1-2.1 = M95 that one goes first.

      With that in mind I also observed that the IN1 groups on the output do not have to be sequential and any empty IN1 groups will get collapsed by cloverleaf on the way out since the IN1 group is optional.

      This observation allowed for a rather clever solution which I will proceed to share.

      Previously I had used the priority code in IN1-22 to set the output group %g2 but when I had a duplicate priority they both used the same value for %g2 and one overwrote the other.

      So what I did was to use a simple hash table technique by multipling the IN1-22 priority code by 2 which creates a one group gap between each IN1 group on the outbound xlate.

      This leaves room for the case of a duplicate which is handled by subracting one from $%g2 when I incurr IN1-2 = M95.

      Turns out to be very compact and only requires one pass to sort and handle duplicates; daddy would be proud.

      Here is the relevant part of the xlate:

      Code:

      prologue
         xlt_infile: hl7 2.3 global_super_adt ADT_A01
         who: RRoss
         date: September 17, 2007 7:07:35 PM CDT
         xlt_outfile: hl7 2.3 global_super_adt ADT_001
         type: xlt
         version: 5.0
      end_prologue

      { { OP ITERATE }
         { BASIS 3(0).0 }
         { VAR %g1 }
         { TYPE group }
         { BODY {
             { { OP IF }
                 { ERR 0 }
                 { COND {3(0).0(%g1).IN1.#22.[0] ne @null} }
                 { THENBODY {
                     { { OP MUL }
                         { ERR 0 }
                         { IN {{3(0).0(%g1).IN1.#22.[0]} =2} }
                         { OUT {{$%g2}} }
                         { FUNCTION MUL }
                     }
                     { { OP IF }
                         { ERR 0 }
                         { COND { 3(0).0(%g1).IN1.#2.[0] eq =M95} }
                         { THENBODY {
                             { { OP SUB }
                                 { ERR 0 }
                                 { IN {{$%g2} =1} }
                                 { OUT {{$%g2}} }
                                 { FUNCTION SUB }
                             }
                         }}
                         { ELSEBODY {
                         }}
                     }
                     { { OP PATHCOPY }
                         { ERR 0 }
                         { IN 3(0).0(%g1).IN1 }
                         { OUT 3(0).0(%g2).IN1 }
                     }
                     { { OP PATHCOPY }
                         { ERR 0 }
                         { IN 3(0).0(%g1).IN2 }
                         { OUT 3(0).0(%g2).IN2 }
                     }
                     { { OP PATHCOPY }
                         { ERR 0 }
                         { IN 3(0).0(%g1).IN3 }
                         { OUT 3(0).0(%g2).IN3 }
                     }
                 }}
                 { ELSEBODY {
                 }}
             }
         }}
      }

      Russ Ross
      RussRoss318@gmail.com

    • #62273
      Cesario Perez
      Participant

      I have it working based on your suggestions in xlate. My previous work in xlate and tcl failed because I did not take it further. But by others help nd your ideas I’m home. I hard code the output mapping (0,1,2) for in22 = 1,2,3. I am assuming there will be no duplicate in1.22 and no more than 3 in1 segments in the message. Thanks again and here is my code which is just like your examples,  I left out bulk which included all in1,in2 and in3 fields.

      { { OP ITERATE }

         { BASIS 1(0).0(%g1) }

         { VAR %g1 }

         { TYPE group }

         { BODY {

             { { OP COMMENT }

                 { COMMENT {TODO: Insert new actions here} }

             }

             { { OP IF }

                 { ERR 0 }

                 { COND { 1(0).0(%g1).IN1.00447.[0]  eq =1} }

                 { THENBODY {

                     { { OP COMMENT }

                         { COMMENT {TODO: Insert new actions here} }

                     }

                     { { OP COPY }

                         { ERR 0 }

                         { IN @null }

                         { OUT 3(0).0(0).IN1.00368 }

                     }

                     { { OP COPY }

                         { ERR 0 }

                         { IN =01 }

                         { OUT 3(0).0(0).IN1.00426 }

                     }

                     { { OP COPY }

                         { ERR 0 }

                         { IN 1(0).0(%g1).IN1.00428 }

                         { OUT 3(0).0(0).IN1.00428(0) }

Viewing 10 reply threads
  • The forum ‘Tcl Library’ is closed to new topics and replies.

Forum Statistics

Registered Users
5,129
Forums
28
Topics
9,301
Replies
34,447
Topic Tags
288
Empty Topic Tags
10