Coverage for tasks/gmcpq.py: 45%

105 statements  

« prev     ^ index     » next       coverage.py v6.5.0, created at 2022-11-08 23:14 +0000

1#!/usr/bin/env python 

2 

3""" 

4camcops_server/tasks/gmcpq.py 

5 

6=============================================================================== 

7 

8 Copyright (C) 2012, University of Cambridge, Department of Psychiatry. 

9 Created by Rudolf Cardinal (rnc1001@cam.ac.uk). 

10 

11 This file is part of CamCOPS. 

12 

13 CamCOPS is free software: you can redistribute it and/or modify 

14 it under the terms of the GNU General Public License as published by 

15 the Free Software Foundation, either version 3 of the License, or 

16 (at your option) any later version. 

17 

18 CamCOPS is distributed in the hope that it will be useful, 

19 but WITHOUT ANY WARRANTY; without even the implied warranty of 

20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 

21 GNU General Public License for more details. 

22 

23 You should have received a copy of the GNU General Public License 

24 along with CamCOPS. If not, see <https://www.gnu.org/licenses/>. 

25 

26=============================================================================== 

27 

28""" 

29 

30import cardinal_pythonlib.rnc_web as ws 

31from sqlalchemy.sql.schema import Column 

32from sqlalchemy.sql.sqltypes import Integer, UnicodeText 

33 

34from camcops_server.cc_modules.cc_constants import ( 

35 CssClass, 

36 POSSIBLE_SEX_VALUES, 

37) 

38from camcops_server.cc_modules.cc_html import ( 

39 get_yes_no_none, 

40 subheading_spanning_two_columns, 

41 td, 

42 tr, 

43 tr_qa, 

44) 

45from camcops_server.cc_modules.cc_request import CamcopsRequest 

46from camcops_server.cc_modules.cc_sqla_coltypes import ( 

47 BIT_CHECKER, 

48 CamcopsColumn, 

49 ONE_TO_FIVE_CHECKER, 

50 PermittedValueChecker, 

51 ZERO_TO_FIVE_CHECKER, 

52) 

53from camcops_server.cc_modules.cc_sqla_coltypes import SexColType 

54from camcops_server.cc_modules.cc_task import get_from_dict, Task 

55from camcops_server.cc_modules.cc_text import SS 

56 

57 

58# ============================================================================= 

59# GMCPQ 

60# ============================================================================= 

61 

62 

63class GMCPQ(Task): 

64 """ 

65 Server implementation of the GMC-PQ task. 

66 """ 

67 

68 __tablename__ = "gmcpq" 

69 shortname = "GMC-PQ" 

70 

71 RATING_TEXT = " (1 poor - 5 very good, 0 does not apply)" 

72 AGREE_TEXT = " (1 strongly disagree - 5 strongly agree, 0 does not apply)" 

73 

74 doctor = Column("doctor", UnicodeText, comment="Doctor's name") 

75 q1 = CamcopsColumn( 

76 "q1", 

77 Integer, 

78 permitted_value_checker=PermittedValueChecker(minimum=1, maximum=4), 

79 comment="Filling in questionnaire for... (1 yourself, " 

80 "2 child, 3 spouse/partner, 4 other relative/friend)", 

81 ) 

82 q2a = CamcopsColumn( 

83 "q2a", 

84 Integer, 

85 permitted_value_checker=BIT_CHECKER, 

86 comment="Reason: advice? (0 no, 1 yes)", 

87 ) 

88 q2b = CamcopsColumn( 

89 "q2b", 

90 Integer, 

91 permitted_value_checker=BIT_CHECKER, 

92 comment="Reason: one-off problem? (0 no, 1 yes)", 

93 ) 

94 q2c = CamcopsColumn( 

95 "q2c", 

96 Integer, 

97 permitted_value_checker=BIT_CHECKER, 

98 comment="Reason: ongoing problem? (0 no, 1 yes)", 

99 ) 

100 q2d = CamcopsColumn( 

101 "q2d", 

102 Integer, 

103 permitted_value_checker=BIT_CHECKER, 

104 comment="Reason: routine check? (0 no, 1 yes)", 

105 ) 

