Coverage for tasks/service_satisfaction.py : 73%

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
3"""
4camcops_server/tasks/service_satisfaction.py
6===============================================================================
8 Copyright (C) 2012-2020 Rudolf Cardinal (rudolf@pobox.com).
10 This file is part of CamCOPS.
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.
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.
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/>.
25===============================================================================
27"""
29from typing import Optional
31from sqlalchemy.ext.declarative import declared_attr
32from sqlalchemy.sql.schema import Column
33from sqlalchemy.sql.sqltypes import Integer, UnicodeText
35from camcops_server.cc_modules.cc_constants import CssClass
36from camcops_server.cc_modules.cc_html import tr_qa
37from camcops_server.cc_modules.cc_request import CamcopsRequest
38from camcops_server.cc_modules.cc_sqla_coltypes import (
39 CamcopsColumn,
40 ZERO_TO_FOUR_CHECKER,
41)
42from camcops_server.cc_modules.cc_string import AS
43from camcops_server.cc_modules.cc_task import (
44 get_from_dict,
45 Task,
46 TaskHasPatientMixin,
47)
50# =============================================================================
51# Abstract base class
52# =============================================================================
54class AbstractSatisfaction(object):
55 # noinspection PyMethodParameters
56 @declared_attr
57 def service(cls) -> Column:
58 return Column(
59 "service", UnicodeText,
60 comment="Clinical service being rated"
61 )
63 # noinspection PyMethodParameters
64 @declared_attr
65 def rating(cls) -> Column:
66 return CamcopsColumn(
67 "rating", Integer,
68 permitted_value_checker=ZERO_TO_FOUR_CHECKER,
69 comment="Rating (0 very poor - 4 excellent)"
70 )
72 # noinspection PyMethodParameters
73 @declared_attr
74 def good(cls) -> Column:
75 return Column(
76 "good", UnicodeText,
77 comment="What has been good?"
78 )
80 # noinspection PyMethodParameters
81 @declared_attr
82 def bad(cls) -> Column:
83 return Column(
84 "bad", UnicodeText,
85 comment="What could be improved?"
86 )
88 TASK_FIELDS = ["service", "rating", "good", "bad"]
90 def is_complete(self) -> bool:
91 # noinspection PyUnresolvedReferences
92 return self.rating is not None and self.field_contents_valid()
93 # ... self.field_contents_valid() is from Task, and we are a mixin
95 def get_rating_text(self, req: CamcopsRequest) -> Optional[str]:
96 ratingdict = {
97 None: None,
98 0: req.wappstring(AS.SATIS_RATING_A_PREFIX + "0"),
99 1: req.wappstring(AS.SATIS_RATING_A_PREFIX + "1"),
100 2: req.wappstring(AS.SATIS_RATING_A_PREFIX + "2"),
101 3: req.wappstring(AS.SATIS_RATING_A_PREFIX + "3"),
102 4: req.wappstring(AS.SATIS_RATING_A_PREFIX + "4"),
103 }
104 return get_from_dict(ratingdict, self.rating)
106 def get_common_task_html(self,
107 req: CamcopsRequest,
108 rating_q: str,
109 good_q: str,
110 bad_q: str) -> str:
111 if self.rating is not None:
112 r = f"{self.rating}. {self.get_rating_text(req)}"
113 else:
114 r = None
115 # noinspection PyUnresolvedReferences
116 return f"""
117 <div class="{CssClass.SUMMARY}">
118 <table class="{CssClass.SUMMARY}">
119 {self.get_is_complete_tr(req)}
120 </table>
121 </div>
122 <table class="{CssClass.TASKDETAIL}">
123 <tr>
124 <th width="50%">Question</th>
125 <th width="50%">Answer</th>
126 </tr>
127 {tr_qa(req.wappstring(AS.SATIS_SERVICE_BEING_RATED),
128 self.service)}
129 {tr_qa(f"{rating_q} {self.service}?", r)}
130 {tr_qa(good_q, self.good)}
131 {tr_qa(bad_q, self.bad)}
132 </table>
133 """
134 # ... self.get_is_complete_tr() is from Task, and we are a mixin
136 def get_task_html(self, req: CamcopsRequest) -> str:
137 raise NotImplementedError("implement in subclass")
140# =============================================================================
141# PatientSatisfaction
142# =============================================================================
144class PatientSatisfaction(TaskHasPatientMixin, AbstractSatisfaction, Task):
145 """
146 Server implementation of the PatientSatisfaction task.
147 """
148 __tablename__ = "pt_satis"
149 shortname = "PatientSatisfaction"
151 @staticmethod
152 def longname(req: "CamcopsRequest") -> str:
153 _ = req.gettext
154 return _("Patient Satisfaction Scale")
156 def get_task_html(self, req: CamcopsRequest) -> str:
157 return self.get_common_task_html(
158 req,
159 req.wappstring(AS.SATIS_PT_RATING_Q),
160 req.wappstring(AS.SATIS_GOOD_Q),
161 req.wappstring(AS.SATIS_BAD_Q)
162 )
165# =============================================================================
166# ReferrerSatisfactionGen
167# =============================================================================
169class ReferrerSatisfactionGen(AbstractSatisfaction, Task):
170 """
171 Server implementation of the ReferrerSatisfactionSurvey task.
172 """
173 __tablename__ = "ref_satis_gen"
174 shortname = "ReferrerSatisfactionSurvey"
176 @staticmethod
177 def longname(req: "CamcopsRequest") -> str:
178 _ = req.gettext
179 return _("Referrer Satisfaction Scale, survey")
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 )
190# =============================================================================
191# ReferrerSatisfactionSpec
192# =============================================================================
194class ReferrerSatisfactionSpec(TaskHasPatientMixin, AbstractSatisfaction,
195 Task):
196 """
197 Server implementation of the ReferrerSatisfactionSpecific task.
198 """
199 __tablename__ = "ref_satis_spec"
200 shortname = "ReferrerSatisfactionSpecific"
202 @staticmethod
203 def longname(req: "CamcopsRequest") -> str:
204 _ = req.gettext
205 return _("Referrer Satisfaction Scale, patient-specific")
207 def get_task_html(self, req: CamcopsRequest) -> str:
208 return self.get_common_task_html(
209 req,
210 req.wappstring(AS.SATIS_REF_SPEC_RATING_Q),
211 req.wappstring(AS.SATIS_GOOD_Q),
212 req.wappstring(AS.SATIS_BAD_Q)
213 )