RAHLTCPX ;HIRMFO/RTK,RVD,GJC - Rad/Nuc Med HL7 TCP/IP Bridge;02/11/08
;;5.0;Radiology/Nuclear Medicine;**47**;Mar 16, 1998;Build 21
;
; this is a modified copy of RAHLTCPB for HL7 v2.4
;
;Integration Agreements
;----------------------
;GENACK^HLMA1(2165); DT^XLFDT(10103) ^DPT("SSN" (10035)
;
EN1 ; Main entry point; Build the ^TMP("RARPT-REC" global
;
N ARR,HLCS,HLDTM,HLFS,HLSCS,MSA1,PAR,RAI,RAX,RAY,RAXX,RAEXIT,RARCNT
N RASEG,RASUB,RAHLTCPB,RANODE,RAVERF,RAESIG,RAERR,RANOSEND
N RARRR,RACNPPP,RACKYES,RAPRSET,RAT35,RASTRE,RARE33
D INIT,PROCESS,XIT
Q
;
INIT ; -- initialize
;
S RASUB=HL("MID"),RAHLTCPB=1,RACNPPP=0,RARRR="",RACKYES=0 K RAERR
K ^TMP("RARPT-REC",$J,RASUB) ; kill storage area for new HL7 message id
S ^TMP("RARPT-REC",$J,RASUB,"RADATE")=$$DT^XLFDT()
S ^TMP("RARPT-REC",$J,RASUB,"VENDOR")=$G(HL("SAN"))
S:$D(HL("ESIG")) ^TMP("RARPT-REC",$J,RASUB,"RAESIG")=HL("ESIG") ;Save off E-Sig information (if it exists)
S:'$$GETSFLAG^RAHLRU($G(HL("SAN")),$G(HL("MTN")),$G(HL("ETN")),$G(HL("VER"))) RANOSEND=$G(HL("SAN"))
;
S HLDTM=HL("DTM")
S HLFS=HL("FS")
S HLCS=$E(HL("ECH"))
S HLSCS=$E(HL("ECH"),4)
S HLREP=$E(HL("ECH"),2)
S HLECH=HL("ECH")
Q
;
PROCESS ; -- pull message text
;
F X HLNEXT Q:HLQUIT'>0!$G(RAEXIT) D
.I '$L(HLNODE),$L($G(HLNODE(1))) S HLNODE=HLNODE(1) K HLNODE(1) F J=2:1 Q:'$D(HLNODE(J)) S HLNODE(J-1)=HLNODE(J) K HLNODE(J)
.Q:$P(HLNODE,HLFS)=""
.Q:"^MSH^PID^PV1^OBR^OBX^ORC^"'[(U_$P(HLNODE,HLFS)_U)
.K ARR,PAR M ARR(1)=HLNODE D PARSEG^RAHLRU1(.ARR,.PAR)
.D @($P(HLNODE,HLFS))
Q:$G(RAEXIT)
I '$D(RASEG("PID")) S RAERR="Missing PID Segment" Q
I '$D(RASEG("OBR")) S RAERR="Missing OBR Segment" Q
I '$D(RASEG("OBX")) S RAERR="Missing OBX Segment" Q
Q
;
MSH ;
Q
PID ; Pick data off the 'PID' segment.
;Req: PID-2(Station number concatenated with dash and DFN ex: 587-1234),
; PID-3(SSN), PID-4(National ICN), PID-5(Patient Name), PID-19(SSN)
;Opt: PID-7(Date of Birth), PID-8(Sex), PID-10(Race), PID-11(Address),
; PID-13(Phone-Home), PID-14(Phone-Bus), PID-22(Ethnic Group)
;
;As a result of PID-2, PID-3, PID-4 discussions/emails with Imaging and
; Identity Management (IDM), the above description is what will be sent
; in fields PID-2 thru PID-4. For parsing incoming ORU messages from
; voice recognition systems, this code will first look for the SSN in
; PID-3. If that is null or not a valid SSN, the code will next look
; for the Station Number-DFN in PID-2. If that is null or does not
; contain a valid DFN, the message will be rejected with an "Invalid
; Patient Identifier" reject message.
;
; get SSN from PID-3/PAR(4) if unsuccessful get DFN from PID-2/PAR(3)
S RADFN="" S RASSNVAL=$P($G(PAR(4)),U,1) I RASSNVAL'="" S RADFN=$O(^DPT("SSN",RASSNVAL,""))
I RADFN="" S RADFN=$P($P($G(PAR(3)),U,1),"-",2) ;strip station number and get DFN
I $G(RADFN)="" S RAERR="Invalid patient identifier",RAEXIT=1 Q
I $G(RADFN)'="" S ^TMP("RARPT-REC",$J,RASUB,"RADFN")=RADFN
;
; get SSN from PID-19/PAR(20)
I $G(PAR(20)) S RASSN=PAR(20),^TMP("RARPT-REC",$J,RASUB,"RASSN")=RASSN
S RASEG("PID")=""
;.I $P(PAR(5),U,5)="NI" D Q ;check for valid ICN
;..S RAICNVAL=$P($P(PAR(5),U,1),"V",1),RADFN=$$GETDFN^MPIF001(RAICNVAL)
;..I $G(RADFN)<0 S RAERR="Invalid patient ICN",RAEXIT=1,RADFN="" Q
Q
PV1 ;Ignored at this time.
Q
ORC ; Pick data off the 'ORC' segment
;Opt: ORC -1
; = CN The combined result code provides a mechanism to transmit
; results that are associated with two or more orders.
; This situation occurs commonly in reports when the radiologist
; dictates a single report for two or more exams.
; = RE Observations to follow is used to transmit patient-specific information with an order.
; An order detail segment (e.g., OBR) can be followed by one or more observation RASEGments (OBX).
; Any observation that can be transmitted in an ORU message can be transmitted with this mechanism.
; When results are transmitted with an order, the results should immediately follow the order or orders that they support.
S RARRR="",RASEG("ORC")=PAR(2)
S:PAR(2)="CN" RACNPPP=RACNPPP+1,RARRR="RARPT-REC-"_RACNPPP
Q
OBR ; Pick data off the 'OBR' segment.
;Req: OBR-1(set ID), OBR-2(Placer Order #), OBR-3(Filler Order #), OBR-4(Uni. Service ID)
; OBR-7(Observ. Date/time), OBR-16(Ord. Provider), OBR-18(Placer Fld 1)
; OBR-19(Placer Fld 2), OBR-20(Filler Fld 1), OBR-21(Filler Fld 2)
; OBR-22(Rslts Rpt/Stat Chng D/T), OBR-25(Rslts Status)
;Opt: OBR-15(Specimen Source), OBR-17(Ord. Callback Phone #), OBR-29(Parent)
; OBR-32(Prin. Rslt Interpreter), OBR-33(Asst. Rslt Interpreter), OBR-35(Transcriptionist)
S RASEG("OBR")=""
I $L(RARRR) K ^TMP(RARRR,$J) M ^TMP(RARRR,$J)=^TMP("RARPT-REC",$J) ;Merge if OBR without Report
S:'$L(RARRR) RARRR="RARPT-REC"
N RAX,RAX1,RAX2,RAI,RARR,RAVERF,RARSDNT,RATRANSC,ARR
;OBR-3/PAR(4) for v2.4: site specific accession # (SSS-DDDDDD-CCCCC)
;Note: if SSAN parameter switch is off format is old # (DDDDDD-CCCCC)
D:$L(PAR(4))
.S RALONGCN=$P(PAR(4),HLCS),^TMP(RARRR,$J,RASUB,"RALONGCN")=RALONGCN
.I RALONGCN="" Q
.I $L(RALONGCN,"-")=2 D ;if old format get data from "ADC" x-ref
..S RADTI=$O(^RADPT("ADC",RALONGCN,RADFN,"")) Q:RADTI=""
..S RACNI=$O(^RADPT("ADC",RALONGCN,RADFN,RADTI,"")) Q:RACNI=""
.I $L(RALONGCN,"-")=3 D ;if new format get data from "ADC1" x-ref
..S RADTI=$O(^RADPT("ADC1",RALONGCN,RADFN,"")) Q:RADTI=""
..S RACNI=$O(^RADPT("ADC1",RALONGCN,RADFN,RADTI,"")) Q:RACNI=""
.Q:RADTI=""
.Q:RACNI=""
.S ^TMP(RARRR,$J,RASUB,"RADTI")=RADTI
.S ^TMP(RARRR,$J,RASUB,"RACNI")=RACNI
I $G(RADTI)'>0 S RAERR="Invalid exam registration timestamp" D XIT Q
I $G(RACNI)'>0 S RAERR="Invalid exam record IEN" D XIT Q
;OBR-25/PAR(26) STATUS: 'C'orrected, 'F'inal, or 'R'esults filed, not verified
I '$L(PAR(26)) S RAERR="Missing Report Status",RAEXIT=1 Q
I "CFR"'[PAR(26) S RAERR="Invalid Report Status: "_PAR(26),RAEXIT=1 Q
S ^TMP(RARRR,$J,RASUB,"RASTAT")=PAR(26)
G:$P(RARRR,"-",3) 112
;OBR-32 PAR(33) Principal Result Interpreter
S RAVERF=+$G(PAR(33)),RAST32=$$VFIER^RAHLRU1(.RAVERF,PAR(26),"OBR-32") I 'RAST32 S RAERR=$P(RAST32,"^",2),RAEXIT=1 Q
I '$D(^XUSEC("RA VERIFY",RAVERF)) S RAERR="PHYSICIAN has no RA VERIFY key",RAEXIT=1 Q
D SR^RAHLRU1(RAVERF)
I +RASTRE=-1 S RAERR=$P(RASTRE,U,2),RAEXIT=1 Q
I RASTRE'["^S^" S RAERR="PHYSICIAN must have a STAFF classification" S RAEXIT=1 Q
S ^TMP(RARRR,$J,RASUB,"RAVERF")=RAVERF
S ^TMP(RARRR,$J,RASUB,"RASTAFF",1)=RAVERF,^("RAWHOCHANGE")=RAVERF ;ID #^family^given
;OBR-33 First Interpreter of Resident type will be the Primary Interpreting staff
D:$L($G(PAR(34)))
.;build an array of good assistants (active & the proper classification)
.S RARR=0 F I=1:1:10 S RARE33=$P(PAR(34),HLREP,I) D:$L(RARE33)
..D SR^RAHLRU1(+RARE33) Q:+RASTRE=-1
..I RASTRE'["^S^",RASTRE'["^R^" Q ;must be a staff or res.
..;find the first resident...
..I RASTRE["^R^",('($D(RARSDNT)#2)) S (RARSDNT,^TMP(RARRR,$J,RASUB,"RARESIDENT"))=+RARE33 Q
..I RASTRE["^R^" S ^TMP(RARRR,$J,RASUB,"RARESIDENT",I)=+RARE33 Q ; To be stored in 70.03 field 70
..I RASTRE["^S^" S ^TMP(RARRR,$J,RASUB,"RASTAFF",I)=+RARE33 ;To be stored in 70.03 field 60
..Q
.Q
;"OBR-35" Transcriptionist
S RATRANSC=$G(PAR(36)),RATRANSC=$P(RATRANSC,HLCS,4)
I RATRANSC'="" S RAT35=$$VFIER^RAHLRU1(.RATRANSC,PAR(26),"OBR-35") I 'RAT35 S RAERR=$P(RAT35,"^",2),RAEXIT=1 Q
S ^TMP(RARRR,$J,RASUB,"RATRANSCRIPT")=$S(RATRANSC]"":RATRANSC,$D(RARSDNT):RARSDNT,1:RAVERF)
D ESIG^RAHLO3
;If last OBR set provider info to all OBRs
K RAXX F I=1:1:RACNPPP S RAXX=RARRR_"-"_I D:$D(^TMP(RAXX,$J,RASUB))
.N RAXXX M RAXXX=^TMP(RAXX,$J,RASUB),^TMP(RAXX,$J,RASUB)=^TMP(RARRR,$J,RASUB),^TMP(RAXX,$J,RASUB)=RAXXX
;
112 ;
I $D(RADTI),$D(RACNI),$D(RAPRSET(RADTI,RACNI)) K RAPRSET(RADTI,RACNI),^TMP(RARRR,$J) S RACNPPP=RACNPPP-1 Q:$P(RARRR,"-",3) M ^TMP(RARRR,$J)=^TMP("RARPT-REC-"_(RACNPPP+1),$J) K ^TMP("RARPT-REC-"_(RACNPPP+1),$J) Q
I $D(RADTI),'$D(RAPRSET(RADTI)) D ;Get array of printset for date...
.N RAPRTSET,RACN,RASUB,CNT
.K RAXX D EN2^RAUTL20(.RAXX) M:$D(RAXX) RAPRSET(RADTI)=RAXX K RAPRSET(RADTI,RACNI)
Q
;
OBX ; Pick data off the 'OBX' segments
;Req: OBX-2(Value Type), OBX-3(Observ. ID), OBX-5(Observ. Value)
; OBX-11(Observ. Rslt. Status)
;
; OBX-2=CE:Coded Element, T:Text
; OBX-3=Identifier ^ Text ^ Name of Coding System ('^' is the
; component separator)
; P^PROCEDURE^L, I^IMPRESSION^L, D^DIAGNOSTIC CODE^L, M:MODIFIERS^L,
; TCM^TECH COMMENT^L, C4^CPT MODIFIERS^L, R^REPORT^L
; OBX-5=data within classification (OBX-3) by Value Type (OBX-2)
; OBX-11=F:Final Results; C:Correction, replace final results;
; R:Rslts entered-not v'fied
;
N RAX S RAOBX3=3 ;RAOBX3 is the # of required components for OBX-3
S RASEG("OBX")="" I $G(PAR(4))']"" S RAERR="Missing Observation Identifier",RAEXIT=1 Q
I $L(PAR(4),HLCS)'=RAOBX3 S RAERR="Observation Identifier format error",RAEXIT=1 Q
;verify OBX-3 by component (three components)
;Ex. RAOBR3(1)="P", RAOBR3(2)="PROCEDURE", RAOBR3(3)="L" always "L"
F RAI=1:1:RAOBX3 S RAOBX3(RAI)=$P(PAR(4),HLCS,RAI)
;
I RAOBX3(3)'="L" S RAERR="Observation Identifier Coding System name in error",RAEXIT=1 Q
S RASTR=""_HLCS_"",RASTR(0)=$P(PAR(4),HLCS,1,2)
;RASTR(0)=identifer and text for this specific HL7 message
;build the identifier and text string for all possible values...
F RAI=1:1 S RAX=$T(OBX3+RAI) Q:RAX="" S RASTR=RASTR_$P(RAX,";",3)_HLCS_$P(RAX,";",4)_HLCS
I RASTR'[(HLCS_RASTR(0)_HLCS) S RAERR="Observation Identifier/Text mismatch" Q
;verify the Observation Value OBX-5
S RAX=$G(PAR(6)),RANODE=$S(RAOBX3(1)="D":"RADX",RAOBX3(1)="I":"RAIMP",1:"RATXT")
S RARCNT(RAOBX3(1))=$G(RARCNT(RAOBX3(1)))+1
I RAX["\S\"!(RAX["\R\")!(RAX["\E\")!(RAX["\T\") S RAX=$$DEESC(RAX)
; For DX Codes we are expecting only the # (ie, 1,2,5 etc not the text)
; If VR (PSCRIBE) sends text with DX Code, strip off text in next line
; Text only will be rejected
I RAOBX3(1)="D" S RAX=+RAX
S ^TMP("RARPT-REC",$J,RASUB,RANODE,RARCNT(RAOBX3(1)))=RAX
F RAI=1:1:RACNPPP S RARRR="RARPT-REC-"_RAI S ^TMP(RARRR,$J,RASUB,RANODE,RARCNT(RAOBX3(1)))=RAX
K RAOBX3,RASTR
Q
XIT ;
D ERR I RAERRCHK=1 G XIT1
I $D(^TMP("RARPT-REC",$J)) S:'RACNPPP RACKYES=1 D EN1^RAHLO D ERR I RAERRCHK=1 G XIT1
F RAI=1:1:RACNPPP S RARRR="RARPT-REC-"_RAI D:$D(^TMP(RARRR,$J))
.K ^TMP("RARPT-REC",$J) M ^TMP("RARPT-REC",$J)=^TMP(RARRR,$J) K ^TMP(RARRR,$J)
.S RACKYES=(RAI=RACNPPP) N I D EN1^RAHLO D ERR I RAERRCHK=1 G XIT1
XIT1 K ^TMP("RARPT-REC",$J) ; kill storage area for current HL7 message id
F RAI=1:1:RACNPPP S RARRR="RARPT-REC-"_RAI K ^TMP(RARRR,$J)
Q
ERR ;
S RAERRCHK=0
I $D(RAERR) D
.S RAEXIT=1,RACKYES=1,RAERRCHK=1
.D ENX^RAHLEXF(HLDTM,RASUB)
.D GENACK
.Q
Q
;
DEESC(RASTR) ;Replace escape sequences with their field separator and escape character
;equivalents. (RAHLTCPX)
;
;input : RASTR=the string of characters being checked for esc sequences
;output: returns a string with field separator and escape characters in
; place of escape sequences
;
;RAFSESC/HLFS = field separator
;RACSESC/$E(HLECH,1) = component separator
;RARSESC/$E(HLECH,2) = repetition separator
;RAESESC/$E(HLECH,3) = escape character
;RASCESC/$E(HLECH,4) = subcomponent separator
;
N RAFSESC,RACSESC,RARSESC,RAESESC,RASCESC
S RAFSESC="\F\",RACSESC="\S\",RARSESC="\R\",RAESESC="\E\",RASCESC="\T\"
N RAYES ;escape characters present? if yes, set YES to one
F D Q:'RAYES
.S RAYES=0
.I RASTR[RAFSESC S RASTR=$P(RASTR,RAFSESC)_HLFS_$P(RASTR,RAFSESC,2,99999),RAYES=1
.I RASTR[RACSESC S RASTR=$P(RASTR,RACSESC)_$E(HLECH,1)_$P(RASTR,RACSESC,2,99999),RAYES=1
.I RASTR[RARSESC S RASTR=$P(RASTR,RARSESC)_$E(HLECH,2)_$P(RASTR,RARSESC,2,99999),RAYES=1
.I RASTR[RAESESC S RASTR=$P(RASTR,RAESESC)_$E(HLECH,3)_$P(RASTR,RAESESC,2,99999),RAYES=1
.I RASTR[RASCESC S RASTR=$P(RASTR,RASCESC)_$E(HLECH,4)_$P(RASTR,RASCESC,2,99999),RAYES=1
.Q
Q RASTR
;
GENACK ; Compile the 'ACK' segment, generate the 'ACK' message.
Q:'$G(RACKYES)
N HLFORMAT,HLARYTYP,RESULT
S MSA1="AA"
Q:$E($G(HL("SAN")),1,3)'="RA-" ; Don't allow non RA namespaced interfaces
I $D(RAERR) S MSA1=$S(HL("SAN")="RA-PSCRIBE-TCP"!$G(RATELE):"AE",1:"AR")
; Added next line to support MedSpeak interface. Must re-initialize
; FS and EC's before sending ACK.
;D:HL("SAN")="RA-CLIENT-TCP" INIT^HLFNC2("RA VOICE TCP SERVER RPT",.HL)
S HLA("HLA",1)="MSA"_HL("FS")_MSA1_HL("FS")_HL("MID")_$S($D(RAERR):HL("FS")_RAERR,1:"")
S HLEID=HL("EID"),HLEIDS=HL("EIDS"),HLARYTYP="LM",HLFORMAT=1
K HLRESLT D GENACK^HLMA1(HLEID,HLMTIENS,HLEIDS,HLARYTYP,HLFORMAT,.RESULT)
I $G(RESULT)="" Q ; RTK 3/26/2008 - UNDEFINED 'RESULT' ERROR
I +$P(RESULT,U,2) D ASTATUS^RAHLACK(RESULT,RASUB,HL("SAN")) ;ERROR in gen ACK...
Q
;
OBX3 ;set the values for OBX-3.1 & OBX-3.2
;;P;PROCEDURE
;;I;IMPRESSION
;;D;DIAGNOSTIC CODE
;;M;MODIFIERS
;;TCM;TECH COMMENT
;;C4;CPT MODIFIERS
;;R;REPORT
RAHLTCPX ;HIRMFO/RTK,RVD,GJC - Rad/Nuc Med HL7 TCP/IP Bridge;02/11/08
+1 ;;5.0;Radiology/Nuclear Medicine;**47**;Mar 16, 1998;Build 21
+2 ;
+3 ; this is a modified copy of RAHLTCPB for HL7 v2.4
+4 ;
+5 ;Integration Agreements
+6 ;----------------------
+7 ;GENACK^HLMA1(2165); DT^XLFDT(10103) ^DPT("SSN" (10035)
+8 ;
EN1 ; Main entry point; Build the ^TMP("RARPT-REC" global
+1 ;
+2 NEW ARR,HLCS,HLDTM,HLFS,HLSCS,MSA1,PAR,RAI,RAX,RAY,RAXX,RAEXIT,RARCNT
+3 NEW RASEG,RASUB,RAHLTCPB,RANODE,RAVERF,RAESIG,RAERR,RANOSEND
+4 NEW RARRR,RACNPPP,RACKYES,RAPRSET,RAT35,RASTRE,RARE33
+5 DO INIT
DO PROCESS
DO XIT
+6 QUIT
+7 ;
INIT ; -- initialize
+1 ;
+2 SET RASUB=HL("MID")
SET RAHLTCPB=1
SET RACNPPP=0
SET RARRR=""
SET RACKYES=0
KILL RAERR
+3 ; kill storage area for new HL7 message id
KILL ^TMP("RARPT-REC",$JOB,RASUB)
+4 SET ^TMP("RARPT-REC",$JOB,RASUB,"RADATE")=$$DT^XLFDT()
+5 SET ^TMP("RARPT-REC",$JOB,RASUB,"VENDOR")=$GET(HL("SAN"))
+6 ;Save off E-Sig information (if it exists)
IF $DATA(HL("ESIG"))
SET ^TMP("RARPT-REC",$JOB,RASUB,"RAESIG")=HL("ESIG")
+7 IF '$$GETSFLAG^RAHLRU($GET(HL("SAN")),$GET(HL("MTN")),$GET(HL("ETN")),$GET(HL("VER")))
SET RANOSEND=$GET(HL("SAN"))
+8 ;
+9 SET HLDTM=HL("DTM")
+10 SET HLFS=HL("FS")
+11 SET HLCS=$EXTRACT(HL("ECH"))
+12 SET HLSCS=$EXTRACT(HL("ECH"),4)
+13 SET HLREP=$EXTRACT(HL("ECH"),2)
+14 SET HLECH=HL("ECH")
+15 QUIT
+16 ;
PROCESS ; -- pull message text
+1 ;
+2 FOR
XECUTE HLNEXT
IF HLQUIT'>0!$GET(RAEXIT)
QUIT
Begin DoDot:1
+3 IF '$LENGTH(HLNODE)
IF $LENGTH($GET(HLNODE(1)))
SET HLNODE=HLNODE(1)
KILL HLNODE(1)
FOR J=2:1
IF '$DATA(HLNODE(J))
QUIT
SET HLNODE(J-1)=HLNODE(J)
KILL HLNODE(J)
+4 IF $PIECE(HLNODE,HLFS)=""
QUIT
+5 IF "^MSH^PID^PV1^OBR^OBX^ORC^"'[(U_$PIECE(HLNODE,HLFS)_U)
QUIT
+6 KILL ARR,PAR
MERGE ARR(1)=HLNODE
DO PARSEG^RAHLRU1(.ARR,.PAR)
+7 DO @($PIECE(HLNODE,HLFS))
End DoDot:1
+8 IF $GET(RAEXIT)
QUIT
+9 IF '$DATA(RASEG("PID"))
SET RAERR="Missing PID Segment"
QUIT
+10 IF '$DATA(RASEG("OBR"))
SET RAERR="Missing OBR Segment"
QUIT
+11 IF '$DATA(RASEG("OBX"))
SET RAERR="Missing OBX Segment"
QUIT
+12 QUIT
+13 ;
MSH ;
+1 QUIT
PID ; Pick data off the 'PID' segment.
+1 ;Req: PID-2(Station number concatenated with dash and DFN ex: 587-1234),
+2 ; PID-3(SSN), PID-4(National ICN), PID-5(Patient Name), PID-19(SSN)
+3 ;Opt: PID-7(Date of Birth), PID-8(Sex), PID-10(Race), PID-11(Address),
+4 ; PID-13(Phone-Home), PID-14(Phone-Bus), PID-22(Ethnic Group)
+5 ;
+6 ;As a result of PID-2, PID-3, PID-4 discussions/emails with Imaging and
+7 ; Identity Management (IDM), the above description is what will be sent
+8 ; in fields PID-2 thru PID-4. For parsing incoming ORU messages from
+9 ; voice recognition systems, this code will first look for the SSN in
+10 ; PID-3. If that is null or not a valid SSN, the code will next look
+11 ; for the Station Number-DFN in PID-2. If that is null or does not
+12 ; contain a valid DFN, the message will be rejected with an "Invalid
+13 ; Patient Identifier" reject message.
+14 ;
+15 ; get SSN from PID-3/PAR(4) if unsuccessful get DFN from PID-2/PAR(3)
+16 SET RADFN=""
SET RASSNVAL=$PIECE($GET(PAR(4)),U,1)
IF RASSNVAL'=""
SET RADFN=$ORDER(^DPT("SSN",RASSNVAL,""))
+17 ;strip station number and get DFN
IF RADFN=""
SET RADFN=$PIECE($PIECE($GET(PAR(3)),U,1),"-",2)
+18 IF $GET(RADFN)=""
SET RAERR="Invalid patient identifier"
SET RAEXIT=1
QUIT
+19 IF $GET(RADFN)'=""
SET ^TMP("RARPT-REC",$JOB,RASUB,"RADFN")=RADFN
+20 ;
+21 ; get SSN from PID-19/PAR(20)
+22 IF $GET(PAR(20))
SET RASSN=PAR(20)
SET ^TMP("RARPT-REC",$JOB,RASUB,"RASSN")=RASSN
+23 SET RASEG("PID")=""
+24 ;.I $P(PAR(5),U,5)="NI" D Q ;check for valid ICN
+25 ;..S RAICNVAL=$P($P(PAR(5),U,1),"V",1),RADFN=$$GETDFN^MPIF001(RAICNVAL)
+26 ;..I $G(RADFN)<0 S RAERR="Invalid patient ICN",RAEXIT=1,RADFN="" Q
+27 QUIT
PV1 ;Ignored at this time.
+1 QUIT
ORC ; Pick data off the 'ORC' segment
+1 ;Opt: ORC -1
+2 ; = CN The combined result code provides a mechanism to transmit
+3 ; results that are associated with two or more orders.
+4 ; This situation occurs commonly in reports when the radiologist
+5 ; dictates a single report for two or more exams.
+6 ; = RE Observations to follow is used to transmit patient-specific information with an order.
+7 ; An order detail segment (e.g., OBR) can be followed by one or more observation RASEGments (OBX).
+8 ; Any observation that can be transmitted in an ORU message can be transmitted with this mechanism.
+9 ; When results are transmitted with an order, the results should immediately follow the order or orders that they support.
+10 SET RARRR=""
SET RASEG("ORC")=PAR(2)
+11 IF PAR(2)="CN"
SET RACNPPP=RACNPPP+1
SET RARRR="RARPT-REC-"_RACNPPP
+12 QUIT
OBR ; Pick data off the 'OBR' segment.
+1 ;Req: OBR-1(set ID), OBR-2(Placer Order #), OBR-3(Filler Order #), OBR-4(Uni. Service ID)
+2 ; OBR-7(Observ. Date/time), OBR-16(Ord. Provider), OBR-18(Placer Fld 1)
+3 ; OBR-19(Placer Fld 2), OBR-20(Filler Fld 1), OBR-21(Filler Fld 2)
+4 ; OBR-22(Rslts Rpt/Stat Chng D/T), OBR-25(Rslts Status)
+5 ;Opt: OBR-15(Specimen Source), OBR-17(Ord. Callback Phone #), OBR-29(Parent)
+6 ; OBR-32(Prin. Rslt Interpreter), OBR-33(Asst. Rslt Interpreter), OBR-35(Transcriptionist)
+7 SET RASEG("OBR")=""
+8 ;Merge if OBR without Report
IF $LENGTH(RARRR)
KILL ^TMP(RARRR,$JOB)
MERGE ^TMP(RARRR,$JOB)=^TMP("RARPT-REC",$JOB)
+9 IF '$LENGTH(RARRR)
SET RARRR="RARPT-REC"
+10 NEW RAX,RAX1,RAX2,RAI,RARR,RAVERF,RARSDNT,RATRANSC,ARR
+11 ;OBR-3/PAR(4) for v2.4: site specific accession # (SSS-DDDDDD-CCCCC)
+12 ;Note: if SSAN parameter switch is off format is old # (DDDDDD-CCCCC)
+13 IF $LENGTH(PAR(4))
Begin DoDot:1
+14 SET RALONGCN=$PIECE(PAR(4),HLCS)
SET ^TMP(RARRR,$JOB,RASUB,"RALONGCN")=RALONGCN
+15 IF RALONGCN=""
QUIT
+16 ;if old format get data from "ADC" x-ref
IF $LENGTH(RALONGCN,"-")=2
Begin DoDot:2
+17 SET RADTI=$ORDER(^RADPT("ADC",RALONGCN,RADFN,""))
IF RADTI=""
QUIT
+18 SET RACNI=$ORDER(^RADPT("ADC",RALONGCN,RADFN,RADTI,""))
IF RACNI=""
QUIT
End DoDot:2
+19 ;if new format get data from "ADC1" x-ref
IF $LENGTH(RALONGCN,"-")=3
Begin DoDot:2
+20 SET RADTI=$ORDER(^RADPT("ADC1",RALONGCN,RADFN,""))
IF RADTI=""
QUIT
+21 SET RACNI=$ORDER(^RADPT("ADC1",RALONGCN,RADFN,RADTI,""))
IF RACNI=""
QUIT
End DoDot:2
+22 IF RADTI=""
QUIT
+23 IF RACNI=""
QUIT
+24 SET ^TMP(RARRR,$JOB,RASUB,"RADTI")=RADTI
+25 SET ^TMP(RARRR,$JOB,RASUB,"RACNI")=RACNI
End DoDot:1
+26 IF $GET(RADTI)'>0
SET RAERR="Invalid exam registration timestamp"
DO XIT
QUIT
+27 IF $GET(RACNI)'>0
SET RAERR="Invalid exam record IEN"
DO XIT
QUIT
+28 ;OBR-25/PAR(26) STATUS: 'C'orrected, 'F'inal, or 'R'esults filed, not verified
+29 IF '$LENGTH(PAR(26))
SET RAERR="Missing Report Status"
SET RAEXIT=1
QUIT
+30 IF "CFR"'[PAR(26)
SET RAERR="Invalid Report Status: "_PAR(26)
SET RAEXIT=1
QUIT
+31 SET ^TMP(RARRR,$JOB,RASUB,"RASTAT")=PAR(26)
+32 IF $PIECE(RARRR,"-",3)
GOTO 112
+33 ;OBR-32 PAR(33) Principal Result Interpreter
+34 SET RAVERF=+$GET(PAR(33))
SET RAST32=$$VFIER^RAHLRU1(.RAVERF,PAR(26),"OBR-32")
IF 'RAST32
SET RAERR=$PIECE(RAST32,"^",2)
SET RAEXIT=1
QUIT
+35 IF '$DATA(^XUSEC("RA VERIFY",RAVERF))
SET RAERR="PHYSICIAN has no RA VERIFY key"
SET RAEXIT=1
QUIT
+36 DO SR^RAHLRU1(RAVERF)
+37 IF +RASTRE=-1
SET RAERR=$PIECE(RASTRE,U,2)
SET RAEXIT=1
QUIT
+38 IF RASTRE'["^S^"
SET RAERR="PHYSICIAN must have a STAFF classification"
SET RAEXIT=1
QUIT
+39 SET ^TMP(RARRR,$JOB,RASUB,"RAVERF")=RAVERF
+40 ;ID #^family^given
SET ^TMP(RARRR,$JOB,RASUB,"RASTAFF",1)=RAVERF
SET ^("RAWHOCHANGE")=RAVERF
+41 ;OBR-33 First Interpreter of Resident type will be the Primary Interpreting staff
+42 IF $LENGTH($GET(PAR(34)))
Begin DoDot:1
+43 ;build an array of good assistants (active & the proper classification)
+44 SET RARR=0
FOR I=1:1:10
SET RARE33=$PIECE(PAR(34),HLREP,I)
IF $LENGTH(RARE33)
Begin DoDot:2
+45 DO SR^RAHLRU1(+RARE33)
IF +RASTRE=-1
QUIT
+46 ;must be a staff or res.
IF RASTRE'["^S^"
IF RASTRE'["^R^"
QUIT
+47 ;find the first resident...
+48 IF RASTRE["^R^"
IF ('($DATA(RARSDNT)#2))
SET (RARSDNT,^TMP(RARRR,$JOB,RASUB,"RARESIDENT"))=+RARE33
QUIT
+49 ; To be stored in 70.03 field 70
IF RASTRE["^R^"
SET ^TMP(RARRR,$JOB,RASUB,"RARESIDENT",I)=+RARE33
QUIT
+50 ;To be stored in 70.03 field 60
IF RASTRE["^S^"
SET ^TMP(RARRR,$JOB,RASUB,"RASTAFF",I)=+RARE33
+51 QUIT
End DoDot:2
+52 QUIT
End DoDot:1
+53 ;"OBR-35" Transcriptionist
+54 SET RATRANSC=$GET(PAR(36))
SET RATRANSC=$PIECE(RATRANSC,HLCS,4)
+55 IF RATRANSC'=""
SET RAT35=$$VFIER^RAHLRU1(.RATRANSC,PAR(26),"OBR-35")
IF 'RAT35
SET RAERR=$PIECE(RAT35,"^",2)
SET RAEXIT=1
QUIT
+56 SET ^TMP(RARRR,$JOB,RASUB,"RATRANSCRIPT")=$SELECT(RATRANSC]"":RATRANSC,$DATA(RARSDNT):RARSDNT,1:RAVERF)
+57 DO ESIG^RAHLO3
+58 ;If last OBR set provider info to all OBRs
+59 KILL RAXX
FOR I=1:1:RACNPPP
SET RAXX=RARRR_"-"_I
IF $DATA(^TMP(RAXX,$JOB,RASUB))
Begin DoDot:1
+60 NEW RAXXX
MERGE RAXXX=^TMP(RAXX,$JOB,RASUB),^TMP(RAXX,$JOB,RASUB)=^TMP(RARRR,$JOB,RASUB),^TMP(RAXX,$JOB,RASUB)=RAXXX
End DoDot:1
+61 ;
112 ;
+1 IF $DATA(RADTI)
IF $DATA(RACNI)
IF $DATA(RAPRSET(RADTI,RACNI))
KILL RAPRSET(RADTI,RACNI),^TMP(RARRR,$JOB)
SET RACNPPP=RACNPPP-1
IF $PIECE(RARRR,"-",3)
QUIT
MERGE ^TMP(RARRR,$JOB)=^TMP("RARPT-REC-"_(RACNPPP+1),$JOB)
KILL ^TMP("RARPT-REC-"_(RACNPPP+1),$JOB)
QUIT
+2 ;Get array of printset for date...
IF $DATA(RADTI)
IF '$DATA(RAPRSET(RADTI))
Begin DoDot:1
+3 NEW RAPRTSET,RACN,RASUB,CNT
+4 KILL RAXX
DO EN2^RAUTL20(.RAXX)
IF $DATA(RAXX)
MERGE RAPRSET(RADTI)=RAXX
KILL RAPRSET(RADTI,RACNI)
End DoDot:1
+5 QUIT
+6 ;
OBX ; Pick data off the 'OBX' segments
+1 ;Req: OBX-2(Value Type), OBX-3(Observ. ID), OBX-5(Observ. Value)
+2 ; OBX-11(Observ. Rslt. Status)
+3 ;
+4 ; OBX-2=CE:Coded Element, T:Text
+5 ; OBX-3=Identifier ^ Text ^ Name of Coding System ('^' is the
+6 ; component separator)
+7 ; P^PROCEDURE^L, I^IMPRESSION^L, D^DIAGNOSTIC CODE^L, M:MODIFIERS^L,
+8 ; TCM^TECH COMMENT^L, C4^CPT MODIFIERS^L, R^REPORT^L
+9 ; OBX-5=data within classification (OBX-3) by Value Type (OBX-2)
+10 ; OBX-11=F:Final Results; C:Correction, replace final results;
+11 ; R:Rslts entered-not v'fied
+12 ;
+13 ;RAOBX3 is the # of required components for OBX-3
NEW RAX
SET RAOBX3=3
+14 SET RASEG("OBX")=""
IF $GET(PAR(4))']""
SET RAERR="Missing Observation Identifier"
SET RAEXIT=1
QUIT
+15 IF $LENGTH(PAR(4),HLCS)'=RAOBX3
SET RAERR="Observation Identifier format error"
SET RAEXIT=1
QUIT
+16 ;verify OBX-3 by component (three components)
+17 ;Ex. RAOBR3(1)="P", RAOBR3(2)="PROCEDURE", RAOBR3(3)="L" always "L"
+18 FOR RAI=1:1:RAOBX3
SET RAOBX3(RAI)=$PIECE(PAR(4),HLCS,RAI)
+19 ;
+20 IF RAOBX3(3)'="L"
SET RAERR="Observation Identifier Coding System name in error"
SET RAEXIT=1
QUIT
+21 SET RASTR=""_HLCS_""
SET RASTR(0)=$PIECE(PAR(4),HLCS,1,2)
+22 ;RASTR(0)=identifer and text for this specific HL7 message
+23 ;build the identifier and text string for all possible values...
+24 FOR RAI=1:1
SET RAX=$TEXT(OBX3+RAI)
IF RAX=""
QUIT
SET RASTR=RASTR_$PIECE(RAX,";",3)_HLCS_$PIECE(RAX,";",4)_HLCS
+25 IF RASTR'[(HLCS_RASTR(0)_HLCS)
SET RAERR="Observation Identifier/Text mismatch"
QUIT
+26 ;verify the Observation Value OBX-5
+27 SET RAX=$GET(PAR(6))
SET RANODE=$SELECT(RAOBX3(1)="D":"RADX",RAOBX3(1)="I":"RAIMP",1:"RATXT")
+28 SET RARCNT(RAOBX3(1))=$GET(RARCNT(RAOBX3(1)))+1
+29 IF RAX["\S\"!(RAX["\R\")!(RAX["\E\")!(RAX["\T\")
SET RAX=$$DEESC(RAX)
+30 ; For DX Codes we are expecting only the # (ie, 1,2,5 etc not the text)
+31 ; If VR (PSCRIBE) sends text with DX Code, strip off text in next line
+32 ; Text only will be rejected
+33 IF RAOBX3(1)="D"
SET RAX=+RAX
+34 SET ^TMP("RARPT-REC",$JOB,RASUB,RANODE,RARCNT(RAOBX3(1)))=RAX
+35 FOR RAI=1:1:RACNPPP
SET RARRR="RARPT-REC-"_RAI
SET ^TMP(RARRR,$JOB,RASUB,RANODE,RARCNT(RAOBX3(1)))=RAX
+36 KILL RAOBX3,RASTR
+37 QUIT
XIT ;
+1 DO ERR
IF RAERRCHK=1
GOTO XIT1
+2 IF $DATA(^TMP("RARPT-REC",$JOB))
IF 'RACNPPP
SET RACKYES=1
DO EN1^RAHLO
DO ERR
IF RAERRCHK=1
GOTO XIT1
+3 FOR RAI=1:1:RACNPPP
SET RARRR="RARPT-REC-"_RAI
IF $DATA(^TMP(RARRR,$JOB))
Begin DoDot:1
+4 KILL ^TMP("RARPT-REC",$JOB)
MERGE ^TMP("RARPT-REC",$JOB)=^TMP(RARRR,$JOB)
KILL ^TMP(RARRR,$JOB)
+5 SET RACKYES=(RAI=RACNPPP)
NEW I
DO EN1^RAHLO
DO ERR
IF RAERRCHK=1
GOTO XIT1
End DoDot:1
XIT1 ; kill storage area for current HL7 message id
KILL ^TMP("RARPT-REC",$JOB)
+1 FOR RAI=1:1:RACNPPP
SET RARRR="RARPT-REC-"_RAI
KILL ^TMP(RARRR,$JOB)
+2 QUIT
ERR ;
+1 SET RAERRCHK=0
+2 IF $DATA(RAERR)
Begin DoDot:1
+3 SET RAEXIT=1
SET RACKYES=1
SET RAERRCHK=1
+4 DO ENX^RAHLEXF(HLDTM,RASUB)
+5 DO GENACK
+6 QUIT
End DoDot:1
+7 QUIT
+8 ;
DEESC(RASTR) ;Replace escape sequences with their field separator and escape character
+1 ;equivalents. (RAHLTCPX)
+2 ;
+3 ;input : RASTR=the string of characters being checked for esc sequences
+4 ;output: returns a string with field separator and escape characters in
+5 ; place of escape sequences
+6 ;
+7 ;RAFSESC/HLFS = field separator
+8 ;RACSESC/$E(HLECH,1) = component separator
+9 ;RARSESC/$E(HLECH,2) = repetition separator
+10 ;RAESESC/$E(HLECH,3) = escape character
+11 ;RASCESC/$E(HLECH,4) = subcomponent separator
+12 ;
+13 NEW RAFSESC,RACSESC,RARSESC,RAESESC,RASCESC
+14 SET RAFSESC="\F\"
SET RACSESC="\S\"
SET RARSESC="\R\"
SET RAESESC="\E\"
SET RASCESC="\T\"
+15 ;escape characters present? if yes, set YES to one
NEW RAYES
+16 FOR
Begin DoDot:1
+17 SET RAYES=0
+18 IF RASTR[RAFSESC
SET RASTR=$PIECE(RASTR,RAFSESC)_HLFS_$PIECE(RASTR,RAFSESC,2,99999)
SET RAYES=1
+19 IF RASTR[RACSESC
SET RASTR=$PIECE(RASTR,RACSESC)_$EXTRACT(HLECH,1)_$PIECE(RASTR,RACSESC,2,99999)
SET RAYES=1
+20 IF RASTR[RARSESC
SET RASTR=$PIECE(RASTR,RARSESC)_$EXTRACT(HLECH,2)_$PIECE(RASTR,RARSESC,2,99999)
SET RAYES=1
+21 IF RASTR[RAESESC
SET RASTR=$PIECE(RASTR,RAESESC)_$EXTRACT(HLECH,3)_$PIECE(RASTR,RAESESC,2,99999)
SET RAYES=1
+22 IF RASTR[RASCESC
SET RASTR=$PIECE(RASTR,RASCESC)_$EXTRACT(HLECH,4)_$PIECE(RASTR,RASCESC,2,99999)
SET RAYES=1
+23 QUIT
End DoDot:1
IF 'RAYES
QUIT
+24 QUIT RASTR
+25 ;
GENACK ; Compile the 'ACK' segment, generate the 'ACK' message.
+1 IF '$GET(RACKYES)
QUIT
+2 NEW HLFORMAT,HLARYTYP,RESULT
+3 SET MSA1="AA"
+4 ; Don't allow non RA namespaced interfaces
IF $EXTRACT($GET(HL("SAN")),1,3)'="RA-"
QUIT
+5 IF $DATA(RAERR)
SET MSA1=$SELECT(HL("SAN")="RA-PSCRIBE-TCP"!$GET(RATELE):"AE",1:"AR")
+6 ; Added next line to support MedSpeak interface. Must re-initialize
+7 ; FS and EC's before sending ACK.
+8 ;D:HL("SAN")="RA-CLIENT-TCP" INIT^HLFNC2("RA VOICE TCP SERVER RPT",.HL)
+9 SET HLA("HLA",1)="MSA"_HL("FS")_MSA1_HL("FS")_HL("MID")_$SELECT($DATA(RAERR):HL("FS")_RAERR,1:"")
+10 SET HLEID=HL("EID")
SET HLEIDS=HL("EIDS")
SET HLARYTYP="LM"
SET HLFORMAT=1
+11 KILL HLRESLT
DO GENACK^HLMA1(HLEID,HLMTIENS,HLEIDS,HLARYTYP,HLFORMAT,.RESULT)
+12 ; RTK 3/26/2008 - UNDEFINED 'RESULT' ERROR
IF $GET(RESULT)=""
QUIT
+13 ;ERROR in gen ACK...
IF +$PIECE(RESULT,U,2)
DO ASTATUS^RAHLACK(RESULT,RASUB,HL("SAN"))
+14 QUIT
+15 ;
OBX3 ;set the values for OBX-3.1 & OBX-3.2
+1 ;;P;PROCEDURE
+2 ;;I;IMPRESSION
+3 ;;D;DIAGNOSTIC CODE
+4 ;;M;MODIFIERS
+5 ;;TCM;TECH COMMENT
+6 ;;C4;CPT MODIFIERS
+7 ;;R;REPORT