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

29from typing import List, Optional 

30 

31from cardinal_pythonlib.datetimefunc import format_datetime 

32from cardinal_pythonlib.typetests import is_false 

33import cardinal_pythonlib.rnc_web as ws 

34from sqlalchemy.sql.schema import Column 

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

36 

37from camcops_server.cc_modules.cc_constants import ( 

38 CssClass, 

39 DateFormat, 

40 ICD10_COPYRIGHT_DIV, 

41) 

42from camcops_server.cc_modules.cc_ctvinfo import CTV_INCOMPLETE, CtvInfo 

43from camcops_server.cc_modules.cc_html import ( 

44 get_true_false_none, 

45 tr_qa, 

46) 

47from camcops_server.cc_modules.cc_request import CamcopsRequest 

48from camcops_server.cc_modules.cc_sqla_coltypes import ( 

49 BIT_CHECKER, 

50 CamcopsColumn, 

51) 

52from camcops_server.cc_modules.cc_string import AS 

53from camcops_server.cc_modules.cc_summaryelement import SummaryElement 

54from camcops_server.cc_modules.cc_task import ( 

55 Task, 

56 TaskHasClinicianMixin, 

57 TaskHasPatientMixin, 

58) 

59from camcops_server.cc_modules.cc_text import SS 

60 

61 

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

63# Icd10Mixed 

64# ============================================================================= 

65 

66class Icd10Mixed(TaskHasClinicianMixin, TaskHasPatientMixin, Task): 

67 """ 

68 Server implementation of the ICD10-MIXED task. 

69 """ 

70 __tablename__ = "icd10mixed" 

71 shortname = "ICD10-MIXED" 

72 

73 date_pertains_to = Column( 

74 "date_pertains_to", Date, 

75 comment="Date the assessment pertains to" 

76 ) 

77 comments = Column( 

78 "comments", UnicodeText, 

79 comment="Clinician's comments" 

80 ) 

81 mixture_or_rapid_alternation = CamcopsColumn( 

82 "mixture_or_rapid_alternation", Boolean, 

83 permitted_value_checker=BIT_CHECKER, 

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

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

86 "manic and depressive symptoms." 

87 ) 

88 duration_at_least_2_weeks = CamcopsColumn( 

89 "duration_at_least_2_weeks", Boolean, 

90 permitted_value_checker=BIT_CHECKER, 

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

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

93 ) 

94 

95 @staticmethod 

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

97 _ = req.gettext 

98 return _( 

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

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

101 ) 

102 

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

104 if not self.is_complete(): 

105 return CTV_INCOMPLETE 

106 category = ( 

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

108 " criteria for mixed affective episode" 

109 ) 

110 infolist = [CtvInfo( 

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

112 format_datetime(self.date_pertains_to, DateFormat.LONG_DATE), 

113 category 

114 ) 

115 )] 

116 if self.comments: 

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

118 return infolist 

119 

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

121 return self.standard_task_summary_fields() + [ 

122 SummaryElement( 

123 name="meets_criteria", 

124 coltype=Boolean(), 

125 value=self.meets_criteria(), 

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

127 ] 

128 

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

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

131 if (self.mixture_or_rapid_alternation and 

132 self.duration_at_least_2_weeks): 

133 return True 

134 if is_false(self.mixture_or_rapid_alternation): 

135 return False 

136 if is_false(self.duration_at_least_2_weeks): 

137 return False 

138 return None 

139 

140 def is_complete(self) -> bool: 

141 return ( 

142 self.meets_criteria() is not None and 

143 self.field_contents_valid() 

144 ) 

145 

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

147 return """ 

148 {clinician_comments} 

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

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

151 {tr_is_complete} 

152 {date_pertains_to} 

153 {meets_criteria} 

154 </table> 

155 </div> 

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

157 {icd10_symptomatic_disclaimer} 

158 </div> 

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

160 <tr> 

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

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

163 </tr> 

164 {mixture_or_rapid_alternation} 

165 {duration_at_least_2_weeks} 

166 </table> 

167 {ICD10_COPYRIGHT_DIV} 

168 """.format( 

169 clinician_comments=self.get_standard_clinician_comments_block( 

170 req, self.comments), 

171 CssClass=CssClass, 

172 tr_is_complete=self.get_is_complete_tr(req), 

173 date_pertains_to=tr_qa( 

174 req.wappstring(AS.DATE_PERTAINS_TO), 

175 format_datetime(self.date_pertains_to, DateFormat.LONG_DATE, 

176 default=None) 

177 ), 

178 meets_criteria=tr_qa( 

179 req.sstring(SS.MEETS_CRITERIA), 

180 get_true_false_none(req, self.meets_criteria()) 

181 ), 

182 icd10_symptomatic_disclaimer=req.wappstring( 

183 AS.ICD10_SYMPTOMATIC_DISCLAIMER), 

184 mixture_or_rapid_alternation=self.get_twocol_bool_row_true_false( 

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

186 duration_at_least_2_weeks=self.get_twocol_bool_row_true_false( 

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

188 ICD10_COPYRIGHT_DIV=ICD10_COPYRIGHT_DIV, 

189 )