106 q2e = CamcopsColumn( 

107 "q2e", 

108 Integer, 

109 permitted_value_checker=BIT_CHECKER, 

110 comment="Reason: treatment? (0 no, 1 yes)", 

111 ) 

112 q2f = CamcopsColumn( 

113 "q2f", 

114 Integer, 

115 permitted_value_checker=BIT_CHECKER, 

116 comment="Reason: other? (0 no, 1 yes)", 

117 ) 

118 q2f_details = Column( 

119 "q2f_details", UnicodeText, comment="Reason, other, details" 

120 ) 

121 q3 = CamcopsColumn( 

122 "q3", 

123 Integer, 

124 permitted_value_checker=ONE_TO_FIVE_CHECKER, 

125 comment="How important to health/wellbeing was the reason " 

126 "(1 not very - 5 very)", 

127 ) 

128 q4a = CamcopsColumn( 

129 "q4a", 

130 Integer, 

131 permitted_value_checker=ZERO_TO_FIVE_CHECKER, 

132 comment="How good: being polite" + RATING_TEXT, 

133 ) 

134 q4b = CamcopsColumn( 

135 "q4b", 

136 Integer, 

137 permitted_value_checker=ZERO_TO_FIVE_CHECKER, 

138 comment="How good: making you feel at ease" + RATING_TEXT, 

139 ) 

140 q4c = CamcopsColumn( 

141 "q4c", 

142 Integer, 

143 permitted_value_checker=ZERO_TO_FIVE_CHECKER, 

144 comment="How good: listening" + RATING_TEXT, 

145 ) 

146 q4d = CamcopsColumn( 

147 "q4d", 

148 Integer, 

149 permitted_value_checker=ZERO_TO_FIVE_CHECKER, 

150 comment="How good: assessing medical condition" + RATING_TEXT, 

151 ) 

152 q4e = CamcopsColumn( 

153 "q4e", 

154 Integer, 

155 permitted_value_checker=ZERO_TO_FIVE_CHECKER, 

156 comment="How good: explaining" + RATING_TEXT, 

157 ) 

158 q4f = CamcopsColumn( 

159 "q4f", 

160 Integer, 

161 permitted_value_checker=ZERO_TO_FIVE_CHECKER, 

162 comment="How good: involving you in decisions" + RATING_TEXT, 

163 ) 

164 q4g = CamcopsColumn( 

165 "q4g", 

166 Integer, 

167 permitted_value_checker=ZERO_TO_FIVE_CHECKER, 

168 comment="How good: providing/arranging treatment" + RATING_TEXT, 

169 ) 

170 q5a = CamcopsColumn( 

171 "q5a", 

172 Integer, 

173 permitted_value_checker=ZERO_TO_FIVE_CHECKER, 

174 comment="Agree/disagree: will keep info confidential" + AGREE_TEXT, 

175 ) 

176 q5b = CamcopsColumn( 

177 "q5b", 

178 Integer, 

179 permitted_value_checker=ZERO_TO_FIVE_CHECKER, 

180 comment="Agree/disagree: honest/trustworthy" + AGREE_TEXT, 

181 ) 

182 q6 = CamcopsColumn( 

183 "q6", 

184 Integer, 

185 permitted_value_checker=BIT_CHECKER, 

186 comment="Confident in doctor's ability to provide care (0 no, 1 yes)", 

187 ) 

188 q7 = CamcopsColumn( 

189 "q7", 

190 Integer, 

191 permitted_value_checker=BIT_CHECKER, 

192 comment="Would be completely happy to see this doctor again " 

193 "(0 no, 1 yes)", 

194 ) 

195 q8 = CamcopsColumn( 

196 "q8", 

197 Integer, 

198 permitted_value_checker=BIT_CHECKER, 

199 comment="Was this visit with your usual doctor (0 no, 1 yes)", 

200 ) 

201 q9 = Column("q9", UnicodeText, comment="Other comments") 

202 q10 = CamcopsColumn( 

203 "q10", 

204 SexColType, 

205 permitted_value_checker=PermittedValueChecker( 

206 permitted_values=POSSIBLE_SEX_VALUES 

207 ), 

208 comment="Sex of rater (M, F, X)", 

209 ) 

