Coverage for tasks/zbi.py : 64%

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/zbi.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 Any, Dict, List, Tuple, Type
31from cardinal_pythonlib.stringfunc import strseq
32from sqlalchemy.ext.declarative import DeclarativeMeta
33from sqlalchemy.sql.sqltypes import Integer
35from camcops_server.cc_modules.cc_constants import (
36 CssClass,
37 DATA_COLLECTION_UNLESS_UPGRADED_DIV,
38)
39from camcops_server.cc_modules.cc_ctvinfo import CTV_INCOMPLETE, CtvInfo
40from camcops_server.cc_modules.cc_db import add_multiple_columns
41from camcops_server.cc_modules.cc_html import answer, tr
42from camcops_server.cc_modules.cc_request import CamcopsRequest
43from camcops_server.cc_modules.cc_string import AS
44from camcops_server.cc_modules.cc_summaryelement import SummaryElement
45from camcops_server.cc_modules.cc_task import (
46 get_from_dict,
47 Task,
48 TaskHasPatientMixin,
49 TaskHasRespondentMixin,
50)
53# =============================================================================
54# ZBI
55# =============================================================================
57class Zbi12Metaclass(DeclarativeMeta):
58 # noinspection PyInitNewSignature
59 def __init__(cls: Type['Zbi12'],
60 name: str,
61 bases: Tuple[Type, ...],
62 classdict: Dict[str, Any]) -> None:
63 add_multiple_columns(
64 cls, "q", 1, cls.NQUESTIONS,
65 minimum=cls.MIN_PER_Q, maximum=cls.MAX_PER_Q,
66 comment_fmt="Q{n}, {s} (0-4, higher worse)",
67 comment_strings=[
68 "insufficient time for self", # 1
69 "stressed with other responsibilities",
70 "angry",
71 "other relationships affected",
72 "strained", # 5
73 "health suffered",
74 "insufficient privacy",
75 "social life suffered",
76 "lost control",
77 "uncertain", # 10
78 "should do more",
79 "could care better"
80 ]
81 )
82 super().__init__(name, bases, classdict)
85class Zbi12(TaskHasRespondentMixin, TaskHasPatientMixin, Task,
86 metaclass=Zbi12Metaclass):
87 """
88 Server implementation of the ZBI-12 task.
89 """
90 __tablename__ = "zbi12"
91 shortname = "ZBI-12"
93 MIN_PER_Q = 0
94 MAX_PER_Q = 4
95 NQUESTIONS = 12
96 TASK_FIELDS = strseq("q", 1, NQUESTIONS)
97 MAX_TOTAL = MAX_PER_Q * NQUESTIONS
99 @staticmethod
100 def longname(req: "CamcopsRequest") -> str:
101 _ = req.gettext
102 return _("Zarit Burden Interview-12")
104 def get_summaries(self, req: CamcopsRequest) -> List[SummaryElement]:
105 return self.standard_task_summary_fields() + [
106 SummaryElement(
107 name="total_score", coltype=Integer(),
108 value=self.total_score(),
109 comment=f"Total score (/ {self.MAX_TOTAL})"
110 ),
111 ]
113 def get_clinical_text(self, req: CamcopsRequest) -> List[CtvInfo]:
114 if not self.is_complete():
115 return CTV_INCOMPLETE
116 return [CtvInfo(
117 content=f"ZBI-12 total score {self.total_score()}/{self.MAX_TOTAL}"
118 )]
120 def total_score(self) -> int:
121 return self.sum_fields(self.TASK_FIELDS)
123 def is_complete(self) -> bool:
124 return (
125 self.field_contents_valid() and
126 self.is_respondent_complete() and
127 self.all_fields_not_none(self.TASK_FIELDS)
128 )
130 def get_task_html(self, req: CamcopsRequest) -> str:
131 option_dict = {None: None}
132 for a in range(self.MIN_PER_Q, self.MAX_PER_Q + 1):
133 option_dict[a] = req.wappstring(AS.ZBI_A_PREFIX + str(a))
134 h = f"""
135 <div class="{CssClass.SUMMARY}">
136 <table class="{CssClass.SUMMARY}">
137 {self.get_is_complete_tr(req)}
138 <tr>
139 <td>Total score (/ {self.MAX_TOTAL})</td>
140 <td>{answer(self.total_score())}</td>
141 </td>
142 </table>
143 </div>
144 <table class="{CssClass.TASKDETAIL}">
145 <tr>
146 <th width="75%">Question</th>
147 <th width="25%">Answer ({self.MIN_PER_Q}–{self.MAX_PER_Q})
148 </th>
149 </tr>
150 """
151 for q in range(1, self.NQUESTIONS + 1):
152 a = getattr(self, "q" + str(q))
153 fa = (f"{a}: {get_from_dict(option_dict, a)}"
154 if a is not None else None)
155 h += tr(self.wxstring(req, "q" + str(q)), answer(fa))
156 h += """
157 </table>
158 """ + DATA_COLLECTION_UNLESS_UPGRADED_DIV
159 return h