Coverage for tasks/ors.py: 59%

54 statements  

« prev     ^ index     » next       coverage.py v7.9.2, created at 2025-07-15 14:23 +0100

1""" 

2camcops_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 

30import datetime 

31from typing import List, Optional 

32 

33from sqlalchemy.orm import Mapped 

34from sqlalchemy.sql.sqltypes import UnicodeText 

35 

36from camcops_server.cc_modules.cc_constants import CssClass 

37from camcops_server.cc_modules.cc_html import tr_qa 

38from camcops_server.cc_modules.cc_request import CamcopsRequest 

39from camcops_server.cc_modules.cc_sqla_coltypes import ( 

40 mapped_camcops_column, 

41 ZERO_TO_10_CHECKER, 

42) 

43from camcops_server.cc_modules.cc_summaryelement import SummaryElement 

44from camcops_server.cc_modules.cc_task import Task, TaskHasPatientMixin 

45 

46 

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

48# ORS 

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

50 

51 

52class 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 """