Source code for camcops_server.tasks.cgi_task

#!/usr/bin/env python

"""
camcops_server/tasks/cgi_task.py

===============================================================================

    Copyright (C) 2012, University of Cambridge, Department of Psychiatry.
    Created by Rudolf Cardinal (rnc1001@cam.ac.uk).

    This file is part of CamCOPS.

    CamCOPS is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    CamCOPS is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with CamCOPS. If not, see <https://www.gnu.org/licenses/>.

===============================================================================

"""

from typing import Dict, List

from sqlalchemy.sql.sqltypes import Integer

from camcops_server.cc_modules.cc_constants import CssClass
from camcops_server.cc_modules.cc_ctvinfo import CTV_INCOMPLETE, CtvInfo
from camcops_server.cc_modules.cc_html import answer, italic, tr, tr_qa
from camcops_server.cc_modules.cc_request import CamcopsRequest
from camcops_server.cc_modules.cc_sqla_coltypes import (
    CamcopsColumn,
    PermittedValueChecker,
)
from camcops_server.cc_modules.cc_summaryelement import SummaryElement
from camcops_server.cc_modules.cc_task import (
    get_from_dict,
    Task,
    TaskHasClinicianMixin,
    TaskHasPatientMixin,
)
from camcops_server.cc_modules.cc_trackerhelpers import TrackerInfo


# =============================================================================
# CGI
# =============================================================================


