Coverage for tasks/ors.py: 59%

1"""

2 camcops_server/tasks/ors.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- By Joe Kearney, Rudolf Cardinal.

27

28"""

29

30 import datetime

31 from typing import List, Optional

32

33 from sqlalchemy.orm import Mapped

34 from sqlalchemy.sql.sqltypes import UnicodeText

35

36 from camcops_server.cc_modules.cc_constants import CssClass

37 from camcops_server.cc_modules.cc_html import tr_qa

38 from camcops_server.cc_modules.cc_request import CamcopsRequest

39 from camcops_server.cc_modules.cc_sqla_coltypes import (

40 mapped_camcops_column,

41 ZERO_TO_10_CHECKER,

42)

43 from camcops_server.cc_modules.cc_summaryelement import SummaryElement

44 from camcops_server.cc_modules.cc_task import Task, TaskHasPatientMixin

45

46

47# =============================================================================

48# ORS

49# =============================================================================

50

51

52 class Ors(TaskHasPatientMixin, Task): # type: ignore[misc]

53 """

54 Server implementation of the PHQ9 task.

55 """

56

57 __tablename__ = "ors"

58 shortname = "ORS"

59 provides_trackers = True

60

61 COMPLETED_BY_SELF = 0

62 COMPLETED_BY_OTHER = 1

63

64 VAS_MIN_INT = 0

65 VAS_MAX_INT = 10

66

67 q_session: Mapped[Optional[int]] = mapped_camcops_column(

68 comment="Session number"

69 )

70 q_date: Mapped[Optional[datetime.date]] = mapped_camcops_column(

71 comment="Session date"

72 )

73 q_who: Mapped[Optional[int]] = mapped_camcops_column(

74 comment="Completed by"

75 )

76 q_who_other: Mapped[Optional[str]] = mapped_camcops_column(

77 UnicodeText, comment="Completed by other: who?"

78 )

79 q_individual: Mapped[Optional[float]] = mapped_camcops_column(

80 comment="Individual rating (0-10, 10 better)",

81 permitted_value_checker=ZERO_TO_10_CHECKER,

82 )

83 q_interpersonal: Mapped[Optional[float]] = mapped_camcops_column(

84 comment="Interpersonal rating (0-10, 10 better)",

85 permitted_value_checker=ZERO_TO_10_CHECKER,

86 )

87 q_social: Mapped[Optional[float]] = mapped_camcops_column(

88 comment="Social rating (0-10, 10 better)",

89 permitted_value_checker=ZERO_TO_10_CHECKER,

90 )

91 q_overall: Mapped[Optional[float]] = mapped_camcops_column(

92 comment="Overall rating (0-10, 10 better)",

93 permitted_value_checker=ZERO_TO_10_CHECKER,

94 )

95

96 @staticmethod

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

98 _ = req.gettext

99 return _("Outcome Rating Scale")

100

101 def is_complete(self) -> bool:

102 required_always = [

103 "q_session",

104 "q_date",

105 "q_who",

106 "q_individual",

107 "q_interpersonal",

108 "q_social",

109 "q_overall",

110 ]

111 for field in required_always:

112 if getattr(self, field) is None:

113 return False

114 if self.q_who == self.COMPLETED_BY_OTHER:

115 if not self.q_who_other:

116 return False

117 return True

118

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

120 return self.standard_task_summary_fields()

121

122 def who(self) -> str:

123 if self.q_who == self.COMPLETED_BY_OTHER:

124 return "Other: " + (self.q_who_other or "Unknown")

125 if self.q_who == self.COMPLETED_BY_SELF:

126 return "Patient"

127 return "Unknown"

128

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

130 fields = ["q_individual", "q_interpersonal", "q_social", "q_overall"]

131 q_a = ""

132 for field in fields:

133 question = field.split("_")[1].capitalize()

134 q_a += tr_qa(question, getattr(self, field))

135

136 return f"""

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

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

139 {self.get_is_complete_tr(req)}

140 {tr_qa("Session number", self.q_session)}

141 {tr_qa("Completed by", self.who())}

142 </table>

143 </div>

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

145 Scores represent a selection on a scale from

146 {self.VAS_MIN_INT} to {self.VAS_MAX_INT}

147 ({self.VAS_MAX_INT} better). Scores reflect the patient’s

148 feelings about the indicated life areas over the past week.

149 </div>

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

151 <tr>

152 <th width="60%">Question</th>

153 <th width="40%">Answer</th>

154 </tr>

155 {q_a}

156 </table>

157 <div class="{CssClass.FOOTNOTES}">

158 </div>

159 """