210 q11 = CamcopsColumn( 

211 "q11", 

212 Integer, 

213 permitted_value_checker=ONE_TO_FIVE_CHECKER, 

214 comment="Age (1 = under 15, 2 = 15-20, 3 = 21-40, " 

215 "4 = 40-60, 5 = 60 or over", # yes, I know it's daft 

216 ) 

217 q12 = CamcopsColumn( 

218 "q12", 

219 Integer, 

220 permitted_value_checker=PermittedValueChecker(minimum=1, maximum=16), 

221 comment="Ethnicity (1 = White British, 2 = White Irish, " 

222 "3 = White other, 4 = Mixed W/B Caribbean, " 

223 "5 = Mixed W/B African, 6 = Mixed W/Asian, 7 = Mixed other, " 

224 "8 = Asian/Asian British - Indian, 9 = A/AB - Pakistani, " 

225 "10 = A/AB - Bangladeshi, 11 = A/AB - other, " 

226 "12 = Black/Black British - Caribbean, 13 = B/BB - African, " 

227 "14 = B/BB - other, 15 = Chinese, 16 = other)", 

228 ) 

229 q12_details = Column( 

230 "q12_details", UnicodeText, comment="Ethnic group, other, details" 

231 ) 

232 

233 @staticmethod 

234 def longname(req: "CamcopsRequest") -> str: 

235 _ = req.gettext 

236 return _("GMC Patient Questionnaire") 

237 

238 def is_complete(self) -> bool: 

239 return ( 

240 self.is_field_not_none("q1") 

241 and self.is_field_not_none("q3") 

242 and self.is_field_not_none("q4a") 

243 and self.is_field_not_none("q4b") 

244 and self.is_field_not_none("q4c") 

245 and self.is_field_not_none("q4d") 

246 and self.is_field_not_none("q4e") 

247 and self.is_field_not_none("q4f") 

248 and self.is_field_not_none("q4g") 

249 and self.is_field_not_none("q5a") 

250 and self.is_field_not_none("q5b") 

251 and self.is_field_not_none("q6") 

252 and self.is_field_not_none("q7") 

253 and self.is_field_not_none("q8") 

254 and self.field_contents_valid() 

255 ) 

256 

257 def get_task_html(self, req: CamcopsRequest) -> str: 

258 dict_q1 = {None: None} 

259 dict_q3 = {None: None} 

260 dict_q4 = {None: None} 

261 dict_q5 = {None: None} 

262 dict_q11 = {None: None} 

263 dict_q12 = {None: None} 

264 for option in range(1, 5): 

265 dict_q1[option] = self.wxstring(req, "q1_option" + str(option)) 

266 for option in range(1, 6): 

267 dict_q3[option] = self.wxstring(req, "q3_option" + str(option)) 

268 dict_q11[option] = self.wxstring(req, "q11_option" + str(option)) 

269 for option in range(0, 6): 

270 prefix = str(option) + " – " if option > 0 else "" 

271 dict_q4[option] = prefix + self.wxstring( 

272 req, "q4_option" + str(option) 

273 ) 

274 dict_q5[option] = prefix + self.wxstring( 

275 req, "q5_option" + str(option) 

276 ) 

277 for option in range(1, 17): 

278 dict_q12[option] = self.wxstring( 

279 req, "ethnicity_option" + str(option) 

280 ) 

281 h = f""" 

282 <div class="{CssClass.SUMMARY}"> 

283 <table class="{CssClass.SUMMARY}"> 

284 {self.get_is_complete_tr(req)} 

285 </table> 

286 </div> 

287 <table class="{CssClass.TASKDETAIL}"> 

288 <tr> 

289 <th width="60%">Question</th> 

290 <th width="40%">Answer</th> 

291 </tr> 

292 """ 

293 ell = "&hellip; " # horizontal ellipsis 

294 sep_row = subheading_spanning_two_columns("<br>") 

295 blank_cell = td("", td_class=CssClass.SUBHEADING) 

296 h += tr_qa(self.wxstring(req, "q_doctor"), ws.webify(self.doctor)) 

