"""
camcops_server/tasks/khandaker_mojo_medicationtherapy.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 List, Optional, Type, TYPE_CHECKING
from sqlalchemy.sql.sqltypes import Float, Integer, UnicodeText
from camcops_server.cc_modules.cc_constants import CssClass
from camcops_server.cc_modules.cc_db import (
ancillary_relationship,
GenericTabletRecordMixin,
TaskDescendant,
)
from camcops_server.cc_modules.cc_html import answer, tr_qa
from camcops_server.cc_modules.cc_sqlalchemy import Base
from camcops_server.cc_modules.cc_sqla_coltypes import CamcopsColumn
from camcops_server.cc_modules.cc_task import Task, TaskHasPatientMixin
if TYPE_CHECKING:
from camcops_server.cc_modules.cc_request import CamcopsRequest
[docs]class KhandakerMojoTableItem(GenericTabletRecordMixin, TaskDescendant, Base):
__abstract__ = True
def any_fields_none(self) -> bool:
for f in self.mandatory_fields():
if getattr(self, f) is None:
return True
return False
@classmethod
def mandatory_fields(cls) -> List[str]:
raise NotImplementedError
def get_response_option(self, req: "CamcopsRequest") -> Optional[str]:
# Reads "self.response" from derived class.
# noinspection PyUnresolvedReferences
response = self.response # type: Optional[int]
if response is None:
return None
return self.task_ancestor().xstring(req, f"response_{response}")
# -------------------------------------------------------------------------
# TaskDescendant overrides
# -------------------------------------------------------------------------
@classmethod
def task_ancestor_class(cls) -> Optional[Type["Task"]]:
return KhandakerMojoMedicationTherapy
[docs] def task_ancestor(self) -> Optional["KhandakerMojoMedicationTherapy"]:
# Reads "self.medicationtable_id" from derived class.
# noinspection PyUnresolvedReferences
return KhandakerMojoMedicationTherapy.get_linked(
self.medicationtable_id, self
)
[docs]class KhandakerMojoMedicationItem(KhandakerMojoTableItem):
__tablename__ = "khandaker_mojo_medication_item"
medicationtable_id = CamcopsColumn(
"medicationtable_id",
Integer,
nullable=False,
comment="FK to medicationtable",
)
seqnum = CamcopsColumn(
"seqnum",
Integer,
nullable=False,
comment="Sequence number of this medication",
)
brand_name = CamcopsColumn("brand_name", UnicodeText, comment="Brand name")
chemical_name = CamcopsColumn(
"chemical_name", UnicodeText, comment="Chemical name for study team"
)
dose = CamcopsColumn("dose", UnicodeText, comment="Dose")
frequency = CamcopsColumn("frequency", UnicodeText, comment="Frequency")
duration_months = CamcopsColumn(
"duration_months", Float, comment="Duration (months)"
)
indication = CamcopsColumn(
"indication",
UnicodeText,
comment="Indication (what is the medication used for?)",
)
response = CamcopsColumn(
"response",
Integer,
comment=(
"1 = treats all symptoms, "
"2 = most symptoms, "
"3 = some symptoms, "
"4 = no symptoms)"
),
)
@classmethod
def mandatory_fields(cls) -> List[str]:
return [
"brand_name",
"chemical_name",
"dose",
"frequency",
"duration_months",
"indication",
"response",
]
def get_html_table_row(self, req: "CamcopsRequest") -> str:
return f"""
<tr>
<td>{answer(self.chemical_name)}</td>
<td>{answer(self.brand_name)}</td>
<td>{answer(self.dose)}</td>
<td>{answer(self.frequency)}</td>
<td>{answer(self.duration_months)}</td>
<td>{answer(self.indication)}</td>
<td>{answer(self.get_response_option(req))}</td>
</tr>
"""
[docs]class KhandakerMojoTherapyItem(KhandakerMojoTableItem):
__tablename__ = "khandaker_mojo_therapy_item"
medicationtable_id = CamcopsColumn(
"medicationtable_id",
Integer,
nullable=False,
comment="FK to medicationtable",
)
seqnum = CamcopsColumn(
"seqnum",
Integer,
nullable=False,
comment="Sequence number of this therapy",
)
therapy = CamcopsColumn("therapy", UnicodeText, comment="Therapy")
frequency = CamcopsColumn("frequency", UnicodeText, comment="Frequency")
sessions_completed = CamcopsColumn(
"sessions_completed", Integer, comment="Sessions completed"
)
sessions_planned = CamcopsColumn(
"sessions_planned", Integer, comment="Sessions planned"
)
indication = CamcopsColumn(
"indication",
UnicodeText,
comment="Indication (what is the medication used for?)",
)
response = CamcopsColumn(
"response",
Integer,
comment=(
"1 = treats all symptoms, "
"2 = most symptoms, "
"3 = some symptoms, "
"4 = no symptoms)"
),
)
@classmethod
def mandatory_fields(cls) -> List[str]:
return [
"therapy",
"frequency",
"sessions_completed",
"sessions_planned",
"indication",
"response",
]
def get_html_table_row(self, req: "CamcopsRequest") -> str:
return f"""
<tr>
<td>{answer(self.therapy)}</td>
<td>{answer(self.frequency)}</td>
<td>{answer(self.sessions_completed)}</td>
<td>{answer(self.sessions_planned)}</td>
<td>{answer(self.indication)}</td>
<td>{answer(self.get_response_option(req))}</td>
</tr>
"""
[docs]class KhandakerMojoMedicationTherapy(TaskHasPatientMixin, Task):
"""
Server implementation of the KhandakerMojoMedicationTherapy task
"""
__tablename__ = "khandaker_mojo_medicationtherapy"
shortname = "Khandaker_MOJO_MedicationTherapy"
info_filename_stem = "khandaker_mojo"
provides_trackers = False
medication_items = ancillary_relationship(
parent_class_name="KhandakerMojoMedicationTherapy",
ancillary_class_name="KhandakerMojoMedicationItem",
ancillary_fk_to_parent_attr_name="medicationtable_id",
ancillary_order_by_attr_name="seqnum",
) # type: List[KhandakerMojoMedicationItem]
therapy_items = ancillary_relationship(
parent_class_name="KhandakerMojoMedicationTherapy",
ancillary_class_name="KhandakerMojoTherapyItem",
ancillary_fk_to_parent_attr_name="medicationtable_id",
ancillary_order_by_attr_name="seqnum",
) # type: List[KhandakerMojoTherapyItem]
[docs] @staticmethod
def longname(req: "CamcopsRequest") -> str:
_ = req.gettext
return _("Khandaker GM — MOJO — Medications and therapies")
[docs] def is_complete(self) -> bool:
# Whilst it's almost certain that anyone completing this task would be
# on some kind of medication, we have no way of knowing when all
# medication has been added to the table
for item in self.medication_items:
if item.any_fields_none():
return False
for item in self.therapy_items:
if item.any_fields_none():
return False
return True
def get_num_medication_items(self) -> int:
return len(self.medication_items)
def get_num_therapy_items(self) -> int:
return len(self.therapy_items)
[docs] def get_task_html(self, req: "CamcopsRequest") -> str:
html = f"""
<div class="{CssClass.SUMMARY}">
<table class="{CssClass.SUMMARY}">
{self.get_is_complete_tr(req)}
{tr_qa("Number of medications",
self.get_num_medication_items())}
{tr_qa("Number of therapies",
self.get_num_therapy_items())}
</table>
</div>
<table class="{CssClass.TASKDETAIL}">
<tr>
<th>{self.xstring(req, "chemical_name")}</th>
<th>{self.xstring(req, "brand_name")}</th>
<th>{self.xstring(req, "dose")}</th>
<th>{self.xstring(req, "frequency")}</th>
<th>{self.xstring(req, "duration_months")}</th>
<th>{self.xstring(req, "indication")}</th>
<th>{self.xstring(req, "response")}</th>
</tr>
"""
for item in self.medication_items:
html += item.get_html_table_row(req)
html += f"""
</table>
<table class="{CssClass.TASKDETAIL}">
<tr>
<th>{self.xstring(req, "therapy")}</th>
<th>{self.xstring(req, "frequency")}</th>
<th>{self.xstring(req, "sessions_completed")}</th>
<th>{self.xstring(req, "sessions_planned")}</th>
<th>{self.xstring(req, "indication")}</th>
<th>{self.xstring(req, "response")}</th>
</tr>
"""
for item in self.therapy_items:
html += item.get_html_table_row(req)
html += """
</table>
"""
return html