- INHUSEN ; DGH ; 05 Nov 1999 12:57 ; Enhanced processing functions and utilities
- ;;3.01;BHL IHS Interfaces with GIS;;JUL 01, 2001
- ;COPYRIGHT 1991-2000 SAIC
- ;CHCS TOOLS_460; GEN 5; 21-MAY-1997
- ;COPYRIGHT 1994 SAIC
- ;
- IN(ING,INDEST,INDSTR,INUSEQ,INSEND,INERR,INXDST,INMSG,INLHSCH,INMSASTA,INNOACK,INSTD) ;Process incoming
- ;--1) Verify all needed data is present
- ;--2) Store xmission (if verified but not if it is for housekeeping)
- ;--3) Determines if seq. # protocol is in effect, and processes
- ;--4) Create receipt ack as specified in MSH.
- ;INPUT:
- ;--ING = (REQ) Variable array/global containing lines from msg.
- ;--INDEST = Array of valid destinations in format
- ; INDEST(type) = .01 field of Tran Type. This is not
- ; required if processing incoming ACKS, but will generate
- ; an error if processing incoming msg with no destination.
- ;--INDSTR = (REQ) Receiver dest. pointer -- $P(^INTHPC(INBPN,0),U,7)
- ;--INUSEQ = (OPT) Use seq. # protocol? 0=no (default) 1=yes
- ;--INSEND = (OPT) Variable which will contain the UIF entry(ies) of
- ;---msg which needs to be sent by tranceiver back to other system.
- ;---This may be an accept ack, or it may be a msg which must be
- ;---resent under sequence number protocol. (Pass By Reference)
- ;--INERR = (OPT) Variable to return error msg. (PBR)
- ;--INXDST = (OPT) EXecutable code to identify the destination for
- ;---msgs which won't be uniquely identified by INTYP_INEVN.
- ;---The executable must return the ien in the variable INDSTP.
- ;--INMSG = (OPT) Variable to return UIF of inbound msg (PBR)
- ;--INLHSCH = (OPT) Set to 1 if the incoming msg should not
- ; be placed on the output controller queue, ^INLHSCH.
- ; If not specified, this routine will determine the
- ; conditions under which a msg is queued.
- ;--INBPN = background process internal number. (Will be set in recvr)
- ;--INMSASTA = (OPT) Variable to return MSA-1 ack status (PBR)
- ;--INNOACK = (OPT) =1 to uppress commit ack. Used for transmitters,
- ; which should not create a commit ack to a commit ack.
- ;--INSTD = (OPT) Namespace/interface standard. Values such as
- ; NC (NCPDP) or X1 (X12) will branch to appropriate logic.
- ;RETURN:
- ;0 = success, 1 = non-fatal error, 2 = fatal error
- N ORIGID,ORIGID2,MESSID,INVL,CND,SEQ,STAT,EXPCT,INDST,INDSTP,INMSH,INTYP,INEVN,LOOP,Z,ACKMSG,MSG
- ;Note: INDST and INDSTP are variables for the Dest. file for the
- ;incoming msg. This may differ from the destination of the
- ;background process.
- ;--Branch to support MEDE America implementation of NCPDP
- I $G(INSTD)="PDTS" S ERR=$$INNC^INHUSEN5(ING,.INUSEQ,.INXDST,.INERR) Q ERR
- ;--Identify interface standard
- S INSTD=$$GETSTD(ING)
- ;---X12 branch
- I $G(INSTD)="X12" S ERR=$$X12IN^INHUSEN6(ING,.INDEST,INDSTR,.INSEND,.INERR,.INXDST,.INMSG,$G(INLHSCH),.INMSASTA,$G(INNOACK)) Q ERR
- ;INUSEQ and INSTD not carred forward from IN
- ;---
- S (EXPCT,INSEND)="" S:'$D(INUSEQ) INUSEQ=0
- ;First verify MSH, get msg type and event type. If invalid, quit
- S INVL=$$VERIF(ING,.INMSH,.INTYP,.INEVN,.INERR) I INVL Q 2
- ;Determine accept acknowledge conditions
- S CND=$P(INMSH,INDELIM,15)
- S (MESSID,ORIGID)=$P(INMSH,INDELIM,10) I MESSID="" S MSG(1)="Message does not have a message ID",MSG(2)=$E(INMSH,1,250) D ERRADD^INHUSEN3(.INERR,.MSG) Q 2
- I INTYP="" S INVL=2,MSG(1)="Unable to determine message type",MSG(2)=$E(INMSH,1,250) D ERRADD^INHUSEN3(.INERR,.MSG) G ACK
- ;If ack, get status (and other data as needed based on MSA).
- ;If application ack, will store and determine if commit ack is needed.
- I INTYP["ACK" D I $E($G(INMSASTA))="A"!INVL G ACK
- . S INVL=$$ACKIN^INHUSEN2(ING,.INMSASTA,.EXPCT,.INDST,.INDSTP,.ACKMSG,.INERR) Q:INVL
- . ;destination only needed for App. ack.
- . Q:$E($G(INMSASTA))="C"
- . I '$G(INDSTP) S MSG(1)="Ack "_MESSID_" has no destination",MSG(2)=$E(INMSH,1,250),INVL=2 D ERRADD^INHUSEN3(.INERR,.MSG) Q
- . S STAT=0 D STORE
- ;--If incoming is a msg not an ack, must determine tran. type.
- I INTYP'["ACK" D G:INVL ACK
- .;If tranceiver passed INXDST, execute it. Otherwise do DEST.
- .S Z=$S($L($G(INXDST)):INXDST,1:"D DEST") X Z
- .I '$D(INDSTP) S INVL=2,MSG(1)="Message "_MESSID_" has no destination",MSG(2)=$E(INMSH,1,250) D ERRADD^INHUSEN3(.INERR,.MSG) Q
- .;pointer needed for most functions, NAME needed for NEW^INHD.
- .S:'$D(INDST) INDST=$P(^INRHD(INDSTP,0),U)
- ;
- ;--Handle sequence number protocol if applicable. Will not store
- ;--msg if link is out of synch or if msg is for re-synch only.
- I INUSEQ D G:INVL ACK
- .;If commit ack (application ack won't get this far in routine)
- .I INTYP["ACK" S INVL=$$ACKINSEQ^INHUSEQ(INMSASTA,INDSTR,EXPCT,.INSEND,.INERR) Q
- .;If msg, verify sequence number
- .S SEQ=$P(INMSH,INDELIM,13)
- .S INVL=$$SEQIN^INHUSEQ(INDSTR,.SEQ,.STAT,.INERR,.EXPCT)
- .;If invalid, must return ack no matter what CND
- .S:INVL CND="ER"
- ;
- ;Store msg
- D STORE
- ;If inbound is an application ack, see if commit ack needed
- I INTYP["ACK",$E(INMSASTA)["A" G ACK
- ;Update parent for commit acks
- I INTYP["ACK",INMSG>0 D CACKLOG^INHUSEN2(INMSG,ACKMSG,INMSASTA,.INERR)
- ;Under sequence number protocol, update LAST RECEIVED, but only after
- ;msg is successfully filed
- I INUSEQ N LTRY S LOOP=0 F LTRY=1:1:5 D Q:LOOP
- .L +^INRHD(INDSTR,3):3
- .I $T S:'$D(^INRHB("RUN",INBPN)) LOOP=1 Q
- .S $P(^INRHD(INDSTR,3),U)=SEQ,LOOP=1 L -^INRHD(INDSTR,3)
- .I '$T D ERRADD^INHUSEN3(.INERR,"Lock failed on ^INRHD("_INDSTR_" for message "_MESSID) Q 2
- ;Flow through to tag ACK. Routine may also jump to ACK from above.
- ACK ;Process commit ack and quit back to transceiver routine.
- ;CND originally set from MSH.
- D
- .;INNOACK parameter over-rides all others.
- .I $G(INNOACK) S CND="NE" Q
- .;Interface Destination File may have over-ride value.
- .S:$L($P(^INRHD(INDSTR,0),U,11)) CND=$P(^INRHD(INDSTR,0),U,11)
- ;Stop Transaction Type Audit
- D:$D(XUAUDIT) TTSTP^XUSAUD("",$G(INMSG))
- N STAT,CERR D
- . Q:CND="NE"
- . ;If CND has value, msg is in enhanced HL7 mode
- . I $L(CND) D Q
- .. I 'INVL,"SU,AL"[CND S CERR=$$CACK^INHUSEN2(INDSTR,"CA",ORIGID,.INERR,EXPCT) Q
- .. I INVL,"AL,ER"[CND S CERR=$$CACK^INHUSEN2(INDSTR,"CR",ORIGID,.INERR,EXPCT) Q
- . ;CND will be null if msg is in original mode.
- . ;If msg can't be filed, let CACK function create reject ack.
- . ;(Transceiver routine will have to send the commit type ack)
- . ;If msg was filed, do nothing. Application will ack.
- . I INVL>1,'$L($P($G(INMSH),U,16)) S CERR=$$CACK^INHUSEN2(INDSTR,"AR",ORIGID,.INERR,EXPCT)
- Q $S($G(CERR)>INVL:CERR,1:INVL)
- ;
- STORE ;Store incoming xmission in the Universal Interface file
- ;IHS needs DT
- D SETDT^UTDT
- D STORE^INHUSEN4
- Q
- ;
- VERIF(INGBL,INMSH,INTYP,INEVN,INERR) ;Determine HL7 message type and event
- Q $$VERIF^INHUSEN4(INGBL,.INMSH,.INTYP,.INEVN,.INERR)
- ;
- DEST ;Find destination for incoming message (not incoming ack?).
- D DEST^INHUSEN4
- Q
- ;
- GETSTD(INGBL) ;Identify the standard of the incoming message.
- ;This function looks at the first part of the first segment of
- ;the incoming message to distinguish between X12 and HL7 messages.
- ;INPUT
- ; INGBL passed from receiver
- ;RETURN
- ; Interface Standard such as X12 or HL7
- ; -1 if standard is unknown or first segment is unrecognizable.
- N LINE,LCT
- I +INGBL S LCT=0 D GETLINE^INHOU(INGBL,.LCT,.LINE)
- I 'INGBL S LINE=$G(@INGBL@(1))
- I $E(LINE,1,3)="MSH" Q "HL7"
- I $E(LINE,1,3)="ISA" Q "X12"
- ;If none of the above, error
- S MSG(1)="Message from receiver "_$P(^INTHPC(INBPN,0),U)_" does not have a known header segment",MSG(2)=$E(LINE,1,250) D ERRADD^INHUSEN3(.INERR,.MSG)
- Q -1
- ;
- INHUSEN ; DGH ; 05 Nov 1999 12:57 ; Enhanced processing functions and utilities
- +1 ;;3.01;BHL IHS Interfaces with GIS;;JUL 01, 2001
- +2 ;COPYRIGHT 1991-2000 SAIC
- +3 ;CHCS TOOLS_460; GEN 5; 21-MAY-1997
- +4 ;COPYRIGHT 1994 SAIC
- +5 ;
- IN(ING,INDEST,INDSTR,INUSEQ,INSEND,INERR,INXDST,INMSG,INLHSCH,INMSASTA,INNOACK,INSTD) ;Process incoming
- +1 ;--1) Verify all needed data is present
- +2 ;--2) Store xmission (if verified but not if it is for housekeeping)
- +3 ;--3) Determines if seq. # protocol is in effect, and processes
- +4 ;--4) Create receipt ack as specified in MSH.
- +5 ;INPUT:
- +6 ;--ING = (REQ) Variable array/global containing lines from msg.
- +7 ;--INDEST = Array of valid destinations in format
- +8 ; INDEST(type) = .01 field of Tran Type. This is not
- +9 ; required if processing incoming ACKS, but will generate
- +10 ; an error if processing incoming msg with no destination.
- +11 ;--INDSTR = (REQ) Receiver dest. pointer -- $P(^INTHPC(INBPN,0),U,7)
- +12 ;--INUSEQ = (OPT) Use seq. # protocol? 0=no (default) 1=yes
- +13 ;--INSEND = (OPT) Variable which will contain the UIF entry(ies) of
- +14 ;---msg which needs to be sent by tranceiver back to other system.
- +15 ;---This may be an accept ack, or it may be a msg which must be
- +16 ;---resent under sequence number protocol. (Pass By Reference)
- +17 ;--INERR = (OPT) Variable to return error msg. (PBR)
- +18 ;--INXDST = (OPT) EXecutable code to identify the destination for
- +19 ;---msgs which won't be uniquely identified by INTYP_INEVN.
- +20 ;---The executable must return the ien in the variable INDSTP.
- +21 ;--INMSG = (OPT) Variable to return UIF of inbound msg (PBR)
- +22 ;--INLHSCH = (OPT) Set to 1 if the incoming msg should not
- +23 ; be placed on the output controller queue, ^INLHSCH.
- +24 ; If not specified, this routine will determine the
- +25 ; conditions under which a msg is queued.
- +26 ;--INBPN = background process internal number. (Will be set in recvr)
- +27 ;--INMSASTA = (OPT) Variable to return MSA-1 ack status (PBR)
- +28 ;--INNOACK = (OPT) =1 to uppress commit ack. Used for transmitters,
- +29 ; which should not create a commit ack to a commit ack.
- +30 ;--INSTD = (OPT) Namespace/interface standard. Values such as
- +31 ; NC (NCPDP) or X1 (X12) will branch to appropriate logic.
- +32 ;RETURN:
- +33 ;0 = success, 1 = non-fatal error, 2 = fatal error
- +34 NEW ORIGID,ORIGID2,MESSID,INVL,CND,SEQ,STAT,EXPCT,INDST,INDSTP,INMSH,INTYP,INEVN,LOOP,Z,ACKMSG,MSG
- +35 ;Note: INDST and INDSTP are variables for the Dest. file for the
- +36 ;incoming msg. This may differ from the destination of the
- +37 ;background process.
- +38 ;--Branch to support MEDE America implementation of NCPDP
- +39 IF $GET(INSTD)="PDTS"
- SET ERR=$$INNC^INHUSEN5(ING,.INUSEQ,.INXDST,.INERR)
- QUIT ERR
- +40 ;--Identify interface standard
- +41 SET INSTD=$$GETSTD(ING)
- +42 ;---X12 branch
- +43 IF $GET(INSTD)="X12"
- SET ERR=$$X12IN^INHUSEN6(ING,.INDEST,INDSTR,.INSEND,.INERR,.INXDST,.INMSG,$GET(INLHSCH),.INMSASTA,$GET(INNOACK))
- QUIT ERR
- +44 ;INUSEQ and INSTD not carred forward from IN
- +45 ;---
- +46 SET (EXPCT,INSEND)=""
- IF '$DATA(INUSEQ)
- SET INUSEQ=0
- +47 ;First verify MSH, get msg type and event type. If invalid, quit
- +48 SET INVL=$$VERIF(ING,.INMSH,.INTYP,.INEVN,.INERR)
- IF INVL
- QUIT 2
- +49 ;Determine accept acknowledge conditions
- +50 SET CND=$PIECE(INMSH,INDELIM,15)
- +51 SET (MESSID,ORIGID)=$PIECE(INMSH,INDELIM,10)
- IF MESSID=""
- SET MSG(1)="Message does not have a message ID"
- SET MSG(2)=$EXTRACT(INMSH,1,250)
- DO ERRADD^INHUSEN3(.INERR,.MSG)
- QUIT 2
- +52 IF INTYP=""
- SET INVL=2
- SET MSG(1)="Unable to determine message type"
- SET MSG(2)=$EXTRACT(INMSH,1,250)
- DO ERRADD^INHUSEN3(.INERR,.MSG)
- GOTO ACK
- +53 ;If ack, get status (and other data as needed based on MSA).
- +54 ;If application ack, will store and determine if commit ack is needed.
- +55 IF INTYP["ACK"
- Begin DoDot:1
- +56 SET INVL=$$ACKIN^INHUSEN2(ING,.INMSASTA,.EXPCT,.INDST,.INDSTP,.ACKMSG,.INERR)
- IF INVL
- QUIT
- +57 ;destination only needed for App. ack.
- +58 IF $EXTRACT($GET(INMSASTA))="C"
- QUIT
- +59 IF '$GET(INDSTP)
- SET MSG(1)="Ack "_MESSID_" has no destination"
- SET MSG(2)=$EXTRACT(INMSH,1,250)
- SET INVL=2
- DO ERRADD^INHUSEN3(.INERR,.MSG)
- QUIT
- +60 SET STAT=0
- DO STORE
- End DoDot:1
- IF $EXTRACT($GET(INMSASTA))="A"!INVL
- GOTO ACK
- +61 ;--If incoming is a msg not an ack, must determine tran. type.
- +62 IF INTYP'["ACK"
- Begin DoDot:1
- +63 ;If tranceiver passed INXDST, execute it. Otherwise do DEST.
- +64 SET Z=$SELECT($LENGTH($GET(INXDST)):INXDST,1:"D DEST")
- XECUTE Z
- +65 IF '$DATA(INDSTP)
- SET INVL=2
- SET MSG(1)="Message "_MESSID_" has no destination"
- SET MSG(2)=$EXTRACT(INMSH,1,250)
- DO ERRADD^INHUSEN3(.INERR,.MSG)
- QUIT
- +66 ;pointer needed for most functions, NAME needed for NEW^INHD.
- +67 IF '$DATA(INDST)
- SET INDST=$PIECE(^INRHD(INDSTP,0),U)
- End DoDot:1
- IF INVL
- GOTO ACK
- +68 ;
- +69 ;--Handle sequence number protocol if applicable. Will not store
- +70 ;--msg if link is out of synch or if msg is for re-synch only.
- +71 IF INUSEQ
- Begin DoDot:1
- +72 ;If commit ack (application ack won't get this far in routine)
- +73 IF INTYP["ACK"
- SET INVL=$$ACKINSEQ^INHUSEQ(INMSASTA,INDSTR,EXPCT,.INSEND,.INERR)
- QUIT
- +74 ;If msg, verify sequence number
- +75 SET SEQ=$PIECE(INMSH,INDELIM,13)
- +76 SET INVL=$$SEQIN^INHUSEQ(INDSTR,.SEQ,.STAT,.INERR,.EXPCT)
- +77 ;If invalid, must return ack no matter what CND
- +78 IF INVL
- SET CND="ER"
- End DoDot:1
- IF INVL
- GOTO ACK
- +79 ;
- +80 ;Store msg
- +81 DO STORE
- +82 ;If inbound is an application ack, see if commit ack needed
- +83 IF INTYP["ACK"
- IF $EXTRACT(INMSASTA)["A"
- GOTO ACK
- +84 ;Update parent for commit acks
- +85 IF INTYP["ACK"
- IF INMSG>0
- DO CACKLOG^INHUSEN2(INMSG,ACKMSG,INMSASTA,.INERR)
- +86 ;Under sequence number protocol, update LAST RECEIVED, but only after
- +87 ;msg is successfully filed
- +88 IF INUSEQ
- NEW LTRY
- SET LOOP=0
- FOR LTRY=1:1:5
- Begin DoDot:1
- +89 LOCK +^INRHD(INDSTR,3):3
- +90 IF $TEST
- IF '$DATA(^INRHB("RUN",INBPN))
- SET LOOP=1
- QUIT
- +91 SET $PIECE(^INRHD(INDSTR,3),U)=SEQ
- SET LOOP=1
- LOCK -^INRHD(INDSTR,3)
- +92 IF '$TEST
- DO ERRADD^INHUSEN3(.INERR,"Lock failed on ^INRHD("_INDSTR_" for message "_MESSID)
- QUIT 2
- End DoDot:1
- IF LOOP
- QUIT
- +93 ;Flow through to tag ACK. Routine may also jump to ACK from above.
- ACK ;Process commit ack and quit back to transceiver routine.
- +1 ;CND originally set from MSH.
- +2 Begin DoDot:1
- +3 ;INNOACK parameter over-rides all others.
- +4 IF $GET(INNOACK)
- SET CND="NE"
- QUIT
- +5 ;Interface Destination File may have over-ride value.
- +6 IF $LENGTH($PIECE(^INRHD(INDSTR,0),U,11))
- SET CND=$PIECE(^INRHD(INDSTR,0),U,11)
- End DoDot:1
- +7 ;Stop Transaction Type Audit
- +8 IF $DATA(XUAUDIT)
- DO TTSTP^XUSAUD("",$GET(INMSG))
- +9 NEW STAT,CERR
- Begin DoDot:1
- +10 IF CND="NE"
- QUIT
- +11 ;If CND has value, msg is in enhanced HL7 mode
- +12 IF $LENGTH(CND)
- Begin DoDot:2
- +13 IF 'INVL
- IF "SU,AL"[CND
- SET CERR=$$CACK^INHUSEN2(INDSTR,"CA",ORIGID,.INERR,EXPCT)
- QUIT
- +14 IF INVL
- IF "AL,ER"[CND
- SET CERR=$$CACK^INHUSEN2(INDSTR,"CR",ORIGID,.INERR,EXPCT)
- QUIT
- End DoDot:2
- QUIT
- +15 ;CND will be null if msg is in original mode.
- +16 ;If msg can't be filed, let CACK function create reject ack.
- +17 ;(Transceiver routine will have to send the commit type ack)
- +18 ;If msg was filed, do nothing. Application will ack.
- +19 IF INVL>1
- IF '$LENGTH($PIECE($GET(INMSH),U,16))
- SET CERR=$$CACK^INHUSEN2(INDSTR,"AR",ORIGID,.INERR,EXPCT)
- End DoDot:1
- +20 QUIT $SELECT($GET(CERR)>INVL:CERR,1:INVL)
- +21 ;
- STORE ;Store incoming xmission in the Universal Interface file
- +1 ;IHS needs DT
- +2 DO SETDT^UTDT
- +3 DO STORE^INHUSEN4
- +4 QUIT
- +5 ;
- VERIF(INGBL,INMSH,INTYP,INEVN,INERR) ;Determine HL7 message type and event
- +1 QUIT $$VERIF^INHUSEN4(INGBL,.INMSH,.INTYP,.INEVN,.INERR)
- +2 ;
- DEST ;Find destination for incoming message (not incoming ack?).
- +1 DO DEST^INHUSEN4
- +2 QUIT
- +3 ;
- GETSTD(INGBL) ;Identify the standard of the incoming message.
- +1 ;This function looks at the first part of the first segment of
- +2 ;the incoming message to distinguish between X12 and HL7 messages.
- +3 ;INPUT
- +4 ; INGBL passed from receiver
- +5 ;RETURN
- +6 ; Interface Standard such as X12 or HL7
- +7 ; -1 if standard is unknown or first segment is unrecognizable.
- +8 NEW LINE,LCT
- +9 IF +INGBL
- SET LCT=0
- DO GETLINE^INHOU(INGBL,.LCT,.LINE)
- +10 IF 'INGBL
- SET LINE=$GET(@INGBL@(1))
- +11 IF $EXTRACT(LINE,1,3)="MSH"
- QUIT "HL7"
- +12 IF $EXTRACT(LINE,1,3)="ISA"
- QUIT "X12"
- +13 ;If none of the above, error
- +14 SET MSG(1)="Message from receiver "_$PIECE(^INTHPC(INBPN,0),U)_" does not have a known header segment"
- SET MSG(2)=$EXTRACT(LINE,1,250)
- DO ERRADD^INHUSEN3(.INERR,.MSG)
- +15 QUIT -1
- +16 ;