Hide keyboard shortcuts

Hot-keys on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

1#!/usr/bin/env python 

2 

3""" 

4camcops_server/tasks/khandaker_mojo_medicationtherapy.py 

5 

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

7 

8 Copyright (C) 2012-2020 Rudolf Cardinal (rudolf@pobox.com). 

9 

10 This file is part of CamCOPS. 

11 

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

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

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

15 (at your option) any later version. 

16 

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

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

19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 

20 GNU General Public License for more details. 

21 

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

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

24 

25=============================================================================== 

26 

27""" 

28 

29 

30from typing import List, Optional, Type, TYPE_CHECKING 

31 

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

33 

34from camcops_server.cc_modules.cc_constants import CssClass 

35from camcops_server.cc_modules.cc_db import ( 

36 ancillary_relationship, 

37 GenericTabletRecordMixin, 

38 TaskDescendant, 

39) 

40from camcops_server.cc_modules.cc_html import answer, tr_qa 

41from camcops_server.cc_modules.cc_sqlalchemy import Base 

42from camcops_server.cc_modules.cc_sqla_coltypes import ( 

43 CamcopsColumn, 

44) 

45from camcops_server.cc_modules.cc_task import ( 

46 Task, 

47 TaskHasPatientMixin, 

48) 

49 

50if TYPE_CHECKING: 

51 from camcops_server.cc_modules.cc_request import CamcopsRequest 

52 

53 

54class KhandakerMojoTableItem(GenericTabletRecordMixin, TaskDescendant, Base): 

55 __abstract__ = True 

56 

57 def any_fields_none(self) -> bool: 

58 for f in self.mandatory_fields(): 

59 if getattr(self, f) is None: 

60 return True 

61 return False 

62 

63 @classmethod 

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

65 raise NotImplementedError 

66 

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

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

69 # noinspection PyUnresolvedReferences 

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

71 if response is None: 

72 return None 

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

74 

75 # ------------------------------------------------------------------------- 

76 # TaskDescendant overrides 

77 # ------------------------------------------------------------------------- 

78 

79 @classmethod 

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

81 return KhandakerMojoMedicationTherapy 

82 

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

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

85 # noinspection PyUnresolvedReferences 

86 return KhandakerMojoMedicationTherapy.get_linked( 

87 self.medicationtable_id, self) 

88 

89 

90class KhandakerMojoMedicationItem(KhandakerMojoTableItem): 

91 __tablename__ = "khandaker_mojo_medication_item" 

92 

93 medicationtable_id = CamcopsColumn( 

94 "medicationtable_id", Integer, nullable=False, 

95 comment="FK to medicationtable" 

96 ) 

97 seqnum = CamcopsColumn( 

98 "seqnum", Integer, nullable=False, 

99 comment="Sequence number of this medication" 

100 ) 

101 brand_name = CamcopsColumn( 

102 "brand_name", UnicodeText, 

103 comment="Brand name" 

104 ) 

105 chemical_name = CamcopsColumn( 

106 "chemical_name", UnicodeText, 

107 comment="Chemical name for study team" 

108 ) 

109 dose = CamcopsColumn( 

110 "dose", UnicodeText, 

111 comment="Dose" 

112 ) 

113 frequency = CamcopsColumn( 

114 "frequency", UnicodeText, 

115 comment="Frequency" 

116 ) 

117 duration_months = CamcopsColumn( 

118 "duration_months", Float, 

119 comment="Duration (months)" 

120 ) 

121 indication = CamcopsColumn( 

122 "indication", UnicodeText, 

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

124 ) 

125 response = CamcopsColumn( 

126 "response", Integer, 

127 comment=("1 = treats all symptoms, " 

128 "2 = most symptoms, " 

129 "3 = some symptoms, " 

130 "4 = no symptoms)") 

131 ) 

132 

133 @classmethod 

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

135 return [ 

136 "brand_name", 

137 "chemical_name", 

138 "dose", 

139 "frequency", 

140 "duration_months", 

141 "indication", 

142 "response", 

143 ] 

144 

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

146 return f""" 

147 <tr> 

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

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

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

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

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

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

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

155 </tr> 

156 """ 

157 

158 