297 h += sep_row 

298 h += tr_qa(self.wxstring(req, "q1"), get_from_dict(dict_q1, self.q1)) 

299 h += tr(td(self.wxstring(req, "q2")), blank_cell, literal=True) 

300 h += tr_qa( 

301 ell + self.wxstring(req, "q2_a"), 

302 get_yes_no_none(req, self.q2a), 

303 default="", 

304 ) 

305 h += tr_qa( 

306 ell + self.wxstring(req, "q2_b"), 

307 get_yes_no_none(req, self.q2b), 

308 default="", 

309 ) 

310 h += tr_qa( 

311 ell + self.wxstring(req, "q2_c"), 

312 get_yes_no_none(req, self.q2c), 

313 default="", 

314 ) 

315 h += tr_qa( 

316 ell + self.wxstring(req, "q2_d"), 

317 get_yes_no_none(req, self.q2d), 

318 default="", 

319 ) 

320 h += tr_qa( 

321 ell + self.wxstring(req, "q2_e"), 

322 get_yes_no_none(req, self.q2e), 

323 default="", 

324 ) 

325 h += tr_qa( 

326 ell + self.wxstring(req, "q2_f"), 

327 get_yes_no_none(req, self.q2f), 

328 default="", 

329 ) 

330 h += tr_qa( 

331 ell + ell + self.wxstring(req, "q2f_s"), 

332 ws.webify(self.q2f_details), 

333 ) 

334 h += tr_qa(self.wxstring(req, "q3"), get_from_dict(dict_q3, self.q3)) 

335 h += tr(td(self.wxstring(req, "q4")), blank_cell, literal=True) 

336 h += tr_qa( 

337 ell + self.wxstring(req, "q4_a"), get_from_dict(dict_q4, self.q4a) 

338 ) 

339 h += tr_qa( 

340 ell + self.wxstring(req, "q4_b"), get_from_dict(dict_q4, self.q4b) 

341 ) 

342 h += tr_qa( 

343 ell + self.wxstring(req, "q4_c"), get_from_dict(dict_q4, self.q4c) 

344 ) 

345 h += tr_qa( 

346 ell + self.wxstring(req, "q4_d"), get_from_dict(dict_q4, self.q4d) 

347 ) 

348 h += tr_qa( 

349 ell + self.wxstring(req, "q4_e"), get_from_dict(dict_q4, self.q4e) 

350 ) 

351 h += tr_qa( 

352 ell + self.wxstring(req, "q4_f"), get_from_dict(dict_q4, self.q4f) 

353 ) 

354 h += tr_qa( 

355 ell + self.wxstring(req, "q4_g"), get_from_dict(dict_q4, self.q4g) 

356 ) 

357 h += tr(td(self.wxstring(req, "q5")), blank_cell, literal=True) 

358 h += tr_qa( 

359 ell + self.wxstring(req, "q5_a"), get_from_dict(dict_q5, self.q5a) 

360 ) 

361 h += tr_qa( 

362 ell + self.wxstring(req, "q5_b"), get_from_dict(dict_q5, self.q5b) 

363 ) 

364 h += tr_qa(self.wxstring(req, "q6"), get_yes_no_none(req, self.q6)) 

365 h += tr_qa(self.wxstring(req, "q7"), get_yes_no_none(req, self.q7)) 

366 h += tr_qa(self.wxstring(req, "q8"), get_yes_no_none(req, self.q8)) 

367 h += tr_qa(self.wxstring(req, "q9_s"), ws.webify(self.q9)) 

368 h += sep_row 

369 h += tr_qa(req.sstring(SS.SEX), ws.webify(self.q10)) 

370 h += tr_qa( 

371 self.wxstring(req, "q11"), get_from_dict(dict_q11, self.q11) 

372 ) 

373 h += tr_qa( 

374 self.wxstring(req, "q12"), get_from_dict(dict_q12, self.q12) 

375 ) 

376 h += tr_qa( 

377 ell + self.wxstring(req, "ethnicity_other_s"), 

378 ws.webify(self.q12_details), 

379 ) 

380 h += """ 

381 </table> 

382 """ 

383 return h