| 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 | ; | 
|---|