| [1442] | 1 | C0QMUERX ; VEN - Analyze ERx Data for Patients ; 5/30/12 10:21am
 | 
|---|
 | 2 |  ;;1.0;C0Q;;May 21, 2012;Build 44
 | 
|---|
 | 3 |  QUIT  ; No Entry from the top
 | 
|---|
 | 4 |  ;
 | 
|---|
 | 5 | UT ; Unit Tests
 | 
|---|
 | 6 |  N C0QDEBUG S C0QDEBUG=1
 | 
|---|
 | 7 |  W "Testing ^DPT B Index",!
 | 
|---|
 | 8 |  D EN("^DPT(""B"")")
 | 
|---|
 | 9 |  W !,"Testing B Index on a C0Q Patient List",!
 | 
|---|
 | 10 |  D EN("^C0Q(301,4,1,""B"")")
 | 
|---|
 | 11 |  W !,"Testing ^AUPNPAT B Index",!
 | 
|---|
 | 12 |  D EN("^AUPNPAT(""B"")")
 | 
|---|
 | 13 |  W !,"Testing Reminder Patient List B Index",!
 | 
|---|
 | 14 |  D EN("^PXRMXP(810.5,80,30,""B"")")
 | 
|---|
 | 15 |  W !,"Testing upright file ^DPT",!
 | 
|---|
 | 16 |  D EN("^DPT")
 | 
|---|
 | 17 |  W !,"Testing a file with no data",!
 | 
|---|
 | 18 |  D EN("^ALKJSDF")
 | 
|---|
 | 19 |  W !,"Testing a no valid parameters",!
 | 
|---|
 | 20 |  D EN("")
 | 
|---|
 | 21 | UT2 ; Units Tests 2 
 | 
|---|
 | 22 |  N C0QDEBUG S C0QDEBUG=1
 | 
|---|
 | 23 |  D EN("^C0Q(301,4,1,""B"")")
 | 
|---|
 | 24 |  QUIT
 | 
|---|
 | 25 | UT3 ; Unit test 3
 | 
|---|
 | 26 |  N C0QDEBUG S C0QDEBUG=1
 | 
|---|
 | 27 |  N GN S GN=$NA(^C0Q(301,32,1,"B"))
 | 
|---|
 | 28 |  D EN(GN)
 | 
|---|
 | 29 |  Q
 | 
|---|
 | 30 |  ;
 | 
|---|
 | 31 | EN(C0QLIST) ; PEP - Analyze ERx Data and store
 | 
|---|
 | 32 |  ; Parameters:
 | 
|---|
 | 33 |  ; C0QLIST - Pass by Name. Global or Local Reference.
 | 
|---|
 | 34 |  ; Can be: ^DPT("B") for all patients or ^C0Q(301,2,1,"B") for a specific patient list
 | 
|---|
 | 35 |  ; Future: Can be a search template on file 2 or 9000001
 | 
|---|
 | 36 |  ;
 | 
|---|
 | 37 |  ; Check if XML Soap Message is installed
 | 
|---|
 | 38 |  I '$D(^C0PX("B","GETMEDS6")) WRITE "GETMEDS6 Soap Message not installed",! QUIT
 | 
|---|
 | 39 |  ;
 | 
|---|
 | 40 |  ; Check if SOAP^C0PWS2 exists
 | 
|---|
 | 41 |  I '$L($T(SOAP^C0PWS2)) WRITE "C0PWS2 Doesn't exist",! QUIT
 | 
|---|
 | 42 |  ;
 | 
|---|
 | 43 |  ; Check C0QLIST for sanity. Must be a single node.
 | 
|---|
 | 44 |  IF '($DATA(C0QLIST)#2)!(C0QLIST="") WRITE "You didn't pass the list",! QUIT
 | 
|---|
 | 45 |  ;
 | 
|---|
 | 46 |  ; Contents must be a Reference with Data
 | 
|---|
 | 47 |  IF '$DATA(@C0QLIST) WRITE "Destination doesn't contain any data",! QUIT
 | 
|---|
 | 48 |  ;
 | 
|---|
 | 49 |  ; Is this a B index?
 | 
|---|
 | 50 |  NEW C0QB
 | 
|---|
 | 51 |  IF $QSUBSCRIPT(C0QLIST,$QLENGTH(C0QLIST))="B" DO
 | 
|---|
 | 52 |  . SET C0QB=1
 | 
|---|
 | 53 |  . ; DEBUG
 | 
