Coverage for tasks/icd10mixed.py: 62%
50 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/icd10mixed.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"""
30from typing import List, Optional
32from cardinal_pythonlib.datetimefunc import format_datetime
33from cardinal_pythonlib.typetests import is_false
34import cardinal_pythonlib.rnc_web as ws
35from sqlalchemy.sql.schema import Column
36from sqlalchemy.sql.sqltypes import Boolean, Date, UnicodeText
38from camcops_server.cc_modules.cc_constants import (
39 CssClass,
40 DateFormat,
41 ICD10_COPYRIGHT_DIV,
42)
43from camcops_server.cc_modules.cc_ctvinfo import CTV_INCOMPLETE, CtvInfo
44from camcops_server.cc_modules.cc_html import get_true_false_none, tr_qa
45from camcops_server.cc_modules.cc_request import CamcopsRequest
46from camcops_server.cc_modules.cc_sqla_coltypes import (
47 BIT_CHECKER,
48 CamcopsColumn,
49)
50from camcops_server.cc_modules.cc_string import AS
51from camcops_server.cc_modules.cc_summaryelement import SummaryElement
52from camcops_server.cc_modules.cc_task import (
53 Task,
54 TaskHasClinicianMixin,
55 TaskHasPatientMixin,
56)
57from camcops_server.cc_modules.cc_text import SS
60# =============================================================================
61# Icd10Mixed
62# =============================================================================
65class Icd10Mixed(TaskHasClinicianMixin, TaskHasPatientMixin, Task):
66 """
67 Server implementation of the ICD10-MIXED task.
68 """
70 __tablename__ = "icd10mixed"
71 shortname = "ICD10-MIXED"
72 info_filename_stem = "icd"
74 date_pertains_to = Column(
75 "date_pertains_to", Date, comment="Date the assessment pertains to"
76 )
77 comments = Column("comments", UnicodeText, comment="Clinician's comments")
78 mixture_or_rapid_alternation = CamcopsColumn(
79 "mixture_or_rapid_alternation",
80 Boolean,
81 permitted_value_checker=BIT_CHECKER,
82 comment="The episode is characterized by either a mixture or "
83 "a rapid alternation (i.e. within a few hours) of hypomanic, "
84 "manic and depressive symptoms.",
85 )
86 duration_at_least_2_weeks = CamcopsColumn(
87 "duration_at_least_2_weeks",
88 Boolean,
89 permitted_value_checker=BIT_CHECKER,
90 comment="Both manic and depressive symptoms must be prominent"
91 " most of the time during a period of at least two weeks.",
92 )
94 @staticmethod
95 def longname(req: "CamcopsRequest") -> str:
96 _ = req.gettext
97 return _(
98 "ICD-10 symptomatic criteria for a mixed affective episode "
99 "(as in e.g. F06.3, F25, F38.00, F31.6)"
100 )
102 def get_clinical_text(self, req: CamcopsRequest) -> List[CtvInfo]:
103 if not self.is_complete():
104 return CTV_INCOMPLETE
105 category = (
106 "Meets" if self.meets_criteria() else "Does not meet"
107 ) + " criteria for mixed affective episode"
108 infolist = [
109 CtvInfo(
110 content="Pertains to: {}. {}.".format(
111 format_datetime(
112 self.date_pertains_to, DateFormat.LONG_DATE
113 ),
114 category,
115 )
116 )
117 ]
118 if self.comments:
119 infolist.append(CtvInfo(content=ws.webify(self.comments)))
120 return infolist
122 def get_summaries(self, req: CamcopsRequest) -> List[SummaryElement]:
123 return self.standard_task_summary_fields() + [
124 SummaryElement(
125 name="meets_criteria",
126 coltype=Boolean(),
127 value=self.meets_criteria(),
128 comment="Meets criteria for a mixed affective episode?",
129 )
130 ]
132 # Meets criteria? These also return null for unknown.
133 def meets_criteria(self) -> Optional[bool]:
134 if (
135 self.mixture_or_rapid_alternation
136 and self.duration_at_least_2_weeks
137 ):
138 return True
139 if is_false(self.mixture_or_rapid_alternation):
140 return False
141 if is_false(self.duration_at_least_2_weeks):
142 return False
143 return None
145 def is_complete(self) -> bool:
146 return (
147 self.meets_criteria() is not None and self.field_contents_valid()
148 )
150 def get_task_html(self, req: CamcopsRequest) -> str:
151 return """
152 {clinician_comments}
153 <div class="{CssClass.SUMMARY}">
154 <table class="{CssClass.SUMMARY}">
155 {tr_is_complete}
156 {date_pertains_to}
157 {meets_criteria}
158 </table>
159 </div>
160 <div class="{CssClass.EXPLANATION}">
161 {icd10_symptomatic_disclaimer}
162 </div>
163 <table class="{CssClass.TASKDETAIL}">
164 <tr>
165 <th width="80%">Question</th>
166 <th width="20%">Answer</th>
167 </tr>
168 {mixture_or_rapid_alternation}
169 {duration_at_least_2_weeks}
170 </table>
171 {ICD10_COPYRIGHT_DIV}
172 """.format(
173 clinician_comments=self.get_standard_clinician_comments_block(
174 req, self.comments
175 ),
176 CssClass=CssClass,
177 tr_is_complete=self.get_is_complete_tr(req),
178 date_pertains_to=tr_qa(
179 req.wappstring(AS.DATE_PERTAINS_TO),
180 format_datetime(
181 self.date_pertains_to, DateFormat.LONG_DATE, default=None
182 ),
183 ),
184 meets_criteria=tr_qa(
185 req.sstring(SS.MEETS_CRITERIA),
186 get_true_false_none(req, self.meets_criteria()),
187 ),
188 icd10_symptomatic_disclaimer=req.wappstring(
189 AS.ICD10_SYMPTOMATIC_DISCLAIMER
190 ),
191 mixture_or_rapid_alternation=self.get_twocol_bool_row_true_false(
192 req, "mixture_or_rapid_alternation", self.wxstring(req, "a")
193 ),
194 duration_at_least_2_weeks=self.get_twocol_bool_row_true_false(
195 req, "duration_at_least_2_weeks", self.wxstring(req, "b")
196 ),
197 ICD10_COPYRIGHT_DIV=ICD10_COPYRIGHT_DIV,
198 )