Coverage for tasks/distressthermometer.py: 49%

1"""

2 camcops_server/tasks/distressthermometer.py

3

4===============================================================================

5

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

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

8

9 This file is part of CamCOPS.

10

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

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

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

14 (at your option) any later version.

15

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

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

18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the

19 GNU General Public License for more details.

20

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

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

23

24===============================================================================

25

26"""

27

28 from typing import Any, List, Optional, Type

29

30 from cardinal_pythonlib.stringfunc import strseq

31 from sqlalchemy.orm import Mapped, mapped_column

32 from sqlalchemy.sql.sqltypes import UnicodeText

33

34 from camcops_server.cc_modules.cc_constants import CssClass, PV

35 from camcops_server.cc_modules.cc_ctvinfo import CTV_INCOMPLETE, CtvInfo

36 from camcops_server.cc_modules.cc_db import add_multiple_columns

37 from camcops_server.cc_modules.cc_html import (

38 get_yes_no_none,

39 subheading_spanning_two_columns,

40 tr_qa,

41)

42 from camcops_server.cc_modules.cc_request import CamcopsRequest

43 from camcops_server.cc_modules.cc_sqla_coltypes import (

44 mapped_camcops_column,

45 PermittedValueChecker,

46)

47 from camcops_server.cc_modules.cc_task import Task, TaskHasPatientMixin

48

49

50# =============================================================================

51# Distress Thermometer

52# =============================================================================

53

54

55 class DistressThermometer( # type: ignore[misc]

56 TaskHasPatientMixin,

57 Task,

58):

59 """

60 Server implementation of the DistressThermometer task.

61 """

62

63 __tablename__ = "distressthermometer"

64 shortname = "Distress Thermometer"

65

66 @classmethod

67 def extend_columns(

68 cls: Type["DistressThermometer"], **kwargs: Any

69 ) -> None:

70 add_multiple_columns(

71 cls,

72 "q",

73 1,

74 cls.NQUESTIONS,

75 pv=PV.BIT,

76 comment_fmt="{n}. {s} (0 no, 1 yes)",

77 comment_strings=[

78 "child care",

79 "housing",

80 "insurance/financial",

81 "transportation",

82 "work/school",

83 "children",

84 "partner",

85 "close friend/relative",

86 "depression",

87 "fears",

88 "nervousness",

89 "sadness",

90 "worry",

91 "loss of interest",

92 "spiritual/religious",

93 "appearance",

94 "bathing/dressing",

95 "breathing",

96 "urination",

97 "constipation",

98 "diarrhoea",

99 "eating",

100 "fatigue",

101 "feeling swollen",

102 "fevers",

103 "getting around",

104 "indigestion",

105 "memory/concentration",

106 "mouth sores",

107 "nausea",

108 "nose dry/congested",

109 "pain",

110 "sexual",

111 "skin dry/itchy",

112 "sleep",

113 "tingling in hands/feet",

114 ],

115 )

116

117 distress: Mapped[Optional[int]] = mapped_camcops_column(

118 permitted_value_checker=PermittedValueChecker(minimum=0, maximum=10),

119 comment="Distress (0 none - 10 extreme)",

120 )

121 other: Mapped[Optional[str]] = mapped_column(

122 UnicodeText, comment="Other problems"

123 )

124

125 NQUESTIONS = 36

126 COMPLETENESS_FIELDS = strseq("q", 1, NQUESTIONS) + ["distress"]

127

128 @staticmethod

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

130 _ = req.gettext

131 return _("Distress Thermometer")

132

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

134 if self.distress is None:

135 return CTV_INCOMPLETE

136 return [CtvInfo(content=f"Overall distress: {self.distress}/10")]

137

138 def is_complete(self) -> bool:

139 return (

140 self.all_fields_not_none(self.COMPLETENESS_FIELDS)

141 and self.field_contents_valid()

142 )

143

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

145 h = f"""

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

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

148 {self.get_is_complete_tr(req)}

149 {tr_qa("Overall distress (0–10)", self.distress)}

150 </table>

151 </div>

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

153 All questions relate to distress/problems “in the past week,

154 including today” (yes = problem, no = no problem).

155 </div>

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

157 <tr>

158 <th width="50%">Question</th>

159 <th width="50%">Answer</th>

160 </tr>

161 """

162 h += tr_qa(

163 "Distress (0 no distress – 10 extreme distress)", self.distress

164 )

165 h += subheading_spanning_two_columns("Practical problems")

166 for i in range(1, 5 + 1):

167 h += tr_qa(

168 f"{i}. {self.wxstring(req, 'q' + str(i))}",

169 get_yes_no_none(req, getattr(self, "q" + str(i))),

170 )

171 h += subheading_spanning_two_columns("Family problems")

172 for i in range(6, 8 + 1):

173 h += tr_qa(

174 f"{i}. {self.wxstring(req, 'q' + str(i))}",

175 get_yes_no_none(req, getattr(self, "q" + str(i))),

176 )

177 h += subheading_spanning_two_columns("Emotional problems")

178 for i in range(9, 14 + 1):

179 h += tr_qa(

180 f"{i}. {self.wxstring(req, 'q' + str(i))}",

181 get_yes_no_none(req, getattr(self, "q" + str(i))),

182 )

183 h += subheading_spanning_two_columns("Spiritual problems")

184 for i in range(15, 15 + 1):

185 h += tr_qa(

186 f"{i}. {self.wxstring(req, 'q' + str(i))}",

187 get_yes_no_none(req, getattr(self, "q" + str(i))),

188 )

189 h += subheading_spanning_two_columns("Physical problems")

190 for i in range(16, self.NQUESTIONS + 1):

191 h += tr_qa(

192 f"{i}. {self.wxstring(req, 'q' + str(i))}",

193 get_yes_no_none(req, getattr(self, "q" + str(i))),

194 )

195 h += subheading_spanning_two_columns("Other problems")

196 h += tr_qa(self.wxstring(req, "other_s"), self.other)

197 h += """

198 </table>

199 """

200 return h