[docs]class Cgi(TaskHasPatientMixin, TaskHasClinicianMixin, Task): """ Server implementation of the CGI task. """ __tablename__ = "cgi" shortname = "CGI" provides_trackers = True q1 = CamcopsColumn( "q1", Integer, permitted_value_checker=PermittedValueChecker(minimum=0, maximum=7), comment="Q1. Severity (1-7, higher worse, 0 not assessed)", ) q2 = CamcopsColumn( "q2", Integer, permitted_value_checker=PermittedValueChecker(minimum=0, maximum=7), comment="Q2. Global improvement (1-7, higher worse, 0 not assessed)", ) q3t = CamcopsColumn( "q3t", Integer, permitted_value_checker=PermittedValueChecker(minimum=0, maximum=4), comment="Q3T. Therapeutic effects (1-4, higher worse, 0 not assessed)", ) q3s = CamcopsColumn( "q3s", Integer, permitted_value_checker=PermittedValueChecker(minimum=0, maximum=4), comment="Q3S. Side effects (1-4, higher worse, 0 not assessed)", ) q3 = CamcopsColumn( "q3", Integer, permitted_value_checker=PermittedValueChecker(minimum=0, maximum=16), comment="Q3 (calculated). Efficacy index [(Q3T - 1) * 4 + Q3S].", ) TASK_FIELDS = ["q1", "q2", "q3t", "q3s", "q3"] MAX_SCORE = 30
[docs] @staticmethod def longname(req: "CamcopsRequest") -> str: _ = req.gettext return _("Clinical Global Impressions")
[docs] def get_trackers(self, req: CamcopsRequest) -> List[TrackerInfo]: return [ TrackerInfo( value=self.total_score(), plot_label="CGI total score", axis_label=f"Total score (out of {self.MAX_SCORE})", axis_min=-0.5, axis_max=self.MAX_SCORE + 0.5, ) ]
[docs] def get_clinical_text(self, req: CamcopsRequest) -> List[CtvInfo]: if not self.is_complete(): return CTV_INCOMPLETE return [ CtvInfo( content=( f"CGI total score {self.total_score()}/{self.MAX_SCORE}" ) ) ]
[docs] def get_summaries(self, req: CamcopsRequest) -> List[SummaryElement]: return self.standard_task_summary_fields() + [ SummaryElement( name="total", coltype=Integer(), value=self.total_score() ) ]
[docs] def is_complete(self) -> bool: if not ( self.all_fields_not_none(self.TASK_FIELDS) and self.field_contents_valid() ): return False # Requirement for everything to be non-zero removed in v2.0.0 # if self.q1 == 0 or self.q2 == 0 or self.q3t == 0 or self.q3s == 0: # return False return True
def total_score(self) -> int: return self.sum_fields(["q1", "q2", "q3"])
[docs] def get_task_html(self, req: CamcopsRequest) -> str: q1_dict = { None: None, 0: self.wxstring(req, "q1_option0"), 1: self.wxstring(req, "q1_option1"), 2: self.wxstring(req, "q1_option2"), 3: self.wxstring(req, "q1_option3"), 4: self.wxstring(req, "q1_option4"), 5: self.wxstring(req, "q1_option5"), 6: self.wxstring(req, "q1_option6"), 7: self.wxstring(req, "q1_option7"), } q2_dict = { None: None, 0: self.wxstring(req, "q2_option0"), 1: self.wxstring(req, "q2_option1"), 2: self.wxstring(req, "q2_option2"), 3: self.wxstring(req, "q2_option3"), 4: self.wxstring(req, "q2_option4"), 5: self.wxstring(req, "q2_option5"), 6: self.wxstring(req, "q2_option6"), 7: self.wxstring(req, "q2_option7"), } q3t_dict = { None: None, 0: self.wxstring(req, "q3t_option0"), 1: self.wxstring(req, "q3t_option1"), 2: self.wxstring(req, "q3t_option2"), 3: self.wxstring(req, "q3t_option3"), 4: self.wxstring(req, "q3t_option4"), } q3s_dict = { None: None, 0: self.wxstring(req, "q3s_option0"), 1: self.wxstring(req, "q3s_option1"), 2: self.wxstring(req, "q3s_option2"), 3: self.wxstring(req, "q3s_option3"), 4: self.wxstring(req, "q3s_option4"), } tr_total_score = tr( "Total score <sup>[1]</sup>", answer(self.total_score()) ) tr_q1 = tr_qa( self.wxstring(req, "q1_s") + " <sup>[2]</sup>", get_from_dict(q1_dict, self.q1), ) tr_q2 = tr_qa( self.wxstring(req, "q2_s") + " <sup>[2]</sup>", get_from_dict(q2_dict, self.q2), ) tr_q3t = tr_qa( self.wxstring(req, "q3t_s") + " <sup>[3]</sup>", get_from_dict(q3t_dict, self.q3t), ) tr_q3s = tr_qa( self.wxstring(req, "q3s_s") + " <sup>[3]</sup>", get_from_dict(q3s_dict, self.q3s), ) tr_q3 = tr( f""" {self.wxstring(req, "q3_s")} <sup>[4]</sup> <div class="{CssClass.SMALLPRINT}"> [(Q3T – 1) × 4 + Q3S] </div> """, answer(self.q3, formatter_answer=italic), ) return f""" <div class="{CssClass.SUMMARY}"> <table class="{CssClass.SUMMARY}"> {self.get_is_complete_tr(req)} {tr_total_score} </table> </div> <table class="{CssClass.TASKDETAIL}"> <tr> <th width="30%">Question</th> <th width="70%">Answer</th> </tr> {tr_q1} {tr_q2} {tr_q3t} {tr_q3s} {tr_q3} </table> <div class="{CssClass.FOOTNOTES}"> [1] Total score: Q1 + Q2 + Q3. Range 3–30 when complete. [2] Questions 1 and 2 are scored 1–7 (0 for not assessed). [3] Questions 3T and 3S are scored 1–4 (0 for not assessed). [4] Q3 is scored 1–16 if Q3T/Q3S complete. </div> """
# ============================================================================= # CGI-I # =============================================================================
[docs]class CgiI(TaskHasPatientMixin, TaskHasClinicianMixin, Task): __tablename__ = "cgi_i" shortname = "CGI-I" extrastring_taskname = "cgi" # shares with CGI info_filename_stem = "cgi" q = CamcopsColumn( "q", Integer, permitted_value_checker=PermittedValueChecker(minimum=0, maximum=7), comment="Global improvement (1-7, higher worse)", ) TASK_FIELDS = ["q"]
[docs] @staticmethod def longname(req: "CamcopsRequest") -> str: _ = req.gettext return _("Clinical Global Impressions – Improvement")
[docs] def get_clinical_text(self, req: CamcopsRequest) -> List[CtvInfo]: if not self.is_complete(): return CTV_INCOMPLETE return [ CtvInfo( content="CGI-I rating: {}".format(self.get_rating_text(req)) ) ]
[docs] def is_complete(self) -> bool: return ( self.all_fields_not_none(self.TASK_FIELDS) and self.field_contents_valid() )
def get_rating_text(self, req: CamcopsRequest) -> str: qdict = self.get_q_dict(req) return get_from_dict(qdict, self.q) def get_q_dict(self, req: CamcopsRequest) -> Dict: return { None: None, 0: self.wxstring(req, "q2_option0"), 1: self.wxstring(req, "q2_option1"), 2: self.wxstring(req, "q2_option2"), 3: self.wxstring(req, "q2_option3"), 4: self.wxstring(req, "q2_option4"), 5: self.wxstring(req, "q2_option5"), 6: self.wxstring(req, "q2_option6"), 7: self.wxstring(req, "q2_option7"), }
[docs] def get_task_html(self, req: CamcopsRequest) -> str: return f""" <div class="{CssClass.SUMMARY}"> <table class="{CssClass.SUMMARY}"> {self.get_is_complete_tr(req)} </table> </div> <table class="{CssClass.TASKDETAIL}"> <tr> <th width="50%">Question</th> <th width="50%">Answer</th> </tr> {tr_qa(self.wxstring(req, "i_q"), self.get_rating_text(req))} </table> """