Coverage for tasks/service_satisfaction.py: 75%

67 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/service_satisfaction.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 Optional 

31 

32from sqlalchemy.ext.declarative import declared_attr 

33from sqlalchemy.sql.schema import Column 

34from sqlalchemy.sql.sqltypes import Integer, 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 CamcopsColumn, 

41 ZERO_TO_FOUR_CHECKER, 

42) 

43from camcops_server.cc_modules.cc_string import AS 

44from camcops_server.cc_modules.cc_task import ( 

45 get_from_dict, 

46 Task, 

47 TaskHasPatientMixin, 

48) 

49 

50 

51# ============================================================================= 

52# Abstract base class 

53# ============================================================================= 

54 

55 

56class AbstractSatisfaction(object): 

57 # noinspection PyMethodParameters 

58 @declared_attr 

59 def service(cls) -> Column: 

60 return Column( 

61 "service", UnicodeText, comment="Clinical service being rated" 

62 ) 

63 

64 # noinspection PyMethodParameters 

65 @declared_attr 

66 def rating(cls) -> Column: 

67 return CamcopsColumn( 

68 "rating", 

69 Integer, 

70 permitted_value_checker=ZERO_TO_FOUR_CHECKER, 

71 comment="Rating (0 very poor - 4 excellent)", 

72 ) 

73 

74 # noinspection PyMethodParameters 

75 @declared_attr 

76 def good(cls) -> Column: 

77 return Column("good", UnicodeText, comment="What has been good?") 

78 

79 # noinspection PyMethodParameters 

80 @declared_attr 

81 def bad(cls) -> Column: 

82 return Column("bad", UnicodeText, comment="What could be improved?") 

83 

84 TASK_FIELDS = ["service", "rating", "good", "bad"] 

85 

86 def is_complete(self) -> bool: 

87 # noinspection PyUnresolvedReferences 

88 return self.rating is not None and self.field_contents_valid() 

89 # ... self.field_contents_valid() is from Task, and we are a mixin 

90 

91 def get_rating_text(self, req: CamcopsRequest) -> Optional[str]: 

92 ratingdict = { 

93 None: None, 

94 0: req.wappstring(AS.SATIS_RATING_A_PREFIX + "0"), 

95 1: req.wappstring(AS.SATIS_RATING_A_PREFIX + "1"), 

96 2: req.wappstring(AS.SATIS_RATING_A_PREFIX + "2"), 

97 3: req.wappstring(AS.SATIS_RATING_A_PREFIX + "3"), 

98 4: req.wappstring(AS.SATIS_RATING_A_PREFIX + "4"), 

99 } 

100 return get_from_dict(ratingdict, self.rating) 

101 

102 def get_common_task_html( 

103 self, req: CamcopsRequest, rating_q: str, good_q: str, bad_q: str 

104 ) -> str: 

105 if self.rating is not None: 

106 r = f"{self.rating}. {self.get_rating_text(req)}" 

107 else: 

108 r = None 

109 # noinspection PyUnresolvedReferences 

110 return f""" 

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

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

113 {self.get_is_complete_tr(req)} 

114 </table> 

115 </div> 

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

117 <tr> 

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

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

120 </tr> 

121 {tr_qa(req.wappstring(AS.SATIS_SERVICE_BEING_RATED), 

122 self.service)} 

123 {tr_qa(f"{rating_q} {self.service}?", r)} 

124 {tr_qa(good_q, self.good)} 

125 {tr_qa(bad_q, self.bad)} 

126 </table> 

127 """ 

128 # ... self.get_is_complete_tr() is from Task, and we are a mixin 

129 

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

131 raise NotImplementedError("implement in subclass") 

132 

133 

134# ============================================================================= 

135# PatientSatisfaction 

136# ============================================================================= 

137 

138 

139class PatientSatisfaction(TaskHasPatientMixin, AbstractSatisfaction, Task): 

140 """ 

141 Server implementation of the PatientSatisfaction task. 

142 """ 

143 

144 __tablename__ = "pt_satis" 

145 shortname = "PatientSatisfaction" 

146 info_filename_stem = "pss" 

147 

148 @staticmethod 

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

150 _ = req.gettext 

151 return _("Patient Satisfaction Scale") 

152 

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

154 return self.get_common_task_html( 

155 req, 

156 req.wappstring(AS.SATIS_PT_RATING_Q), 

157 req.wappstring(AS.SATIS_GOOD_Q), 

158 req.wappstring(AS.SATIS_BAD_Q), 

159 ) 

160 

161 

162# ============================================================================= 

163# ReferrerSatisfactionGen 

164# ============================================================================= 

165 

166 

167class ReferrerSatisfactionGen(AbstractSatisfaction, Task): 

168 """ 

169 Server implementation of the ReferrerSatisfactionSurvey task. 

170 """ 

171 

172 __tablename__ = "ref_satis_gen" 

173 shortname = "ReferrerSatisfactionSurvey" 

174 info_filename_stem = "rss" 

175 

176 @staticmethod 

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

178 _ = req.gettext 

179 return _("Referrer Satisfaction Scale, survey") 

180 

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

182 return self.get_common_task_html( 

183 req, 

184 req.wappstring(AS.SATIS_REF_GEN_RATING_Q), 

185 req.wappstring(AS.SATIS_GOOD_Q), 

186 req.wappstring(AS.SATIS_BAD_Q), 

187 ) 

188 

189 

190# ============================================================================= 

191# ReferrerSatisfactionSpec 

192# ============================================================================= 

193 

194 

195class ReferrerSatisfactionSpec( 

196 TaskHasPatientMixin, AbstractSatisfaction, Task 

197): 

198 """ 

199 Server implementation of the ReferrerSatisfactionSpecific task. 

200 """ 

201 

202 __tablename__ = "ref_satis_spec" 

203 shortname = "ReferrerSatisfactionSpecific" 

204 info_filename_stem = "rss" 

205 

206 @staticmethod 

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

208 _ = req.gettext 

209 return _("Referrer Satisfaction Scale, patient-specific") 

210 

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

212 return self.get_common_task_html( 

213 req, 

214 req.wappstring(AS.SATIS_REF_SPEC_RATING_Q), 

215 req.wappstring(AS.SATIS_GOOD_Q), 

216 req.wappstring(AS.SATIS_BAD_Q), 

217 )