Coverage for tasks/khandaker_mojo_medicationtherapy.py: 63%

94 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/khandaker_mojo_medicationtherapy.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 

30 

31from typing import List, Optional, Type, TYPE_CHECKING 

32 

33from sqlalchemy.sql.sqltypes import Float, Integer, UnicodeText 

34 

35from camcops_server.cc_modules.cc_constants import CssClass 

36from camcops_server.cc_modules.cc_db import ( 

37 ancillary_relationship, 

38 GenericTabletRecordMixin, 

39 TaskDescendant, 

40) 

41from camcops_server.cc_modules.cc_html import answer, tr_qa 

42from camcops_server.cc_modules.cc_sqlalchemy import Base 

43from camcops_server.cc_modules.cc_sqla_coltypes import CamcopsColumn 

44from camcops_server.cc_modules.cc_task import Task, TaskHasPatientMixin 

45 

46if TYPE_CHECKING: 

47 from camcops_server.cc_modules.cc_request import CamcopsRequest 

48 

49 

50class KhandakerMojoTableItem(GenericTabletRecordMixin, TaskDescendant, Base): 

51 __abstract__ = True 

52 

53 def any_fields_none(self) -> bool: 

54 for f in self.mandatory_fields(): 

55 if getattr(self, f) is None: 

56 return True 

57 return False 

58 

59 @classmethod 

60 def mandatory_fields(cls) -> List[str]: 

61 raise NotImplementedError 

62 

63 def get_response_option(self, req: "CamcopsRequest") -> Optional[str]: 

64 # Reads "self.response" from derived class. 

65 # noinspection PyUnresolvedReferences 

66 response = self.response # type: Optional[int] 

67 if response is None: 

68 return None 

69 return self.task_ancestor().xstring(req, f"response_{response}") 

70 

71 # ------------------------------------------------------------------------- 

72 # TaskDescendant overrides 

73 # ------------------------------------------------------------------------- 

74 

75 @classmethod 

76 def task_ancestor_class(cls) -> Optional[Type["Task"]]: 

77 return KhandakerMojoMedicationTherapy 

78 

79 def task_ancestor(self) -> Optional["KhandakerMojoMedicationTherapy"]: 

80 # Reads "self.medicationtable_id" from derived class. 

81 # noinspection PyUnresolvedReferences 

82 return KhandakerMojoMedicationTherapy.get_linked( 

83 self.medicationtable_id, self 

84 ) 

85 

86 

87class KhandakerMojoMedicationItem(KhandakerMojoTableItem): 

88 __tablename__ = "khandaker_mojo_medication_item" 

89 

90 medicationtable_id = CamcopsColumn( 

91 "medicationtable_id", 

92 Integer, 

93 nullable=False, 

94 comment="FK to medicationtable", 

95 ) 

96 seqnum = CamcopsColumn( 

97 "seqnum", 

98 Integer, 

99 nullable=False, 

100 comment="Sequence number of this medication", 

101 ) 

102 brand_name = CamcopsColumn("brand_name", UnicodeText, comment="Brand name") 

103 chemical_name = CamcopsColumn( 

104 "chemical_name", UnicodeText, comment="Chemical name for study team" 

105 ) 

106 dose = CamcopsColumn("dose", UnicodeText, comment="Dose") 

107 frequency = CamcopsColumn("frequency", UnicodeText, comment="Frequency") 

108 duration_months = CamcopsColumn( 

109 "duration_months", Float, comment="Duration (months)" 

110 ) 

111 indication = CamcopsColumn( 

112 "indication", 

113 UnicodeText, 

114 comment="Indication (what is the medication used for?)", 

115 ) 

116 response = CamcopsColumn( 

117 "response", 

118 Integer, 

119 comment=( 

120 "1 = treats all symptoms, " 

121 "2 = most symptoms, " 

122 "3 = some symptoms, " 

123 "4 = no symptoms)" 

124 ), 

125 ) 

126 

127 @classmethod 

128 def mandatory_fields(cls) -> List[str]: 

129 return [ 

130 "brand_name", 

131 "chemical_name", 

132 "dose", 

133 "frequency", 

134 "duration_months", 

135 "indication", 

136 "response", 

137 ] 

138 

139 def get_html_table_row(self, req: "CamcopsRequest") -> str: 

140 return f""" 

141 <tr> 

142 <td>{answer(self.chemical_name)}</td> 

143 <td>{answer(self.brand_name)}</td> 

144 <td>{answer(self.dose)}</td> 

145 <td>{answer(self.frequency)}</td> 

146 <td>{answer(self.duration_months)}</td> 

147 <td>{answer(self.indication)}</td> 

148 <td>{answer(self.get_response_option(req))}</td> 

149 </tr> 

150 """ 

151 

152 

153class KhandakerMojoTherapyItem(KhandakerMojoTableItem): 

154 __tablename__ = "khandaker_mojo_therapy_item" 

155 

156 medicationtable_id = CamcopsColumn( 

157 "medicationtable_id", 

158 Integer, 

159 nullable=False, 

160 comment="FK to medicationtable", 

161 ) 

162 seqnum = CamcopsColumn( 

163 "seqnum", 

164 Integer, 

165 nullable=False, 

166 comment="Sequence number of this therapy", 

167 ) 

