Coverage for tasks/apeqpt.py: 47%
60 statements
« prev ^ index » next coverage.py v6.5.0, created at 2022-11-08 23:14 +0000
« prev ^ index » next coverage.py v6.5.0, created at 2022-11-08 23:14 +0000
1#!/usr/bin/env python
3"""
4camcops_server/tasks/apeqpt.py
6===============================================================================
8 Copyright (C) 2012, University of Cambridge, Department of Psychiatry.
9 Created by Rudolf Cardinal (rnc1001@cam.ac.uk).
11 This file is part of CamCOPS.
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.
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.
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/>.
26===============================================================================
28- By Joe Kearney, Rudolf Cardinal.
30"""
32from typing import Dict, List
34from sqlalchemy.sql.sqltypes import Integer, UnicodeText
36from camcops_server.cc_modules.cc_constants import CssClass
37from camcops_server.cc_modules.cc_fhir import (
38 FHIRAnsweredQuestion,
39 FHIRAnswerType,
40 FHIRQuestionType,
41)
42from camcops_server.cc_modules.cc_html import tr_qa
43from camcops_server.cc_modules.cc_request import CamcopsRequest
44from camcops_server.cc_modules.cc_sqla_coltypes import (
45 CamcopsColumn,
46 PendulumDateTimeAsIsoTextColType,
47 ZERO_TO_ONE_CHECKER,
48 ZERO_TO_TWO_CHECKER,
49 ZERO_TO_FOUR_CHECKER,
50)
51from camcops_server.cc_modules.cc_summaryelement import SummaryElement
52from camcops_server.cc_modules.cc_task import get_from_dict, Task
55# =============================================================================
56# APEQPT
57# =============================================================================
60class Apeqpt(Task):
61 """
62 Server implementation of the APEQPT task.
63 """
65 __tablename__ = "apeqpt"
66 shortname = "APEQPT"
67 provides_trackers = True
69 # todo: remove q_datetime (here and in the C++) -- it duplicates when_created # noqa
70 q_datetime = CamcopsColumn(
71 "q_datetime",
72 PendulumDateTimeAsIsoTextColType,
73 comment="Date/time the assessment tool was completed",
74 )
76 N_CHOICE_QUESTIONS = 3
77 q1_choice = CamcopsColumn(
78 "q1_choice",
79 Integer,
80 comment="Enough information was provided (0 no, 1 yes)",
81 permitted_value_checker=ZERO_TO_ONE_CHECKER,
82 )
83 q2_choice = CamcopsColumn(
84 "q2_choice",
85 Integer,
86 comment="Treatment preference (0 no, 1 yes)",
87 permitted_value_checker=ZERO_TO_ONE_CHECKER,
88 )
89 q3_choice = CamcopsColumn(
90 "q3_choice",
91 Integer,
92 comment="Preference offered (0 no, 1 yes, 2 N/A)",
93 permitted_value_checker=ZERO_TO_TWO_CHECKER,
94 )
96 q1_satisfaction = CamcopsColumn(
97 "q1_satisfaction",
98 Integer,
99 comment=(
100 "Patient satisfaction (0 not at all satisfied - "
101 "4 completely satisfied)"
102 ),
103 permitted_value_checker=ZERO_TO_FOUR_CHECKER,
104 )
105 q2_satisfaction = CamcopsColumn(
106 "q2_satisfaction", UnicodeText, comment="Service experience"
107 )
109 MAIN_QUESTIONS = [
110 "q_datetime",
111 "q1_choice",
112 "q2_choice",
113 "q3_choice",
114 "q1_satisfaction",
115 ]
117 @staticmethod
118 def longname(req: "CamcopsRequest") -> str:
119 _ = req.gettext
120 return _(
121 "Assessment Patient Experience Questionnaire "
122 "for Psychological Therapies"
123 )
125 def is_complete(self) -> bool:
126 if self.any_fields_none(self.MAIN_QUESTIONS):
127 return False
128 if not self.field_contents_valid():
129 return False
130 return True
132 def get_summaries(self, req: CamcopsRequest) -> List[SummaryElement]:
133 return self.standard_task_summary_fields()
135 def get_task_html(self, req: CamcopsRequest) -> str:
136 c_dict = {
137 0: "0 — " + self.wxstring(req, "a0_choice"),
138 1: "1 — " + self.wxstring(req, "a1_choice"),
139 2: "2 — " + self.wxstring(req, "a2_choice"),
140 }
141 s_dict = {
142 0: "0 — " + self.wxstring(req, "a0_satisfaction"),
143 1: "1 — " + self.wxstring(req, "a1_satisfaction"),
144 2: "2 — " + self.wxstring(req, "a2_satisfaction"),
145 3: "3 — " + self.wxstring(req, "a3_satisfaction"),
146 4: "4 — " + self.wxstring(req, "a4_satisfaction"),
147 }
148 q_a = ""
149 for i in range(1, self.N_CHOICE_QUESTIONS + 1):
150 nstr = str(i)
151 q_a += tr_qa(
152 self.wxstring(req, "q" + nstr + "_choice"),
153 get_from_dict(c_dict, getattr(self, "q" + nstr + "_choice")),
154 )
156 q_a += tr_qa(
157 self.wxstring(req, "q1_satisfaction"),
158 get_from_dict(s_dict, self.q1_satisfaction),
159 )
160 q_a += tr_qa(
161 self.wxstring(req, "q2_satisfaction"),
162 self.q2_satisfaction,
163 default="",
164 )
166 return f"""
167 <div class="{CssClass.SUMMARY}">
168 <table class="{CssClass.SUMMARY}">
169 {self.get_is_complete_tr(req)}
170 </table>
171 </div>
172 <div class="{CssClass.EXPLANATION}">
173 Patient satisfaction rating for service provided. The service
174 is rated on choice offered and general satisfaction.
175 </div>
176 <table class="{CssClass.TASKDETAIL}">
177 <tr>
178 <th width="60%">Question</th>
179 <th width="40%">Answer</th>
180 </tr>
181 {q_a}
182 </table>
183 """
185 def get_fhir_questionnaire(
186 self, req: "CamcopsRequest"
187 ) -> List[FHIRAnsweredQuestion]:
188 items = [] # type: List[FHIRAnsweredQuestion]
190 yes_no_options = {} # type: Dict[int, str]
191 for index in range(2):
192 yes_no_options[index] = self.wxstring(req, f"a{index}_choice")
193 items.append(
194 FHIRAnsweredQuestion(
195 qname="q1_choice",
196 qtext=self.wxstring(req, "q1_choice"),
197 qtype=FHIRQuestionType.CHOICE,
198 answer_type=FHIRAnswerType.INTEGER,
199 answer=self.q1_choice,
200 answer_options=yes_no_options,
201 )
202 )
203 items.append(
204 FHIRAnsweredQuestion(
205 qname="q2_choice",
206 qtext=self.wxstring(req, "q2_choice"),
207 qtype=FHIRQuestionType.CHOICE,
208 answer_type=FHIRAnswerType.INTEGER,
209 answer=self.q2_choice,
210 answer_options=yes_no_options,
211 )
212 )
214 yes_no_na_options = yes_no_options.copy()
215 yes_no_na_options[2] = self.wxstring(req, "a2_choice")
216 items.append(
217 FHIRAnsweredQuestion(
218 qname="q3_choice",
219 qtext=self.wxstring(req, "q3_choice"),
220 qtype=FHIRQuestionType.CHOICE,
221 answer_type=FHIRAnswerType.INTEGER,
222 answer=self.q3_choice,
223 answer_options=yes_no_na_options,
224 )
225 )
227 satisfaction_options = {} # type: Dict[int, str]
228 for index in range(5):
229 satisfaction_options[index] = self.wxstring(
230 req, f"a{index}_satisfaction"
231 )
232 items.append(
233 FHIRAnsweredQuestion(
234 qname="q1_satisfaction",
235 qtext=self.xstring(req, "q1_satisfaction"),
236 qtype=FHIRQuestionType.CHOICE,
237 answer_type=FHIRAnswerType.INTEGER,
238 answer=self.q1_satisfaction,
239 answer_options=satisfaction_options,
240 )
241 )
243 items.append(
244 FHIRAnsweredQuestion(
245 qname="q2_satisfaction",
246 qtext=self.xstring(req, "q2_satisfaction"),
247 qtype=FHIRQuestionType.STRING,
248 answer_type=FHIRAnswerType.STRING,
249 answer=self.q2_satisfaction,
250 )
251 )
253 return items