Coverage for tasks/contactlog.py: 78%
36 statements
« prev ^ index » next coverage.py v7.9.2, created at 2025-07-15 14:23 +0100
« prev ^ index » next coverage.py v7.9.2, created at 2025-07-15 14:23 +0100
1"""
2camcops_server/tasks/contactlog.py
4===============================================================================
6 Copyright (C) 2012, University of Cambridge, Department of Psychiatry.
7 Created by Rudolf Cardinal (rnc1001@cam.ac.uk).
9 This file is part of CamCOPS.
11 CamCOPS is free software: you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation, either version 3 of the License, or
14 (at your option) any later version.
16 CamCOPS is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
21 You should have received a copy of the GNU General Public License
22 along with CamCOPS. If not, see <https://www.gnu.org/licenses/>.
24===============================================================================
26"""
28from typing import List, Optional
30from cardinal_pythonlib.datetimefunc import format_datetime, get_duration_h_m
31import cardinal_pythonlib.rnc_web as ws
32from pendulum import DateTime as Pendulum
33from sqlalchemy.orm import Mapped, mapped_column
34from sqlalchemy.sql.sqltypes import UnicodeText
36from camcops_server.cc_modules.cc_constants import CssClass, DateFormat
37from camcops_server.cc_modules.cc_ctvinfo import CTV_INCOMPLETE, CtvInfo
38from camcops_server.cc_modules.cc_html import (
39 italic,
40 get_yes_no_none,
41 tr,
42 tr_qa,
43)
44from camcops_server.cc_modules.cc_request import CamcopsRequest
45from camcops_server.cc_modules.cc_sqla_coltypes import (
46 mapped_camcops_column,
47 BIT_CHECKER,
48 PendulumDateTimeAsIsoTextColType,
49)
50from camcops_server.cc_modules.cc_task import (
51 Task,
52 TaskHasClinicianMixin,
53 TaskHasPatientMixin,
54)
57# =============================================================================
58# ContactLog
59# =============================================================================
62class ContactLog(TaskHasClinicianMixin, TaskHasPatientMixin, Task): # type: ignore[misc] # noqa: E501
63 """
64 Server implementation of the ContactLog task.
65 """
67 __tablename__ = "contactlog"
68 shortname = "ContactLog"
69 info_filename_stem = "clinical"
71 location: Mapped[Optional[str]] = mapped_column(
72 UnicodeText, comment="Location"
73 )
74 start: Mapped[Optional[Pendulum]] = mapped_column(
75 PendulumDateTimeAsIsoTextColType,
76 comment="Date/time that contact started",
77 )
78 end: Mapped[Optional[Pendulum]] = mapped_column(
79 "end",
80 PendulumDateTimeAsIsoTextColType,
81 comment="Date/time that contact ended",
82 )
83 patient_contact: Mapped[Optional[int]] = mapped_camcops_column(
84 permitted_value_checker=BIT_CHECKER,
85 comment="Patient contact involved (0 no, 1 yes)?",
86 )
87 staff_liaison: Mapped[Optional[int]] = mapped_camcops_column(
88 permitted_value_checker=BIT_CHECKER,
89 comment="Liaison with staff involved (0 no, 1 yes)?",
90 )
91 other_liaison: Mapped[Optional[int]] = mapped_camcops_column(
92 permitted_value_checker=BIT_CHECKER,
93 comment="Liaison with others (e.g. family) involved (0 no, 1 yes)?",
94 )
95 comment: Mapped[Optional[str]] = mapped_column(
96 "comment", UnicodeText, comment="Comment"
97 )
99 @staticmethod
100 def longname(req: "CamcopsRequest") -> str:
101 _ = req.gettext
102 return _("Clinical contact log")
104 def get_clinical_text(self, req: CamcopsRequest) -> List[CtvInfo]:
105 if not self.is_complete():
106 return CTV_INCOMPLETE
107 contact_type = "Patient" if self.patient_contact else "Non-patient"
108 return [
109 CtvInfo(
110 content=(
111 f"{contact_type} contact. Duration (hours:minutes) "
112 f"{get_duration_h_m(self.start, self.end)}."
113 )
114 )
115 ]
117 def is_complete(self) -> bool:
118 return (
119 self.start is not None
120 and self.end is not None
121 and self.field_contents_valid()
122 )
124 def get_task_html(self, req: CamcopsRequest) -> str:
125 return f"""
126 <table class="{CssClass.TASKDETAIL}">
127 <tr>
128 <td width="33%">Location:</td>
129 <td width="67%"><b>{ws.webify(self.location)}</b></td>
130 </tr>
131 {tr_qa("Start:", format_datetime(self.start,
132 DateFormat.SHORT_DATETIME,
133 None))}
134 {tr_qa("End:", format_datetime(self.end,
135 DateFormat.SHORT_DATETIME,
136 None))}
137 {tr(italic("Calculated duration (hours:minutes)"),
138 italic(get_duration_h_m(self.start, self.end)))}
139 {tr_qa("Patient contact?",
140 get_yes_no_none(req, self.patient_contact))}
141 {tr_qa("Staff liaison?",
142 get_yes_no_none(req, self.staff_liaison))}
143 {tr_qa("Other liaison?",
144 get_yes_no_none(req, self.other_liaison))}
145 {tr_qa("Comment:", self.comment)}
146 </table>
147 """