168 therapy = CamcopsColumn("therapy", UnicodeText, comment="Therapy") 

169 frequency = CamcopsColumn("frequency", UnicodeText, comment="Frequency") 

170 sessions_completed = CamcopsColumn( 

171 "sessions_completed", Integer, comment="Sessions completed" 

172 ) 

173 sessions_planned = CamcopsColumn( 

174 "sessions_planned", Integer, comment="Sessions planned" 

175 ) 

176 indication = CamcopsColumn( 

177 "indication", 

178 UnicodeText, 

179 comment="Indication (what is the medication used for?)", 

180 ) 

181 response = CamcopsColumn( 

182 "response", 

183 Integer, 

184 comment=( 

185 "1 = treats all symptoms, " 

186 "2 = most symptoms, " 

187 "3 = some symptoms, " 

188 "4 = no symptoms)" 

189 ), 

190 ) 

191 

192 @classmethod 

193 def mandatory_fields(cls) -> List[str]: 

194 return [ 

195 "therapy", 

196 "frequency", 

197 "sessions_completed", 

198 "sessions_planned", 

199 "indication", 

200 "response", 

201 ] 

202 

203 def get_html_table_row(self, req: "CamcopsRequest") -> str: 

204 return f""" 

205 <tr> 

206 <td>{answer(self.therapy)}</td> 

207 <td>{answer(self.frequency)}</td> 

208 <td>{answer(self.sessions_completed)}</td> 

209 <td>{answer(self.sessions_planned)}</td> 

210 <td>{answer(self.indication)}</td> 

211 <td>{answer(self.get_response_option(req))}</td> 

212 </tr> 

213 """ 

214 

215 

216class KhandakerMojoMedicationTherapy(TaskHasPatientMixin, Task): 

217 """ 

218 Server implementation of the KhandakerMojoMedicationTherapy task 

219 """ 

220 

221 __tablename__ = "khandaker_mojo_medicationtherapy" 

222 shortname = "Khandaker_MOJO_MedicationTherapy" 

223 info_filename_stem = "khandaker_mojo" 

224 provides_trackers = False 

225 

226 medication_items = ancillary_relationship( 

227 parent_class_name="KhandakerMojoMedicationTherapy", 

228 ancillary_class_name="KhandakerMojoMedicationItem", 

229 ancillary_fk_to_parent_attr_name="medicationtable_id", 

230 ancillary_order_by_attr_name="seqnum", 

231 ) # type: List[KhandakerMojoMedicationItem] 

232 

233 therapy_items = ancillary_relationship( 

234 parent_class_name="KhandakerMojoMedicationTherapy", 

235 ancillary_class_name="KhandakerMojoTherapyItem", 

236 ancillary_fk_to_parent_attr_name="medicationtable_id", 

237 ancillary_order_by_attr_name="seqnum", 

238 ) # type: List[KhandakerMojoTherapyItem] 

239 

240 @staticmethod 

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

242 _ = req.gettext 

243 return _("Khandaker GM — MOJO — Medications and therapies") 

244 

245 def is_complete(self) -> bool: 

246 # Whilst it's almost certain that anyone completing this task would be 

247 # on some kind of medication, we have no way of knowing when all 

248 # medication has been added to the table 

249 for item in self.medication_items: 

250 if item.any_fields_none(): 

251 return False 

252 

253 for item in self.therapy_items: 

254 if item.any_fields_none(): 

255 return False 

256 

257 return True 

258 

259 def get_num_medication_items(self) -> int: 

260 return len(self.medication_items) 

261 

262 def get_num_therapy_items(self) -> int: 

263 return len(self.therapy_items) 

264 

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

266 html = f""" 

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

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

269 {self.get_is_complete_tr(req)} 

270 {tr_qa("Number of medications", 

271 self.get_num_medication_items())} 

272 {tr_qa("Number of therapies", 

273 self.get_num_therapy_items())} 

274 </table> 

275 </div> 

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

277 <tr> 

278 <th>{self.xstring(req, "chemical_name")}</th> 

279 <th>{self.xstring(req, "brand_name")}</th> 

280 <th>{self.xstring(req, "dose")}</th> 

281 <th>{self.xstring(req, "frequency")}</th> 

282 <th>{self.xstring(req, "duration_months")}</th> 

283 <th>{self.xstring(req, "indication")}</th> 

284 <th>{self.xstring(req, "response")}</th> 

285 </tr> 

286 """ 

287 for item in self.medication_items: 

288 html += item.get_html_table_row(req) 

289 

290 html += f""" 

291 </table> 

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

293 <tr> 

294 <th>{self.xstring(req, "therapy")}</th> 

295 <th>{self.xstring(req, "frequency")}</th> 

296 <th>{self.xstring(req, "sessions_completed")}</th> 

297 <th>{self.xstring(req, "sessions_planned")}</th> 

298 <th>{self.xstring(req, "indication")}</th> 

299 <th>{self.xstring(req, "response")}</th> 

300 </tr> 

301 """ 

302 

303 for item in self.therapy_items: 

304 html += item.get_html_table_row(req) 

305 

306 html += """ 

307 </table> 

308 """ 

309 

310 return html