Coverage for tasks/icd10mixed.py: 62%

50 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/icd10mixed.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 

30from typing import List, Optional 

31 

32from cardinal_pythonlib.datetimefunc import format_datetime 

33from cardinal_pythonlib.typetests import is_false 

34import cardinal_pythonlib.rnc_web as ws 

35from sqlalchemy.sql.schema import Column 

36from sqlalchemy.sql.sqltypes import Boolean, Date, UnicodeText 

37 

38from camcops_server.cc_modules.cc_constants import ( 

39 CssClass, 

40 DateFormat, 

41 ICD10_COPYRIGHT_DIV, 

42) 

43from camcops_server.cc_modules.cc_ctvinfo import CTV_INCOMPLETE, CtvInfo 

44from camcops_server.cc_modules.cc_html import get_true_false_none, tr_qa 

45from camcops_server.cc_modules.cc_request import CamcopsRequest 

46from camcops_server.cc_modules.cc_sqla_coltypes import ( 

47 BIT_CHECKER, 

48 CamcopsColumn, 

49) 

50from camcops_server.cc_modules.cc_string import AS 

51from camcops_server.cc_modules.cc_summaryelement import SummaryElement 

52from camcops_server.cc_modules.cc_task import ( 

53 Task, 

54 TaskHasClinicianMixin, 

55 TaskHasPatientMixin, 

56) 

57from camcops_server.cc_modules.cc_text import SS 

58 

59 

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

61# Icd10Mixed 

62# ============================================================================= 

63 

64 

65class Icd10Mixed(TaskHasClinicianMixin, TaskHasPatientMixin, Task): 

66 """ 

67 Server implementation of the ICD10-MIXED task. 

68 """ 

69 

70 __tablename__ = "icd10mixed" 

71 shortname = "ICD10-MIXED" 

72 info_filename_stem = "icd" 

73 

74 date_pertains_to = Column( 

75 "date_pertains_to", Date, comment="Date the assessment pertains to" 

76 ) 

77 comments = Column("comments", UnicodeText, comment="Clinician's comments") 

78 mixture_or_rapid_alternation = CamcopsColumn( 

79 "mixture_or_rapid_alternation", 

80 Boolean, 

81 permitted_value_checker=BIT_CHECKER, 

82 comment="The episode is characterized by either a mixture or " 

83 "a rapid alternation (i.e. within a few hours) of hypomanic, " 

84 "manic and depressive symptoms.", 

85 ) 

86 duration_at_least_2_weeks = CamcopsColumn( 

87 "duration_at_least_2_weeks", 

88 Boolean, 

89 permitted_value_checker=BIT_CHECKER, 

90 comment="Both manic and depressive symptoms must be prominent" 

91 " most of the time during a period of at least two weeks.", 

92 ) 

93 

94 @staticmethod 

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

96 _ = req.gettext 

97 return _( 

98 "ICD-10 symptomatic criteria for a mixed affective episode " 

99 "(as in e.g. F06.3, F25, F38.00, F31.6)" 

100 ) 

101 

102 def get_clinical_text(self, req: CamcopsRequest) -> List[CtvInfo]: 

103 if not self.is_complete(): 

104 return CTV_INCOMPLETE 

105 category = ( 

106 "Meets" if self.meets_criteria() else "Does not meet" 

107 ) + " criteria for mixed affective episode" 

108 infolist = [ 

109 CtvInfo( 

110 content="Pertains to: {}. {}.".format( 

111 format_datetime( 

112 self.date_pertains_to, DateFormat.LONG_DATE 

113 ), 

114 category, 

115 ) 

116 ) 

117 ] 

118 if self.comments: 

119 infolist.append(CtvInfo(content=ws.webify(self.comments))) 

120 return infolist 

121 

122 def get_summaries(self, req: CamcopsRequest) -> List[SummaryElement]: 

123 return self.standard_task_summary_fields() + [ 

124 SummaryElement( 

125 name="meets_criteria", 

126 coltype=Boolean(), 

127 value=self.meets_criteria(), 

128 comment="Meets criteria for a mixed affective episode?", 

129 ) 

130 ] 

131 

132 # Meets criteria? These also return null for unknown. 

133 def meets_criteria(self) -> Optional[bool]: 

134 if ( 

135 self.mixture_or_rapid_alternation 

136 and self.duration_at_least_2_weeks 

137 ): 

138 return True 

139 if is_false(self.mixture_or_rapid_alternation): 

140 return False 

141 if is_false(self.duration_at_least_2_weeks): 

142 return False 

143 return None 

144 

145 def is_complete(self) -> bool: 

146 return ( 

147 self.meets_criteria() is not None and self.field_contents_valid() 

148 ) 

149 

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

151 return """ 

152 {clinician_comments} 

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

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

155 {tr_is_complete} 

156 {date_pertains_to} 

157 {meets_criteria} 

158 </table> 

159 </div> 

160 <div class="{CssClass.EXPLANATION}"> 

161 {icd10_symptomatic_disclaimer} 

162 </div> 

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

164 <tr> 

165 <th width="80%">Question</th> 

166 <th width="20%">Answer</th> 

167 </tr> 

168 {mixture_or_rapid_alternation} 

169 {duration_at_least_2_weeks} 

170 </table> 

171 {ICD10_COPYRIGHT_DIV} 

172 """.format( 

173 clinician_comments=self.get_standard_clinician_comments_block( 

174 req, self.comments 

175 ), 

176 CssClass=CssClass, 

177 tr_is_complete=self.get_is_complete_tr(req), 

178 date_pertains_to=tr_qa( 

179 req.wappstring(AS.DATE_PERTAINS_TO), 

180 format_datetime( 

181 self.date_pertains_to, DateFormat.LONG_DATE, default=None 

182 ), 

183 ), 

184 meets_criteria=tr_qa( 

185 req.sstring(SS.MEETS_CRITERIA), 

186 get_true_false_none(req, self.meets_criteria()), 

187 ), 

188 icd10_symptomatic_disclaimer=req.wappstring( 

189 AS.ICD10_SYMPTOMATIC_DISCLAIMER 

190 ), 

191 mixture_or_rapid_alternation=self.get_twocol_bool_row_true_false( 

192 req, "mixture_or_rapid_alternation", self.wxstring(req, "a") 

193 ), 

194 duration_at_least_2_weeks=self.get_twocol_bool_row_true_false( 

195 req, "duration_at_least_2_weeks", self.wxstring(req, "b") 

196 ), 

197 ICD10_COPYRIGHT_DIV=ICD10_COPYRIGHT_DIV, 

198 )