1 | C0QQRDA ; GPL - Quality Reporting QRDA Processing ; 8/2/12 10:15am
|
---|
2 | ;;1.0;QUALITY MEASURES;**4**;May 21, 2012;Build 28
|
---|
3 | ;Copyright 2012 George Lilly. Licensed under the terms of the GNU
|
---|
4 | ;General Public License See attached copy of the License.
|
---|
5 | ;
|
---|
6 | ;This program is free software; you can redistribute it and/or modify
|
---|
7 | ;it under the terms of the GNU General Public License as published by
|
---|
8 | ;the Free Software Foundation; either version 2 of the License, or
|
---|
9 | ;(at your option) any later version.
|
---|
10 | ;
|
---|
11 | ;This program is distributed in the hope that it will be useful,
|
---|
12 | ;but WITHOUT ANY WARRANTY; without even the implied warranty of
|
---|
13 | ;MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
---|
14 | ;GNU General Public License for more details.
|
---|
15 | ;
|
---|
16 | ;You should have received a copy of the GNU General Public License along
|
---|
17 | ;with this program; if not, write to the Free Software Foundation, Inc.,
|
---|
18 | ;51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
---|
19 | ;
|
---|
20 | EN ; Private to this Package; Main Entry Point for this routine
|
---|
21 | ; This EP is interactive or silent depending on params
|
---|
22 | ;
|
---|
23 | ; Check for config errors first; try to set-up.
|
---|
24 | N % S %=$$CHECKPAR()
|
---|
25 | I +%=1 D EN^DDIOL($P(%,U,2)) QUIT ; No inpatient pars found... QUIT
|
---|
26 | I +%=2 D ; No QRDA Measure Sets... try to set it up.
|
---|
27 | . D EN^DDIOL("Trying to automatically set-up measure sets in parameters")
|
---|
28 | . N % S %=$$SETUPPAR($$INPPARM())
|
---|
29 | . I % D EN^DDIOL("Failed to set-up..."_$P(%,U,2))
|
---|
30 | . E D EN^DDIOL("...Set-up complete")
|
---|
31 | ;
|
---|
32 | ; Print Intro
|
---|
33 | N %
|
---|
34 | S %(1)="This program collects patients from the denominators of the measures"
|
---|
35 | S %(2)="STK, VTE, and ED and outputs modified CCR files to the kernel default"
|
---|
36 | S %(3)="directory (probably /tmp/)."
|
---|
37 | S %(4)=""
|
---|
38 | S %(5)="This will take some time to execute."
|
---|
39 | S %(6)=""
|
---|
40 | S %(6,"F")="!!!"
|
---|
41 | ;
|
---|
42 | D EN^DDIOL(.%)
|
---|
43 | ;
|
---|
44 | ; Ask user which measure set to run
|
---|
45 | N DIR,DTOUT,DUOUT,X,Y,DIRUT,DIROUT,DA ; DIR variables
|
---|
46 | S DIR(0)="SB^V:VTE;S:STK;E:ED;A:ALL"
|
---|
47 | S DIR("A")="Measure to calculate"
|
---|
48 | S DIR("A",1)="Which measure set would you like to produce QRDA documents for?"
|
---|
49 | S DIR("A",2)="Choose to Run [V]TE Measure Set, [S]TK Measure Set, or "
|
---|
50 | S DIR("A",3)="[E]D Measure Set. Or you can choose to run [A]ll of them."
|
---|
51 | D ^DIR
|
---|
52 | ;
|
---|
53 | I $G(DTOUT)!$G(DUOUT) QUIT ; Did user hit '^' or time out?
|
---|
54 | ;
|
---|
55 | ; Get the Measure Set IEN which the user has seleted.
|
---|
56 | ; NB: field names start with VTE, STK, or ED; so I can use the output
|
---|
57 | ; of DIR directly.
|
---|
58 | ;
|
---|
59 | N FLD S FLD=Y(0) ; Grab full text of user choice into var "FLD" for field.
|
---|
60 | N C0QMSIENS ; Measure set IENs (^ piece); (0) stores the identifier for file names
|
---|
61 | ;looks like this in the end
|
---|
62 | ; C0QMSIENS=1^3^5
|
---|
63 | ; C0QMSIENS(0)="ED^VTE^STK"
|
---|
64 | ;
|
---|
65 | N INPPARM S INPPARM=$$INPPARM() ; Inpatient Parameter IEN in 401
|
---|
66 | ;
|
---|
67 | ; If not all, grab the measure; else, grab all of them in ^ pieces
|
---|
68 | I FLD'="ALL" D
|
---|
69 | . S C0QMSIENS=$$GET1^DIQ(1130580001.401,INPPARM,FLD,"I")
|
---|
70 | . S C0QMSIENS(0)=FLD
|
---|
71 | ;
|
---|
72 | E D
|
---|
73 | . N C0QED S C0QED=$$GET1^DIQ(1130580001.401,INPPARM,"ED","I")
|
---|
74 | . N C0QVTE S C0QVTE=$$GET1^DIQ(1130580001.401,INPPARM,"VTE","I")
|
---|
75 | . N C0QSTK S C0QSTK=$$GET1^DIQ(1130580001.401,INPPARM,"STK","I")
|
---|
76 | . S C0QMSIENS=C0QED_U_C0QVTE_U_C0QSTK
|
---|
77 | . S C0QMSIENS(0)="ED"_U_"VTE"_U_"STK"
|
---|
78 | ;
|
---|
79 | ;
|
---|
80 | S:'C0QMSIENS $EC=",U1," ; Debug.Assert that MSIEN is numeric.
|
---|
81 | ;
|
---|
82 | ;
|
---|
83 | ; Do the work
|
---|
84 | N C0QI ; Counter through the measures
|
---|
85 | F C0QI=1:1:$L(C0QMSIENS,U) D
|
---|
86 | . N MSIEN S MSIEN=$P(C0QMSIENS,U,C0QI) ; Measure Set IEN
|
---|
87 | . N MSNAME S MSNAME=$P(C0QMSIENS(0),U,C0QI) ; Measure Set Name
|
---|
88 | . N REF S REF=$NAME(^TMP("C0QQRDA",$J)) ; Global for data collection
|
---|
89 | . K @REF ; Clear global
|
---|
90 | . D WORK(REF,MSIEN) ; Process Measure Set, collect data in global
|
---|
91 | . D PRINTXML(REF,MSNAME) ; Generate XML; output to File.
|
---|
92 | . K @REF ; Clear global
|
---|
93 | QUIT
|
---|
94 | ;
|
---|
95 | ;SILENTEN(RETURN) ; For future RPC calls...; needs to be reworked.
|
---|
96 | ; N % S %=$$CHECKPAR()
|
---|
97 | ; I % S RETURN(0)=% Q
|
---|
98 | ;
|
---|
99 | ; N DIQUIET S DIQUIET=1
|
---|
100 | ; D EN
|
---|
101 | ; S RETURN(0)=0
|
---|
102 | ; QUIT
|
---|
103 | ;
|
---|
104 | CHECKPAR() ; Private Proc; Check if environment is okay.
|
---|
105 | ; Output: 0 or +ve^message for error
|
---|
106 | ; 1 -> No Inpatient Parameters found
|
---|
107 | ; 2 -> Measurement Set(s) not found.
|
---|
108 | ;
|
---|
109 | N INPPARM S INPPARM=$$INPPARM() ; Inpatient Parameters IEN
|
---|
110 | I 'INPPARM Q 1_U_"No Inpatient Parameters found"
|
---|
111 | ;
|
---|
112 | ; Pointer fields to Measurement Set file, we grab the IENs
|
---|
113 | N C0QED S C0QED=$$GET1^DIQ(1130580001.401,INPPARM,"ED","I")
|
---|
114 | N C0QSTK S C0QSTK=$$GET1^DIQ(1130580001.401,INPPARM,"STK","I")
|
---|
115 | N C0QVTE S C0QVTE=$$GET1^DIQ(1130580001.401,INPPARM,"VTE","I")
|
---|
116 | ;
|
---|
117 | N TXT S TXT="" ; Error text
|
---|
118 | I 'C0QED S TXT=TXT_"ED,"
|
---|
119 | I 'C0QSTK S TXT=TXT_"STK,"
|
---|
120 | I 'C0QVTE S TXT=TXT_"VTE"
|
---|
121 | I $E(TXT,$L(TXT))="," S TXT=$E(TXT,1,$L(TXT)-1) ; remove trailing comma
|
---|
122 | I $L(TXT) Q 2_U_"Measure Sets missing from parameters: "_TXT
|
---|
123 | ;
|
---|
124 | QUIT 0 ; All okay
|
---|
125 | ;
|
---|
126 | SETUPPAR(INPPARM) ; Private Proc; Set-up QRDA lists if Inpatient Param is found.
|
---|
127 | ; Input: Inpatient Parameter IEN in C0Q(401, -> C0Q Parameters
|
---|
128 | ; Output: 0 if okay or 1^error description
|
---|
129 | N C0QFDA
|
---|
130 | ;
|
---|
131 | N VTEIEN S VTEIEN=$O(^C0Q(201,"B","VTE CMS REPORTING MEASURES",""))
|
---|
132 | I 'VTEIEN QUIT 1_U_"VTE not found"
|
---|
133 | N STKIEN S STKIEN=$O(^C0Q(201,"B","STK CMS REPORTING MEASURES",""))
|
---|
134 | I 'STKIEN QUIT 1_U_"STK not found"
|
---|
135 | N EDIEN S EDIEN=$O(^C0Q(201,"B","ED CMS REPORTING MEASURES",""))
|
---|
136 | I 'EDIEN QUIT 1_U_"ED not found"
|
---|
137 | ;
|
---|
138 | S C0QFDA(1130580001.401,INPPARM_",",5.1)=VTEIEN
|
---|
139 | S C0QFDA(1130580001.401,INPPARM_",",5.2)=STKIEN
|
---|
140 | S C0QFDA(1130580001.401,INPPARM_",",5.3)=EDIEN
|
---|
141 | ;
|
---|
142 | N C0QERR
|
---|
143 | D FILE^DIE("",$NA(C0QFDA),$NA(C0QERR))
|
---|
144 | I $D(C0QERR) Q 2_U_C0QERR("DIERR",1,"TEXT",1)
|
---|
145 | Q 0
|
---|
146 | ;
|
---|
147 | WORK(C0QREF,C0QMSIEN) ; Private Proc; Process Measure Sets; Collect the data.
|
---|
148 | ; Input/Output: C0QREF -> Global for Output passed by Name
|
---|
149 | ; C0QMSIEN -> (Input): Measurement Set IEN to calculate
|
---|
150 | ;
|
---|
151 | ; Print
|
---|
152 | D EN^DDIOL(C0QMSIEN_": "_^C0Q(201,C0QMSIEN,0))
|
---|
153 | D EN^DDIOL("")
|
---|
154 | ;
|
---|
155 | ; Calculate totals and move patients over from individual measures
|
---|
156 | N A
|
---|
157 | D UPDATE^C0QUPDT(.A,C0QMSIEN) ; FYI: A isn't used.
|
---|
158 | ;
|
---|
159 | ; Get QRDA code for Measure Set.
|
---|
160 | N C0QMSQRDA S C0QMSQRDA=$$GET1^DIQ($$C0QMFN^C0QUPDT(),C0QMSIEN_",","QRDA TEMPLATE ROOT")
|
---|
161 | ;
|
---|
162 | N C0QI S C0QI=0 ; Fileman IEN looper
|
---|
163 | F S C0QI=$O(^C0Q(201,C0QMSIEN,5,C0QI)) Q:'C0QI D ; For each measure in Measure Set
|
---|
164 | . ;
|
---|
165 | . ; Get QRDA code using relational jump
|
---|
166 | . N C0QMEASUREQRDA S C0QMEASUREQRDA=$$GET1^DIQ($$C0QMMFN^C0QUPDT(),C0QI_","_C0QMSIEN_",",".01:QRDA TEMPLATE ROOT")
|
---|
167 | . ;
|
---|
168 | . ; Then collect patients in the denominator, and store in output global
|
---|
169 | . N C0QP S C0QP=0
|
---|
170 | . F S C0QP=$O(^C0Q(201,C0QMSIEN,5,C0QI,3,C0QP)) Q:'C0QP D ; For each patient in denominator
|
---|
171 | . . N C0QDFN S C0QDFN=+^(C0QP,0)
|
---|
172 | . . S @C0QREF@(C0QDFN,C0QMSQRDA,C0QMEASUREQRDA)=""
|
---|
173 | QUIT
|
---|
174 | ;
|
---|
175 | INPPARM() ; $$ Private; Get Inpatient Parameters IEN
|
---|
176 | ; Output: IEN of Inpatient Parameter in C0Q PARAMETER file
|
---|
177 | ;
|
---|
178 | ; Browse this tree of xrefs to get the IEN of INP type (last line here).
|
---|
179 | ; ^C0Q(401,"B","INPATIENT",2)=""
|
---|
180 | ; ^C0Q(401,"B","OUTPATIENT",1)=""
|
---|
181 | ; ^C0Q(401,"MU","MU12",1)=""
|
---|
182 | ; ^C0Q(401,"MU","MU12",2)=""
|
---|
183 | ; ^C0Q(401,"MUTYP","MU12","EP",1)=""
|
---|
184 | ; ^C0Q(401,"MUTYP","MU12","INP",2)=""
|
---|
185 | ;
|
---|
186 | N MUID S MUID="" ; Looper for MU Year ID
|
---|
187 | N FOUND S FOUND=0 ; Found flag to get out of loop
|
---|
188 | N IEN ; Output variable
|
---|
189 | F S MUID=$O(^C0Q(401,"MUTYP",MUID),-1) Q:MUID="" Q:FOUND D ; Loop backwards
|
---|
190 | . N TYP S TYP="" ; Type ("EP" or "INP")
|
---|
191 | . F S TYP=$O(^C0Q(401,"MUTYP",MUID,TYP)) Q:TYP="" Q:FOUND D
|
---|
192 | . . I TYP="INP" S IEN=$O(^(TYP,"")),FOUND=1 Q ; If found, get IEN, quit out of loops
|
---|
193 | QUIT +$G(IEN)
|
---|
194 | ;
|
---|
195 | PRINTXML(C0QREF,C0QMNM) ; Print the XML; Private Proc
|
---|
196 | ; Input: C0QREF -> Global By Name
|
---|
197 | ; C0QMNM -> Measure Name -> Either VTE, STK, ED. For use in filenames.
|
---|
198 | ; Output: modified CCRs are saved in /tmp/
|
---|
199 | N C0QDFN,C0QMS,C0QM S (C0QDFN,C0QMS,C0QM)="" ; DFN, Measure Set, Measure loopers
|
---|
200 | F S C0QDFN=$O(@C0QREF@(C0QDFN)) Q:C0QDFN="" D ; For each patient
|
---|
201 | . ;
|
---|
202 | . N GREEN S GREEN=$C(27)_"[1;37;42m"
|
---|
203 | . N RESET S RESET=$C(27)_"[0m"
|
---|
204 | . D EN^DDIOL(GREEN_"Prosessing DFN "_C0QDFN_RESET,"","!!!")
|
---|
205 | . D EN^DDIOL("","","!")
|
---|
206 | . ;
|
---|
207 | . ; CCR Generatation is next; protected against crashes.
|
---|
208 | . ; ET set to new value then restored.
|
---|
209 | . N C0QCCRXML ; CCR XML
|
---|
210 | . N OLDTRAP S OLDTRAP=$ET
|
---|
211 | . ; ET: Rollback to this level, write the error in red , clear it, then quit
|
---|
212 | . N ETTEXT S ETTEXT=$C(27)_"[1;37;41m"_$$EC^%ZOSV_$C(27)_RESET
|
---|
213 | . N $ES,$ET
|
---|
214 | . S $ET="W ETTEXT D ^%ZTER G ROLLDOWN^C0QQRDA"
|
---|
215 | . D CCRRPC^C0CCCR(.C0QCCRXML,C0QDFN) ; Run CCR RPC.
|
---|
216 | . S $ET=OLDTRAP
|
---|
217 | . ;
|
---|
218 | . ;
|
---|
219 | . ; Quality XML Section generated by hand next...
|
---|
220 | . N C0QXML ; Generated Quality XML
|
---|
221 | . D XMLSTORE(.C0QXML,$$OT("QUALITY")) ; Open Tag
|
---|
222 | . F S C0QMS=$O(@C0QREF@(C0QDFN,C0QMS)) Q:C0QMS="" D ; For each measure set
|
---|
223 | . . D XMLSTORE(.C0QXML,$$OT("MEASURE_SET")) ; Open tag
|
---|
224 | . . D XMLSTORE(.C0QXML,$$TAG("ID",C0QMS)) ; Write out set QRDA code
|
---|
225 | . . D XMLSTORE(.C0QXML,$$OT("MEASURES")) ; Open tag
|
---|
226 | . . F S C0QM=$O(@C0QREF@(C0QDFN,C0QMS,C0QM)) Q:C0QM="" D ; for each measure
|
---|
227 | . . . D XMLSTORE(.C0QXML,$$TAG("MEASURE",C0QM)) ; Write <measure> and qrda code
|
---|
228 | . . D XMLSTORE(.C0QXML,$$CT("MEASURES")) ; Close tag
|
---|
229 | . . D XMLSTORE(.C0QXML,$$CT("MEASURE_SET")) ; Close tag
|
---|
230 | . D XMLSTORE(.C0QXML,$$CT("QUALITY")) ; Close tag
|
---|
231 | . ;
|
---|
232 | . ;
|
---|
233 | . ; Insert Quality XML under the root of the CCR document
|
---|
234 | . D INSERT^C0CXPATH($NA(C0QCCRXML),$NA(C0QXML),"//ContinuityOfCareRecord")
|
---|
235 | . ;
|
---|
236 | . ;
|
---|
237 | . ; Get Kernel Default Directory
|
---|
238 | . N DEFDIR S DEFDIR=$$DEFDIR^%ZISH()
|
---|
239 | . ;
|
---|
240 | . ;
|
---|
241 | . ; Write out to a file.
|
---|
242 | . N FN S FN=C0QMNM_"_QRDA_CCR_DFN"_$$RJ^XLFSTR(C0QDFN,10,"0")_".XML" ; File Name
|
---|
243 | . K C0QCCRXML(0) ; remove zero node; API doesn't support it.
|
---|
244 | . D EN^DDIOL($$OUTPUT^C0CXPATH($NA(C0QCCRXML(1)),FN,DEFDIR))
|
---|
245 | QUIT
|
---|
246 | ;
|
---|
247 | ; Quick XML stuff ; All Private
|
---|
248 | OT(STR) Q "<"_STR_">" ; $$ Open Tag
|
---|
249 | CT(STR) Q "</"_STR_">" ; $$ Close Tag
|
---|
250 | TAG(NM,CONTENT) Q "<"_NM_">"_CONTENT_"</"_NM_">" ; $$ Whole tag
|
---|
251 | ;
|
---|
252 | XMLSTORE(REF,STR) ; Priv Proc - Store XML
|
---|
253 | ; REF -> Save Array. Pass by Reference.
|
---|
254 | ; STR -> What to store. Pass by Value.
|
---|
255 | ; Use like this: D XMLSTORE(.STORE,"<tag>")
|
---|
256 | ; Output: STORE(1)="<tag>"
|
---|
257 | N L ; Number Subscript to use
|
---|
258 | S L=$O(REF(" "),-1) S L=L+1 ; Get last number and increment
|
---|
259 | S REF(L)=STR,REF(0)=L ; Store string in numbered sub, store last number in 0 node (not used here)
|
---|
260 | QUIT
|
---|
261 | ;
|
---|
262 | ; Following is for formatting printed XML. L passed in Symbol Table and starts at 0.
|
---|
263 | L1 D WS S L=L+1 Q ; Write space and increment
|
---|
264 | L2 S L=L-1 D WS Q ; Decrement and Write space
|
---|
265 | WS X "F I=1:1:L W "" """ Q ; Write Space
|
---|
266 | ; This is for rolling down the stack to the $ES level
|
---|
267 | ROLLDOWN S $ET="Q:$ES S $EC=""""",$EC=",U99," QUIT
|
---|