|---|
 | 54 |  . W:$G(C0QDEBUG) "B index passed",!
 | 
|---|
 | 55 |  . ; DEBUG
 | 
|---|
 | 56 |  ELSE  SET C0QB=0
 | 
|---|
 | 57 |  ;
 | 
|---|
 | 58 |  ; Make sure our TMP is empty
 | 
|---|
 | 59 |  K ^TMP($J)
 | 
|---|
 | 60 |  ;
 | 
|---|
 | 61 |  ; Walk the global
 | 
|---|
 | 62 |  N C0QWALK S C0QWALK=$SELECT(C0QB:"",'C0QB:0) ; Walker
 | 
|---|
 | 63 |  N C0QDONE S C0QDONE=0 ; Finish Flag
 | 
|---|
 | 64 |  FOR  SET C0QWALK=$O(@C0QLIST@(C0QWALK)) QUIT:C0QDONE  DO
 | 
|---|
 | 65 |  . ; Are we done?
 | 
|---|
 | 66 |  . I C0QB,C0QWALK="" S C0QDONE=1 QUIT  ; If in index and we are out, done
 | 
|---|
 | 67 |  . I 'C0QB,'+C0QWALK S C0QDONE=1 QUIT  ; If not in index and we are not numeric, done
 | 
|---|
 | 68 |  . ;
 | 
|---|
 | 69 |  . N C0QDFN ; DFN of Patient
 | 
|---|
 | 70 |  . ; If Walking B Index and Index not numeric, grab DFN (assuming ^DPT or ^AUPNPAT)
 | 
|---|
 | 71 |  . ; TODO: Should I check that the global is ^DPT or ^AUPNPAT?
 | 
|---|
 | 72 |  . I C0QB,'+C0QWALK S C0QDFN=$O(@C0QLIST@(C0QWALK,""))
 | 
|---|
 | 73 |  . ; Otherwise, we will assume the contents of the index are the DFNs
 | 
|---|
 | 74 |  . E  S C0QDFN=C0QWALK
 | 
|---|
 | 75 |  . I $G(C0QDEBUG) W C0QDFN," "
 | 
|---|
 | 76 |  . ;
 | 
|---|
 | 77 |  . ; Now, check to see if the patient has e-Rx's
 | 
|---|
 | 78 |  . I $$HASERX(C0QDFN) S ^TMP($J,C0QDFN)=""
 | 
|---|
 | 79 |  ;
 | 
|---|
 | 80 |  W:$G(C0QDEBUG) ! ;
 | 
|---|
 | 81 |  ;
 | 
|---|
 | 82 |  ; Loop through collected DFNs, send to WS, and get data back, store in ^TMP($J,DFN)
 | 
|---|
 | 83 |  N C0QDFN S C0QDFN=0
 | 
|---|
 | 84 |  F  S C0QDFN=$O(^TMP($J,C0QDFN)) Q:C0QDFN=""  DO
 | 
|---|
 | 85 |  . N C0POUT
 | 
|---|
 | 86 |  . W:$G(C0QDEBUG) "Calling GETMEDS6 SOAP Web Service Call for "_C0QDFN,!
 | 
|---|
 | 87 |  . D SOAP^C0PWS2("C0POUT","GETMEDS6",DUZ,C0QDFN)
 | 
|---|
 | 88 |  . Q:$G(C0POUT(1,"RowCount"))=0 ; WS says no data
 | 
|---|
 | 89 |  . M ^TMP($J,C0QDFN)=C0POUT
 | 
|---|
 | 90 |  ;
 | 
|---|
 | 91 |  ; From the New Crop Meaningful Use documentation:
 | 
|---|
 | 92 |  ; Appendix G: Meaningful Use Certification FAQ Question 10
 | 
|---|
 | 93 |  ;
 | 
|---|
 | 94 |  ; DENOMINATOR                        NUMERATOR
 | 
|---|
 | 95 |  ; DeaClassCode = 0, 9                DeaClassCode = 0, 9
 | 
|---|
 | 96 |  ; PharmacyType = 1                   PharmacyType = 1
 | 
|---|
 | 97 |  ; PharmacyDetailType = 1, 2          PharmacyDetailType = 1, 2
 | 
|---|
 | 98 |  ; FinalDestinationType = 1, 2, 3, 4  FinalDestinationType = 3, 4
 | 
|---|
 | 99 |  ; FinalStatusType = 1, 4, 5          FinalStatusType = 1, 5
 | 
|---|
 | 100 |  ;
 | 
|---|
 | 101 |  ; DeMorgan's Law
 | 
|---|
 | 102 |  ; NOT(A or B) = NOT(A) and NOT(B)
 | 
|---|
 | 103 |  ; So to collect prescriptions for which DeaClassCode is 0 or 9
 | 
|---|
 | 104 |  ; We exclude all those who are not 0 AND not 9.
 | 
|---|
 | 105 |  ; See: http://en.wikipedia.org/wiki/De_Morgan%27s_laws#Negation_of_a_disjunction
 | 
|---|
 | 106 |  ;
 | 
|---|
 | 107 |  ; The algorithms below use an Onion Peeling method. Any prescription which
 | 
|---|
 | 108 |  ; fails makes you jump to the next prescription.
 | 
|---|
 | 109 |  ; The "Onion levels" are:
 | 
|---|
 | 110 |  ; DeaClassCode, PharamcyType, PharmacyDetailType, FinalDestinationType, FinalStatusType
 | 
|---|
 | 111 |  ;
 | 
|---|
 | 112 |  ; Now walk through collected DFNs and accumulate MU stats
 | 
|---|
 | 113 |  ;
 | 
|---|
 | 114 |  ; WARNING: Naked References below
 | 
|---|
 | 115 |  ; 
 | 
|---|
 | 116 |  N C0QDFN,C0QRXNO S (C0QDFN,C0QRXNO)=0
 | 
|---|
 | 117 |  N C0QD S C0QD=0 ; Denominator
 | 
|---|
 | 118 |  ;
 | 
|---|
 | 119 |  ; Calculate Denominator below
 | 
|---|
 | 120 |  F  S C0QDFN=$O(^TMP($J,C0QDFN)) Q:C0QDFN=""  DO
 | 
|---|
 | 121 |  . F  S C0QRXNO=$O(^TMP($J,C0QDFN,C0QRXNO)) Q:C0QRXNO=""  DO
 | 
|---|
 | 122 |  .. W:$G(C0QDEBUG) "Patient "_C0QDFN_" Rx "_C0QRXNO,!
 | 
|---|
 | 123 |  .. ;
 | 
|---|
 | 124 |  .. I ^(C0QRXNO,"DeaClassCode") ; Change $REFERENCE
 | 
|---|
 | 125 |  .. ;
 | 
|---|
 | 126 |  .. N DEA S DEA=^("DeaClassCode")
 | 
|---|
 | 127 |  .. W:$G(C0QDEBUG) "DeaClassCode: "_DEA,!
 | 
|---|
 | 128 |  .. Q:((DEA'=0)&(DEA'=9))
 | 
|---|
 | 129 |  .. ;
 | 
|---|
 | 130 |  .. N PT S PT=^("PharmacyType")
 | 
|---|
 | 131 |  .. W:$G(C0QDEBUG) "PharmacyType: "_PT,!
 | 
|---|
 | 132 |  .. Q:(PT'=1)
 | 
|---|
 | 133 |  .. ;
 | 
|---|
 | 134 |  .. N PDT S PDT=^("PharmacyDetailType")
 | 
|---|
 | 135 |  .. W:$G(C0QDEBUG) "PharmacyDetailType: "_PDT,!
 | 
|---|
 | 136 |  .. Q:((PDT'=1)&(PDT'=2))
 | 
|---|
 | 137 |  .. ;
 | 
|---|
 | 138 |  .. N FDT S FDT=^("FinalDestinationType")
 | 
|---|
 | 139 |  .. W:$G(C0QDEBUG) "FinalDestinationType: "_FDT,!
 | 
|---|
 | 140 |  .. Q:((FDT'=1)&(FDT'=2)&(FDT'=3)&(FDT'=4))
 | 
|---|
 | 141 |  .. ;
 | 
|---|
 | 142 |  .. N FST S FST=^("FinalStatusType")
 | 
|---|
 | 143 |  .. W:$G(C0QDEBUG) "FinalStatusType: "_FST,!
 | 
|---|
 | 144 |  .. Q:((FST'=1)&(FST'=4)&(FST'=5))
 | 
|---|
 | 145 |  .. ;
 | 
|---|
 | 146 |  .. W:$G(C0QDEBUG) "Adding to Denominator",!
 | 
|---|
 | 147 |  .. S C0QD=C0QD+1
 | 
|---|
 | 148 |  ;
 | 
|---|
 | 149 |  ; Calculate Numerator below
 | 
|---|
 | 150 |  N C0QDFN,C0QRXNO S (C0QDFN,C0QRXNO)=0
 | 
|---|
 | 151 |  N C0QN S C0QN=0 ; Numerator
 | 
|---|
 | 152 |  F  S C0QDFN=$O(^TMP($J,C0QDFN)) Q:C0QDFN=""  DO
 | 
|---|
 | 153 |  . F  S C0QRXNO=$O(^TMP($J,C0QDFN,C0QRXNO)) Q:C0QRXNO=""  DO
 | 
|---|
 | 154 |  .. W:$G(C0QDEBUG) "Patient "_C0QDFN_" Rx "_C0QRXNO,!
 | 
|---|
 | 155 |  .. ;
 | 
|---|
 | 156 |  .. I ^(C0QRXNO,"DeaClassCode") ; Change $REFERENCE
 | 
|---|
 | 157 |  .. ;
 | 
|---|
 | 158 |  .. N DEA S DEA=^("DeaClassCode")
 | 
|---|
 | 159 |  .. W:$G(C0QDEBUG) "DeaClassCode: "_DEA,!
 | 
|---|
 | 160 |  .. Q:((DEA'=0)&(DEA'=9))
 | 
|---|
 | 161 |  .. ;
 | 
|---|
 | 162 |  .. N PT S PT=^("PharmacyType")
 | 
|---|
 | 163 |  .. W:$G(C0QDEBUG) "PharmacyType: "_PT,!
 | 
|---|
 | 164 |  .. Q:(PT'=1)
 | 
|---|
 | 165 |  .. ;
 | 
|---|
 | 166 |  .. N PDT S PDT=^("PharmacyDetailType")
 | 
|---|
 | 167 |  .. W:$G(C0QDEBUG) "PharmacyDetailType: "_PDT,!
 | 
|---|
 | 168 |  .. Q:((PDT'=1)&(PDT'=2))
 | 
|---|
 | 169 |  .. ;
 | 
|---|
 | 170 |  .. N FDT S FDT=^("FinalDestinationType")
 | 
|---|
 | 171 |  .. W:$G(C0QDEBUG) "FinalDestinationType: "_FDT,!
 | 
|---|
 | 172 |  .. Q:((FDT'=3)&(FDT'=4))
 | 
|---|
 | 173 |  .. ;
 | 
|---|
 | 174 |  .. N FST S FST=^("FinalStatusType")
 | 
|---|
 | 175 |  .. W:$G(C0QDEBUG) "FinalStatusType: "_FST,!
 | 
|---|
 | 176 |  .. Q:((FST'=1)&(FST'=5))
 | 
|---|
 | 177 |  .. ;
 | 
|---|
 | 178 |  .. W:$G(C0QDEBUG) "Adding to Numerator",!
 | 
|---|
 | 179 |  .. S C0QN=C0QN+1
 | 
|---|
 | 180 |  ;
 | 
|---|
 | 181 |  S ^TMP($J)=C0QN_U_C0QD
 | 
|---|
 | 182 |  ;
 | 
|---|
 | 183 |  ; TODO: Over here, do something with the numerator and denominator..
 | 
|---|
 | 184 |  ; Probably store them somewhere.
 | 
|---|
 | 185 |  ; 
 | 
|---|
 | 186 |  I '$G(C0QDEBUG) K ^TMP($J) ; Empty out in production not testing
 | 
|---|
 | 187 |  QUIT
 | 
|---|
 | 188 |  ;
 | 
|---|
 | 189 | HASERX(DFN) ; $$ - Private; Has E-Prescriptions?
 | 
|---|
 | 190 |  ; Parameters
 | 
|---|
 | 191 |  ; - DFN by Value
 | 
|---|
 | 192 |  ; Output
 | 
|---|
 | 193 |  ; 0 or 1 (false or true)
 | 
|---|
 | 194 |  N ZI S ZI=""
 | 
|---|
 | 195 |  N ZERX S ZERX=$NA(^PS(55,DFN,"NVA"))
 | 
|---|
 | 196 |  N DONE,HASERX
 | 
|---|
 | 197 |  F  S ZI=$O(@ZERX@(ZI)) Q:ZI=""  Q:$G(DONE)  D
 | 
|---|
 | 198 |  . I $G(@ZERX@(ZI,1,1,0))["E-Rx Web" S (DONE,HASERX)=1
 | 
|---|
 | 199 |  Q +$G(HASERX)
 | 
|---|