| 1 | PXRMLOG ; SLC/PKR - Clinical Reminders logic routines. ;06/12/2006
 | 
|---|
| 2 |  ;;2.0;CLINICAL REMINDERS;**4**;Feb 04, 2005;Build 21
 | 
|---|
| 3 |  ;==========================================================
 | 
|---|
| 4 | EVALPCL(DEFARR,PXRMPDEM,FREQ,PCLOGIC,FIEVAL) ;Evaluate the Patient Cohort
 | 
|---|
| 5 |  ;Logic.
 | 
|---|
| 6 |  ;Determine the applicable frequency age range set; get the baseline.
 | 
|---|
| 7 |  N AGEFI,IND,FINDING,FLIST,FREQDAY,MAXAGE,MINAGE,NODE,NUMAFI
 | 
|---|
| 8 |  N PCLOG,PCLSTR,RANKAR,RANK,RANKFI,TEMP,TEST
 | 
|---|
| 9 |  D MMF^PXRMAGE(.DEFARR,.PXRMPDEM,.MINAGE,.MAXAGE,.FREQ,.FIEVAL)
 | 
|---|
| 10 |  ;If there is no match with any of the baseline values FREQ=-1.
 | 
|---|
| 11 |  ;If there was no frequency in the definition then FREQ="".
 | 
|---|
| 12 |  ;See if any findings override the baseline.
 | 
|---|
| 13 |  S TEMP=DEFARR(40)
 | 
|---|
| 14 |  S NUMAFI=+$P(TEMP,U,1)
 | 
|---|
| 15 |  ;If there are no age findings use the baseline.
 | 
|---|
| 16 |  I NUMAFI=0 G ACHK
 | 
|---|
| 17 |  S FLIST=$P(TEMP,U,2)
 | 
|---|
| 18 |  F IND=1:1:NUMAFI D
 | 
|---|
| 19 |  . S FINDING=$P(FLIST,";",IND)
 | 
|---|
| 20 |  . I FIEVAL(FINDING) D
 | 
|---|
| 21 |  .. S NODE=$S(FINDING["FF":25,1:20)
 | 
|---|
| 22 |  .. S TEMP=DEFARR(NODE,FINDING,0)
 | 
|---|
| 23 |  .. S RANK=+$P(TEMP,U,5)
 | 
|---|
| 24 |  .. I RANK=0 S RANK=9999
 | 
|---|
| 25 |  .. S FREQDAY=$$FRQINDAY^PXRMDATE($P(TEMP,U,4))
 | 
|---|
| 26 |  ..;If there is no frequency with this rank ignore it.
 | 
|---|
| 27 |  .. I FREQDAY]"" S RANKAR(RANK,FREQDAY,FINDING)=""
 | 
|---|
| 28 |  ;If there was a ranking use it otherwise use the greatest frequency.
 | 
|---|
| 29 |  I '$D(RANKAR) G ACHK
 | 
|---|
| 30 |  S RANK=0
 | 
|---|
| 31 |  S RANK=+$O(RANKAR(RANK))
 | 
|---|
| 32 |  S FREQDAY=+$O(RANKAR(RANK,""))
 | 
|---|
| 33 |  S FINDING=$O(RANKAR(RANK,FREQDAY,""))
 | 
|---|
| 34 |  I FINDING'="" D
 | 
