Home   Package List   Routine Alphabetical List   Global Alphabetical List   FileMan Files List   FileMan Sub-Files List   Package Component Lists   Package-Namespace Mapping  
Routine: RAHLTCPX

RAHLTCPX.m

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