159class KhandakerMojoTherapyItem(KhandakerMojoTableItem): 

160 __tablename__ = "khandaker_mojo_therapy_item" 

161 

162 medicationtable_id = CamcopsColumn( 

163 "medicationtable_id", Integer, nullable=False, 

164 comment="FK to medicationtable" 

165 ) 

166 seqnum = CamcopsColumn( 

167 "seqnum", Integer, nullable=False, 

168 comment="Sequence number of this therapy" 

169 ) 

170 therapy = CamcopsColumn( 

171 "therapy", UnicodeText, 

172 comment="Therapy" 

173 ) 

174 frequency = CamcopsColumn( 

175 "frequency", UnicodeText, 

176 comment="Frequency" 

177 ) 

178 sessions_completed = CamcopsColumn( 

179 "sessions_completed", Integer, 

180 comment="Sessions completed" 

181 ) 

182 sessions_planned = CamcopsColumn( 

183 "sessions_planned", Integer, 

184 comment="Sessions planned" 

185 ) 

186 indication = CamcopsColumn( 

187 "indication", UnicodeText, 

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

189 ) 

190 response = CamcopsColumn( 

191 "response", Integer, 

192 comment=("1 = treats all symptoms, " 

193 "2 = most symptoms, " 

194 "3 = some symptoms, " 

195 "4 = no symptoms)") 

196 ) 

197 

198 @classmethod 

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

200 return [ 

201 "therapy", 

202 "frequency", 

203 "sessions_completed", 

204 "sessions_planned", 

205 "indication", 

206 "response", 

207 ] 

208 

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

210 return f""" 

211 <tr> 

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

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

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

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

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

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

218 </tr> 

219 """ 

220 

221 

222class KhandakerMojoMedicationTherapy(TaskHasPatientMixin, Task): 

223 """ 

224 Server implementation of the KhandakerMojoMedicationTherapy task 

225 """ 

226 __tablename__ = "khandaker_mojo_medicationtherapy" 

227 shortname = "Khandaker_MOJO_MedicationTherapy" 

228 provides_trackers = False 

229 

230 medication_items = ancillary_relationship( 

231 parent_class_name="KhandakerMojoMedicationTherapy", 

232 ancillary_class_name="KhandakerMojoMedicationItem", 

233 ancillary_fk_to_parent_attr_name="medicationtable_id", 

234 ancillary_order_by_attr_name="seqnum" 

235 ) # type: List[KhandakerMojoMedicationItem] 

236 

237 therapy_items = ancillary_relationship( 

238 parent_class_name="KhandakerMojoMedicationTherapy", 

239 ancillary_class_name="KhandakerMojoTherapyItem", 

240 ancillary_fk_to_parent_attr_name="medicationtable_id", 

241 ancillary_order_by_attr_name="seqnum" 

242 ) # type: List[KhandakerMojoTherapyItem] 

243 

244 @staticmethod 

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

246 _ = req.gettext 

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

248 

249 def is_complete(self) -> bool: 

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

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

252 # medication has been added to the table 

253 for item in self.medication_items: 

254 if item.any_fields_none(): 

255 return False 

256 

257 for item in self.therapy_items: 

258 if item.any_fields_none(): 

259 return False 

260 

261 return True 

262 

263 def get_num_medication_items(self) -> int: 

264 return len(self.medication_items) 

265 

266 def get_num_therapy_items(self) -> int: 

267 return len(self.therapy_items) 

268 

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

270 html = f""" 

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

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

273 {self.get_is_complete_tr(req)} 

274 {tr_qa("Number of medications", 

275 self.get_num_medication_items())} 

276 {tr_qa("Number of therapies", 

277 self.get_num_therapy_items())} 

278 </table> 

279 </div> 

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

281 <tr> 

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

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

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

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

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

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

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

289 </tr> 

290 """ 

291 for item in self.medication_items: 

292 html += item.get_html_table_row(req) 

293 

294 html += f""" 

295 </table> 

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

297 <tr> 

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

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

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

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

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

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

304 </tr> 

305 """ 

306 

307 for item in self.therapy_items: 

308 html += item.get_html_table_row(req) 

309 

310 html += """ 

311 </table> 

312 """ 

313 

314 return html