|---|
| 35 |  . S NODE=$S(FINDING["FF":25,1:20)
 | 
|---|
| 36 |  . S TEMP=DEFARR(NODE,FINDING,0)
 | 
|---|
| 37 |  . S FREQ=$P(TEMP,U,4)
 | 
|---|
| 38 |  . S MINAGE=$P(TEMP,U,2)
 | 
|---|
| 39 |  . S MAXAGE=$P(TEMP,U,3)
 | 
|---|
| 40 |  .;Remove the baseline age findings since they have been overridden.
 | 
|---|
| 41 |  . K FIEVAL("AGE")
 | 
|---|
| 42 | ACHK ;
 | 
|---|
| 43 |  I FREQ="" D
 | 
|---|
| 44 |  . S AGEFI=0
 | 
|---|
| 45 |  . S ^TMP(PXRMPID,$J,PXRMITEM,"INFO","NOFREQ")="There is no reminder frequency!"
 | 
|---|
| 46 |  E  D
 | 
|---|
| 47 |  .;Save the final frequency and age range for display.
 | 
|---|
| 48 |  .;Use the z so this will be the last of the info text.
 | 
|---|
| 49 |  . S ^TMP(PXRMPID,$J,PXRMITEM,"zFREQARNG")=FREQ_U_MINAGE_U_MAXAGE
 | 
|---|
| 50 |  . S AGEFI=$S(FREQ=-1:0,1:$$AGECHECK^PXRMAGE(PXRMPDEM("AGE"),MINAGE,MAXAGE))
 | 
|---|
| 51 |  S FIEVAL("AGE")=AGEFI
 | 
|---|
| 52 |  ;
 | 
|---|
| 53 |  ;Evaluate the patient cohort logic
 | 
|---|
| 54 | EVAL ;
 | 
|---|
| 55 |  N AGE,DPCLOG,FI,FF,FUN,FUNCTION,FUNLIST,NUM,SEX,VAR
 | 
|---|
| 56 |  S TEMP=DEFARR(32)
 | 
|---|
| 57 |  S NUM=+$P(TEMP,U,1)
 | 
|---|
| 58 |  S (PCLOG,PCLSTR)=DEFARR(31)
 | 
|---|
| 59 |  S FLIST=$P(TEMP,U,2)
 | 
|---|
| 60 |  F IND=1:1:NUM D
 | 
|---|
| 61 |  . S FINDING=$P(FLIST,";",IND)
 | 
|---|
| 62 |  . I FINDING="AGE" S AGE=+$G(FIEVAL("AGE"))
 | 
|---|
| 63 |  . I FINDING="SEX" S SEX=+$G(FIEVAL("SEX"))
 | 
|---|
| 64 |  . I FINDING["FF" S TEMP=$P(FINDING,"FF",2),FF(TEMP)=FIEVAL(FINDING)
 | 
|---|
| 65 |  . E  S FI(FINDING)=FIEVAL(FINDING)
 | 
|---|
| 66 |  I @PCLOG
 | 
|---|
| 67 |  S TEST=$T
 | 
|---|
| 68 |  I 'AGEFI,PCLSTR["AGE" D
 | 
|---|
| 69 |  . S ^TMP(PXRMPID,$J,PXRMITEM,"N/A","AGE")=""
 | 
|---|
| 70 |  . S ^TMP(PXRMPID,$J,PXRMITEM,"INFO","AGE")="Patient does not meet any age criteria!"
 | 
|---|
| 71 |  ;Reminders are always N/A for dead patients unless PXRMIDOD is true in which case
 | 
|---|
| 72 |  ;the regular cohort logic applies.
 | 
|---|
| 73 |  I '$G(PXRMIDOD),PXRMPDEM("DOD")'="" S TEST=0
 | 
|---|
| 74 |  S PCLOGIC=TEST_U_PCLSTR
 | 
|---|
| 75 |  I 'TEST S ^TMP(PXRMPID,$J,PXRMITEM,"N/A","COHORT")=""
 | 
|---|
| 76 |  I $G(PXRMDEBG) D
 | 
|---|
| 77 |  . S DPCLOG=PCLOG
 | 
|---|
| 78 |  . F IND=1:1:NUM D
 | 
|---|
| 79 |  .. S FINDING=$P(FLIST,";",IND)
 | 
|---|
| 80 |  .. I FINDING="AGE" S DPCLOG=$$STRREP^PXRMUTIL(DPCLOG,"AGE",+$G(FIEVAL(FINDING))) Q
 | 
|---|
| 81 |  .. I FINDING="SEX" S DPCLOG=$$STRREP^PXRMUTIL(DPCLOG,"SEX",+$G(FIEVAL(FINDING))) Q
 | 
|---|
| 82 |  .. S TEMP=$S(FINDING["FF":"FF("_$P(FINDING,"FF",2)_")",1:"FI("_FINDING_")")
 | 
|---|
| 83 |  .. S DPCLOG=$$STRREP^PXRMUTIL(DPCLOG,TEMP,FIEVAL(FINDING))
 | 
|---|
| 84 |  S PCLOGIC=PCLOGIC_U_$G(DPCLOG)
 | 
|---|
| 85 |  I $G(PXRMDEBG) S ^TMP(PXRMPID,$J,PXRMITEM,"PATIENT COHORT LOGIC")=PCLOGIC
 | 
|---|
| 86 |  Q
 | 
|---|
| 87 |  ;
 | 
|---|
| 88 |  ;==========================================================
 | 
|---|
| 89 | EVALRESL(DEFARR,RESDATE,RESLOGIC,FIEVAL) ;Evaluate the
 | 
|---|
| 90 |  ;Resolution Logic.
 | 
|---|
| 91 |  N DRESLOG,IND,FF,FI,FINDING,FLIST,NUM,RESLOG,RESLSTR,TEMP,TEST
 | 
|---|
| 92 |  S TEMP=DEFARR(36)
 | 
|---|
| 93 |  S NUM=+$P(TEMP,U,1)
 | 
|---|
| 94 |  I NUM=0 Q
 | 
|---|
| 95 |  S (RESLOG,RESLSTR)=DEFARR(35)
 | 
|---|
| 96 |  S FLIST=$P(TEMP,U,2)
 | 
|---|
| 97 |  F IND=1:1:NUM D
 | 
|---|
| 98 |  . S FINDING=$P(FLIST,";",IND)
 | 
|---|
| 99 |  .;Check for contraindicated in a resolution finding
 | 
|---|
| 100 |  . I $G(FIEVAL(FINDING,"CONTRAINDICATED")) S FIEVAL("CONTRAINDICATED")=1
 | 
|---|
| 101 |  . I FINDING["FF" S TEMP=$P(FINDING,"FF",2),FF(TEMP)=FIEVAL(FINDING)
 | 
|---|
| 102 |  . E  S FI(FINDING)=FIEVAL(FINDING)
 | 
|---|
| 103 |  I @RESLOG
 | 
|---|
| 104 |  S TEST=$T
 | 
|---|
| 105 |  I $G(PXRMDEBG) D
 | 
|---|
| 106 |  . S DRESLOG=RESLOG
 | 
|---|
| 107 |  . F IND=1:1:NUM D
 | 
|---|
| 108 |  .. S FINDING=$P(FLIST,";",IND)
 | 
|---|
| 109 |  .. S TEMP=$S(FINDING["FF":"FF("_$P(FINDING,"FF",2)_")",1:"FI("_FINDING_")")
 | 
|---|
| 110 |  .. S DRESLOG=$$STRREP^PXRMUTIL(DRESLOG,TEMP,FIEVAL(FINDING))
 | 
|---|
| 111 |  S RESLOGIC=TEST_U_RESLSTR_U_$G(DRESLOG)
 | 
|---|
| 112 |  I $G(PXRMDEBG) S ^TMP(PXRMPID,$J,PXRMITEM,"RESOLUTION LOGIC")=RESLOGIC
 | 
|---|
| 113 |  S RESDATE=$S(TEST=1:$$RESDATE(RESLSTR,.FIEVAL),1:0)
 | 
|---|
| 114 |  Q
 | 
|---|
| 115 |  ;
 | 
|---|
| 116 |  ;==========================================================
 | 
|---|
| 117 | LOGOP(DT1,DT2,LOP) ;Given two dates return the most recent if the logical
 | 
|---|
| 118 |  ;operator is ! and the oldest if it is &. True FFs which don't have
 | 
|---|
| 119 |  ;a date are flagged with date of -1.
 | 
|---|
| 120 |  I DT1=0,DT2=0 Q 0
 | 
|---|
| 121 |  I DT1=-1,DT2=-1 Q -1
 | 
|---|
| 122 |  N VALUE
 | 
|---|
| 123 |  I LOP="&" D  Q VALUE
 | 
|---|
| 124 |  . I DT1=-1 S VALUE=DT2 Q
 | 
|---|
| 125 |  . I DT2=-1 S VALUE=DT1 Q
 | 
|---|
| 126 |  . I DT1=0 S VALUE=DT2 Q
 | 
|---|
| 127 |  . I DT2=0 S VALUE=DT1 Q
 | 
|---|
| 128 |  . S VALUE=$S(DT1>DT2:DT2,1:DT1)
 | 
|---|
| 129 |  I LOP'="!" Q 0
 | 
|---|
| 130 |  I DT1=-1 Q $S(DT2>0:DT2,1:-1)
 | 
|---|
| 131 |  I DT2=-1 Q $S(DT1>0:DT1,1:-1)
 | 
|---|
| 132 |  Q $S(DT1>DT2:DT1,1:DT2)
 | 
|---|
| 133 |  ;
 | 
|---|
| 134 |  ;==========================================================
 | 
|---|
| 135 | RESDATE(RESLSTR,FIEVAL) ;Return the resolution date based on the following
 | 
|---|
| 136 |  ;rules:
 | 
|---|
| 137 |  ; Dates that are ORed use the most recent.
 | 
|---|
| 138 |  ; Dates that are ANDed use the oldest.
 | 
|---|
| 139 |  ;This is only evaluated if the resolution logic is true.
 | 
|---|
| 140 |  N DATE,DSTRING,DT1,DT2,DT3,FFI,IND,INDEX,JND
 | 
|---|
| 141 |  N OPER,PFSTACK,STACK,TEMP
 | 
|---|
| 142 |  ;Remove leading (n) entries.
 | 
|---|
| 143 |  I ($E(RESLSTR,1,4)="(0)!")!($E(RESLSTR,1,4)="(1)&") S $E(RESLSTR,1,4)=""
 | 
|---|
| 144 |  ;The NOT operator is not relevant for the date calculation so remove
 | 
|---|
| 145 |  ;any NOTs.
 | 
|---|
| 146 |  S DSTRING=$TR(RESLSTR,"'","")
 | 
|---|
| 147 |  ;Replace true findings with their dates. This includes false findings
 | 
|---|
| 148 |  ;that are notted in the logic.
 | 
|---|
| 149 |  S OPER="!&"
 | 
|---|
| 150 |  D POSTFIX^PXRMSTAC(DSTRING,OPER,.PFSTACK)
 | 
|---|
| 151 |  S JND=0
 | 
|---|
| 152 |  F IND=1:1:PFSTACK(0) D
 | 
|---|
| 153 |  . S TEMP=PFSTACK(IND)
 | 
|---|
| 154 |  . I TEMP="FI" D  Q
 | 
|---|
| 155 |  .. S IND=IND+1,INDEX=PFSTACK(IND)
 | 
|---|
| 156 |  .. S DATE=$S(FIEVAL(INDEX)=1:FIEVAL(INDEX,"DATE"),1:0)
 | 
|---|
| 157 |  .. S JND=JND+1,STACK(JND)=DATE
 | 
|---|
| 158 |  . I TEMP="FF" D  Q
 | 
|---|
| 159 |  .. S IND=IND+1,INDEX=PFSTACK(IND)
 | 
|---|
| 160 |  .. S FFI="FF"_INDEX
 | 
|---|
| 161 |  ..;FFs do not have dates, flag with -1.
 | 
|---|
| 162 |  .. S DATE=-1
 | 
|---|
| 163 |  .. S JND=JND+1,STACK(JND)=DATE
 | 
|---|
| 164 |  . I OPER[TEMP S JND=JND+1,STACK(JND)=TEMP
 | 
|---|
| 165 |  S STACK(0)=JND
 | 
|---|
| 166 |  K PFSTACK
 | 
|---|
| 167 |  S PFSTACK(0)=0
 | 
|---|
| 168 |  F IND=1:1:STACK(0) D
 | 
|---|
| 169 |  . S TEMP=STACK(IND)
 | 
|---|
| 170 |  . I OPER[TEMP D
 | 
|---|
| 171 |  ..;Pop the top two elements on the stack and do the operation.
 | 
|---|
| 172 |  .. S DT1=$$POP^PXRMSTAC(.PFSTACK)
 | 
|---|
| 173 |  .. S DT2=$$POP^PXRMSTAC(.PFSTACK)
 | 
|---|
| 174 |  .. S DT3=$$LOGOP(DT1,DT2,TEMP)
 | 
|---|
| 175 |  ..;Save the result back on the stack
 | 
|---|
| 176 |  .. D PUSH^PXRMSTAC(.PFSTACK,DT3)
 | 
|---|
| 177 |  . E  D PUSH^PXRMSTAC(.PFSTACK,TEMP)
 | 
|---|
| 178 |  ;The result is the only thing left on the stack.
 | 
|---|
| 179 |  Q $$POP^PXRMSTAC(.PFSTACK)
 | 
|---|
| 180 |  ;
 | 
|---|
| 181 |  ;==========================================================
 | 
|---|
| 182 | SEX(DEFARR,SEX) ;Return FALSE (0) if the patient is the wrong sex for
 | 
|---|
| 183 |  ; the reminder, TRUE (1) is the patient is the right sex.
 | 
|---|
| 184 |  N REMSEX
 | 
|---|
| 185 |  S REMSEX=$P(DEFARR(0),U,9)
 | 
|---|
| 186 |  I REMSEX="" Q 1
 | 
|---|
| 187 |  I SEX=REMSEX Q 1
 | 
|---|
| 188 |  S ^TMP(PXRMPID,$J,PXRMITEM,"N/A","SEX")=""
 | 
|---|
| 189 |  S ^TMP(PXRMPID,$J,PXRMITEM,"INFO","SEX")="Patient is the wrong sex!"
 | 
|---|
| 190 |  Q 0
 | 
|---|
| 191 |  ;
 | 
|---|
| 192 |  ;==========================================================
 | 
|---|
| 193 | VALID(LOGSTR,DA,MINLEN,MAXLEN) ;Make sure that LOGSTR is a valid logic string.
 | 
|---|
| 194 |  ;This is called by the input transform for PATIENT COHORT LOGIC and
 | 
|---|
| 195 |  ;RESOLUTION LOGIC. Return 1 if LOGSTR is ok.
 | 
|---|
| 196 |  ;Don't do this if this is being called as a result of an install
 | 
|---|
| 197 |  ;through the Exchange Utility.
 | 
|---|
| 198 |  I $G(PXRMEXCH) Q 1
 | 
|---|
| 199 |  I LOGSTR="" Q 0
 | 
|---|
| 200 |  ;
 | 
|---|
| 201 |  ;Check the length.
 | 
|---|
| 202 |  N LEN
 | 
|---|
| 203 |  S LEN=$L(LOGSTR)
 | 
|---|
| 204 |  I (LEN<MINLEN)!(LEN>MAXLEN) Q 0
 | 
|---|
| 205 |  ;
 | 
|---|
| 206 |  ;Use the FileMan code validator to check the code.
 | 
|---|
| 207 |  N TEST,X
 | 
|---|
| 208 |  S X="S Y="_$TR(LOGSTR,";","")
 | 
|---|
| 209 |  D ^DIM
 | 
|---|
| 210 |  I $D(X)=0 D  Q 0
 | 
|---|
| 211 |  . S TEXT(1)="LOGIC string: "_LOGSTR
 | 
|---|
| 212 |  . S TEXT(2)="contains invalid MUMPS code!"
 | 
|---|
| 213 |  . D EN^DDIOL(.TEXT)
 | 
|---|
| 214 |  ;
 | 
|---|
| 215 |  N ELE1,ELE2,MNUM,SEP,STACK,TEXT,TSTSTR,VALID
 | 
|---|
| 216 |  ;Make sure the entries in LOGSTR are valid elements or functions.
 | 
|---|
| 217 |  S TSTSTR=LOGSTR
 | 
|---|
| 218 |  S TSTSTR=$TR(TSTSTR,"'","")
 | 
|---|
| 219 |  S TSTSTR=$TR(TSTSTR,"&",U)
 | 
|---|
| 220 |  S TSTSTR=$TR(TSTSTR,"!",U)
 | 
|---|
| 221 |  ;Set the allowable logic separators.
 | 
|---|
| 222 |  S SEP="^,<>="
 | 
|---|
| 223 |  ;Convert the string to postfix form for evaluation.
 | 
|---|
| 224 |  D POSTFIX^PXRMSTAC(TSTSTR,SEP,.STACK)
 | 
|---|
| 225 |  S (ELE1,VALID)=1
 | 
|---|
| 226 |  F  Q:(ELE1="")!(VALID=0)  D
 | 
|---|
| 227 |  . S ELE1=$$POP^PXRMSTAC(.STACK)
 | 
|---|
| 228 |  . I SEP[ELE1 Q
 | 
|---|
| 229 |  .;If the element is FI or FF then the next element should be a number.
 | 
|---|
| 230 |  . S MNUM=$S(ELE1="FI":20,ELE1="FF":25,1:"")
 | 
|---|
| 231 |  . I MNUM'="" D
 | 
|---|
| 232 |  .. S ELE2=$$POP^PXRMSTAC(.STACK)
 | 
|---|
| 233 |  .. I ELE2'=+ELE2 S VALID=0
 | 
|---|
| 234 |  .. I VALID S VALID=$D(^PXD(811.9,DA,MNUM,ELE2))
 | 
|---|
| 235 |  .. I 'VALID D
 | 
|---|
| 236 |  ... S TEXT=ELE1_"("_ELE2_") is not in this definition!"
 | 
|---|
| 237 |  ... D EN^DDIOL(TEXT)
 | 
|---|
| 238 |  Q VALID
 | 
|---|
| 239 |  ;
 | 
|---|
| 240 |  ;==========================================================
 | 
|---|
| 241 | VALIDR(LOGSTR,DA,MINLEN,MAXLEN) ;Make sure that LOGSTR is a valid resolution 
 | 
|---|
| 242 |  ;logic string. This is called by the input transform for RESOLUTION
 | 
|---|
| 243 |  ;LOGIC. Return 1 if LOGSTR is ok.
 | 
|---|
| 244 |  ;Don't do this if this is being called as a result of an install
 | 
|---|
| 245 |  ;through the Exchange Utility.
 | 
|---|
| 246 |  I $G(PXRMEXCH) Q 1
 | 
|---|
| 247 |  I LOGSTR="" Q 0
 | 
|---|
| 248 |  N TEXT
 | 
|---|
| 249 |  ;The resolution logic cannot contain SEX or AGE.
 | 
|---|
| 250 |  I LOGSTR["AGE" D  Q 0
 | 
|---|
| 251 |  . S TEXT="The resolution logic cannot contain AGE!"
 | 
|---|
| 252 |  . D EN^DDIOL(TEXT)
 | 
|---|
| 253 |  I LOGSTR["SEX" D  Q 0
 | 
|---|
| 254 |  . S TEXT="The resolution logic cannot contain SEX!"
 | 
|---|
| 255 |  . D EN^DDIOL(TEXT)
 | 
|---|
| 256 |  ;Now call the regular logic string validator.
 | 
|---|
| 257 |  Q $$VALID(LOGSTR,DA,MINLEN,MAXLEN)
 | 
|---|
| 258 |  ;
 | 
|---|