canvas 0.3.1__py3-none-any.whl → 0.4.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of canvas might be problematic. Click here for more details.

Files changed (36) hide show
  1. {canvas-0.3.1.dist-info → canvas-0.4.0.dist-info}/METADATA +2 -1
  2. {canvas-0.3.1.dist-info → canvas-0.4.0.dist-info}/RECORD +36 -34
  3. canvas_cli/apps/emit/emit.py +1 -1
  4. canvas_cli/apps/logs/logs.py +6 -6
  5. canvas_cli/apps/plugin/plugin.py +11 -7
  6. canvas_cli/templates/plugins/default/{{ cookiecutter.__project_slug }}/protocols/my_protocol.py +1 -1
  7. canvas_cli/tests.py +12 -5
  8. canvas_cli/utils/context/context.py +2 -2
  9. canvas_cli/utils/context/tests.py +5 -4
  10. canvas_cli/utils/print/print.py +1 -1
  11. canvas_cli/utils/print/tests.py +2 -3
  12. canvas_generated/messages/events_pb2.py +2 -2
  13. canvas_generated/messages/events_pb2.pyi +4 -0
  14. canvas_sdk/base.py +2 -1
  15. canvas_sdk/commands/base.py +25 -25
  16. canvas_sdk/commands/tests/protocol/tests.py +5 -3
  17. canvas_sdk/commands/tests/test_utils.py +8 -44
  18. canvas_sdk/commands/tests/unit/tests.py +3 -3
  19. canvas_sdk/data/client.py +1 -1
  20. canvas_sdk/effects/banner_alert/tests.py +12 -4
  21. canvas_sdk/effects/protocol_card/protocol_card.py +1 -1
  22. canvas_sdk/effects/protocol_card/tests.py +2 -2
  23. canvas_sdk/protocols/clinical_quality_measure.py +1 -0
  24. canvas_sdk/utils/http.py +2 -2
  25. canvas_sdk/v1/data/common.py +46 -0
  26. canvas_sdk/v1/data/imaging.py +102 -0
  27. canvas_sdk/v1/data/lab.py +182 -10
  28. canvas_sdk/v1/data/patient.py +4 -1
  29. canvas_sdk/v1/data/questionnaire.py +4 -2
  30. canvas_sdk/value_set/tests/test_value_sets.py +9 -6
  31. canvas_sdk/value_set/v2022/intervention.py +0 -24
  32. canvas_sdk/value_set/value_set.py +24 -21
  33. plugin_runner/plugin_runner.py +59 -8
  34. plugin_runner/sandbox.py +1 -1
  35. {canvas-0.3.1.dist-info → canvas-0.4.0.dist-info}/WHEEL +0 -0
  36. {canvas-0.3.1.dist-info → canvas-0.4.0.dist-info}/entry_points.txt +0 -0
@@ -560,6 +560,8 @@ class EventType(int, metaclass=_enum_type_wrapper.EnumTypeWrapper):
560
560
  PATIENT_CHART__CONDITIONS: _ClassVar[EventType]
561
561
  PATIENT_CHART_SUMMARY__SECTION_CONFIGURATION: _ClassVar[EventType]
562
562
  CLAIM__CONDITIONS: _ClassVar[EventType]
563
+ PLUGIN_CREATED: _ClassVar[EventType]
564
+ PLUGIN_UPDATED: _ClassVar[EventType]
563
565
  UNKNOWN: EventType
564
566
  ALLERGY_INTOLERANCE_CREATED: EventType
565
567
  ALLERGY_INTOLERANCE_UPDATED: EventType
@@ -1111,6 +1113,8 @@ VITALS_COMMAND__POST_EXECUTE_ACTION: EventType
1111
1113
  PATIENT_CHART__CONDITIONS: EventType
1112
1114
  PATIENT_CHART_SUMMARY__SECTION_CONFIGURATION: EventType
1113
1115
  CLAIM__CONDITIONS: EventType
1116
+ PLUGIN_CREATED: EventType
1117
+ PLUGIN_UPDATED: EventType
1114
1118
 
1115
1119
  class Event(_message.Message):
1116
1120
  __slots__ = ("type", "target", "context")
canvas_sdk/base.py CHANGED
@@ -31,7 +31,8 @@ class Model(BaseModel):
31
31
 
32
32
  def _get_error_details(self, method: Any) -> list[InitErrorDetails]:
33
33
  required_fields = self._get_effect_method_required_fields(method)
34
- class_name = self.__repr_name__()
34
+ class_name = self.__repr_name__() # type: ignore[misc]
35
+
35
36
  class_name_article = "an" if class_name.startswith(("A", "E", "I", "O", "U")) else "a"
36
37
  return [
37
38
  self._create_error_detail(
@@ -2,7 +2,7 @@ import json
2
2
  import re
3
3
  from enum import EnumType
4
4
  from types import NoneType, UnionType
5
- from typing import Any, Literal, Tuple, Union, get_args, get_origin
5
+ from typing import Any, Literal, Tuple, Union, cast, get_args, get_origin
6
6
 
7
7
  from canvas_sdk.base import Model
8
8
  from canvas_sdk.commands.constants import Coding
@@ -25,9 +25,7 @@ class _BaseCommand(Model):
25
25
  note_uuid: str | None = None
26
26
  command_uuid: str | None = None
27
27
 
28
- def _get_effect_method_required_fields(
29
- self, method: Literal["originate", "edit", "delete", "commit", "enter_in_error"]
30
- ) -> tuple:
28
+ def _get_effect_method_required_fields(self, method: str) -> tuple:
31
29
  base_required_fields: tuple = getattr(
32
30
  _BaseCommand.Meta, f"{method}_required_fields", tuple()
33
31
  )
@@ -52,7 +50,7 @@ class _BaseCommand(Model):
52
50
  return schema.get("$defs", {}).get(choice_key, {}).get("enum")
53
51
 
54
52
  @classmethod
55
- def _get_property_type(cls, name: str) -> type:
53
+ def _get_property_type(cls, name: str) -> type | None:
56
54
  annotation = cls.model_fields[name].annotation
57
55
  origin = get_origin(annotation)
58
56
 
@@ -89,7 +87,7 @@ class _BaseCommand(Model):
89
87
  """Originate a new command in the note body."""
90
88
  self._validate_before_effect("originate")
91
89
  return Effect(
92
- type=EffectType.Value(f"ORIGINATE_{self.constantized_key()}_COMMAND"),
90
+ type=f"ORIGINATE_{self.constantized_key()}_COMMAND",
93
91
  payload=json.dumps(
94
92
  {
95
93
  "note": self.note_uuid,
@@ -101,37 +99,39 @@ class _BaseCommand(Model):
101
99
  def edit(self) -> Effect:
102
100
  """Edit the command."""
103
101
  self._validate_before_effect("edit")
104
- return {
105
- "type": f"EDIT_{self.constantized_key()}_COMMAND",
106
- "payload": {
107
- "command": self.command_uuid,
108
- "data": self.values,
109
- },
110
- }
102
+ return Effect(
103
+ type=f"EDIT_{self.constantized_key()}_COMMAND",
104
+ payload=json.dumps(
105
+ {
106
+ "command": self.command_uuid,
107
+ "data": self.values,
108
+ }
109
+ ),
110
+ )
111
111
 
112
112
  def delete(self) -> Effect:
113
113
  """Delete the command."""
114
114
  self._validate_before_effect("delete")
115
- return {
116
- "type": f"DELETE_{self.constantized_key()}_COMMAND",
117
- "payload": {"command": self.command_uuid},
118
- }
115
+ return Effect(
116
+ type=f"DELETE_{self.constantized_key()}_COMMAND",
117
+ payload=json.dumps({"command": self.command_uuid}),
118
+ )
119
119
 
120
120
  def commit(self) -> Effect:
121
121
  """Commit the command."""
122
122
  self._validate_before_effect("commit")
123
- return {
124
- "type": f"COMMIT_{self.constantized_key()}_COMMAND",
125
- "payload": {"command": self.command_uuid},
126
- }
123
+ return Effect(
124
+ type=f"COMMIT_{self.constantized_key()}_COMMAND",
125
+ payload=json.dumps({"command": self.command_uuid}),
126
+ )
127
127
 
128
128
  def enter_in_error(self) -> Effect:
129
129
  """Mark the command as entered-in-error."""
130
130
  self._validate_before_effect("enter_in_error")
131
- return {
132
- "type": f"ENTER_IN_ERROR_{self.constantized_key()}_COMMAND",
133
- "payload": {"command": self.command_uuid},
134
- }
131
+ return Effect(
132
+ type=f"ENTER_IN_ERROR_{self.constantized_key()}_COMMAND",
133
+ payload=json.dumps({"command": self.command_uuid}),
134
+ )
135
135
 
136
136
  def recommend(self, title: str = "", button: str | None = None) -> Recommendation:
137
137
  """Returns a command recommendation to be inserted via Protocol Card."""
@@ -31,10 +31,10 @@ def plugin_name() -> str:
31
31
  return f"commands{datetime.now().timestamp()}".replace(".", "")
32
32
 
33
33
 
34
- @pytest.fixture(autouse=True, scope="session")
34
+ @pytest.fixture(scope="session")
35
35
  def write_and_install_protocol_and_clean_up(
36
36
  plugin_name: str, token: MaskedValue, new_note: dict
37
- ) -> Generator[Any, Any, Any]:
37
+ ) -> Generator[None, None, None]:
38
38
  write_protocol_code(new_note["externallyExposableId"], plugin_name, COMMANDS)
39
39
  install_plugin(plugin_name, token)
40
40
 
@@ -44,7 +44,9 @@ def write_and_install_protocol_and_clean_up(
44
44
 
45
45
 
46
46
  @pytest.mark.integtest
47
- def test_protocol_that_inserts_every_command(token: MaskedValue, new_note: dict) -> None:
47
+ def test_protocol_that_inserts_every_command(
48
+ write_and_install_protocol_and_clean_up: None, token: MaskedValue, new_note: dict
49
+ ) -> None:
48
50
  trigger_plugin_event(token)
49
51
 
50
52
  commands_in_body = get_original_note_body_commands(new_note["id"], token)
@@ -5,7 +5,7 @@ from contextlib import chdir
5
5
  from datetime import datetime
6
6
  from decimal import Decimal
7
7
  from pathlib import Path
8
- from typing import Any
8
+ from typing import Any, cast
9
9
 
10
10
  import pytest
11
11
  import requests
@@ -63,21 +63,7 @@ def random_string() -> str:
63
63
  return "".join(random.choices(string.ascii_uppercase + string.digits, k=7))
64
64
 
65
65
 
66
- def fake(
67
- field_props: dict,
68
- Command: (
69
- AssessCommand
70
- | DiagnoseCommand
71
- | GoalCommand
72
- | HistoryOfPresentIllnessCommand
73
- | MedicationStatementCommand
74
- | PlanCommand
75
- | PrescribeCommand
76
- | QuestionnaireCommand
77
- | ReasonForVisitCommand
78
- | StopMedicationCommand
79
- ),
80
- ) -> Any:
66
+ def fake(field_props: dict, Command: type[_BaseCommand]) -> Any:
81
67
  t = get_field_type(field_props)
82
68
  match t:
83
69
  case "string":
@@ -107,18 +93,7 @@ def fake(
107
93
 
108
94
 
109
95
  def raises_wrong_type_error(
110
- Command: (
111
- AssessCommand
112
- | DiagnoseCommand
113
- | GoalCommand
114
- | HistoryOfPresentIllnessCommand
115
- | MedicationStatementCommand
116
- | PlanCommand
117
- | PrescribeCommand
118
- | QuestionnaireCommand
119
- | ReasonForVisitCommand
120
- | StopMedicationCommand
121
- ),
96
+ Command: type[_BaseCommand],
122
97
  field: str,
123
98
  ) -> None:
124
99
  field_props = Command.model_json_schema()["properties"][field]
@@ -155,18 +130,7 @@ def raises_wrong_type_error(
155
130
 
156
131
 
157
132
  def raises_none_error_for_effect_method(
158
- Command: (
159
- AssessCommand
160
- | DiagnoseCommand
161
- | GoalCommand
162
- | HistoryOfPresentIllnessCommand
163
- | MedicationStatementCommand
164
- | PlanCommand
165
- | PrescribeCommand
166
- | QuestionnaireCommand
167
- | ReasonForVisitCommand
168
- | StopMedicationCommand
169
- ),
133
+ Command: type[_BaseCommand],
170
134
  method: str,
171
135
  ) -> None:
172
136
  cmd_name = Command.__name__
@@ -214,7 +178,7 @@ class Protocol(BaseProtocol):
214
178
 
215
179
  def install_plugin(plugin_name: str, token: MaskedValue) -> None:
216
180
  requests.post(
217
- plugin_url(settings.INTEGRATION_TEST_URL),
181
+ plugin_url(cast(str, settings.INTEGRATION_TEST_URL)),
218
182
  data={"is_enabled": True},
219
183
  files={"package": open(_build_package(Path(f"./custom-plugins/{plugin_name}")), "rb")},
220
184
  headers={"Authorization": f"Bearer {token.value}"},
@@ -267,7 +231,7 @@ def clean_up_files_and_plugins(plugin_name: str, token: MaskedValue) -> None:
267
231
 
268
232
  # disable
269
233
  requests.patch(
270
- plugin_url(settings.INTEGRATION_TEST_URL, plugin_name),
234
+ plugin_url(cast(str, settings.INTEGRATION_TEST_URL), plugin_name),
271
235
  data={"is_enabled": False},
272
236
  headers={
273
237
  "Authorization": f"Bearer {token.value}",
@@ -275,13 +239,13 @@ def clean_up_files_and_plugins(plugin_name: str, token: MaskedValue) -> None:
275
239
  )
276
240
  # delete
277
241
  requests.delete(
278
- plugin_url(settings.INTEGRATION_TEST_URL, plugin_name),
242
+ plugin_url(cast(str, settings.INTEGRATION_TEST_URL), plugin_name),
279
243
  headers={"Authorization": f"Bearer {token.value}"},
280
244
  )
281
245
 
282
246
 
283
247
  # For reuse with the protocol code
284
- COMMANDS = [
248
+ COMMANDS: list[type[_BaseCommand]] = [
285
249
  AssessCommand,
286
250
  DiagnoseCommand,
287
251
  GoalCommand,
@@ -79,7 +79,7 @@ runner = CliRunner()
79
79
  ],
80
80
  )
81
81
  def test_command_raises_generic_error_when_kwarg_given_incorrect_type(
82
- Command: _BaseCommand,
82
+ Command: type[_BaseCommand],
83
83
  fields_to_test: tuple[str],
84
84
  ) -> None:
85
85
  for field in fields_to_test:
@@ -179,7 +179,7 @@ def test_command_raises_generic_error_when_kwarg_given_incorrect_type(
179
179
  ],
180
180
  )
181
181
  def test_command_raises_specific_error_when_kwarg_given_incorrect_type(
182
- Command: PlanCommand | ReasonForVisitCommand,
182
+ Command: type[PlanCommand] | type[ReasonForVisitCommand],
183
183
  err_kwargs: dict,
184
184
  err_msg: str,
185
185
  valid_kwargs: dict,
@@ -255,7 +255,7 @@ def test_command_raises_specific_error_when_kwarg_given_incorrect_type(
255
255
  ],
256
256
  )
257
257
  def test_command_allows_kwarg_with_correct_type(
258
- Command: _BaseCommand,
258
+ Command: type[_BaseCommand],
259
259
  fields_to_test: tuple[str],
260
260
  ) -> None:
261
261
  schema = Command.model_json_schema()
canvas_sdk/data/client.py CHANGED
@@ -54,7 +54,7 @@ class _CanvasGQLClient:
54
54
 
55
55
  def __init__(self) -> None:
56
56
  self.client = Client(
57
- transport=AIOHTTPTransport(url=cast(str, GRAPHQL_ENDPOINT)),
57
+ transport=AIOHTTPTransport(url=GRAPHQL_ENDPOINT),
58
58
  # TODO: follow the documentation in the link below to specify a
59
59
  # cached copy of the schema
60
60
  # https://gql.readthedocs.io/en/stable/usage/validation.html#using-a-provided-schema
@@ -6,6 +6,7 @@ from typing import Any, Generator
6
6
 
7
7
  import pytest
8
8
  import requests
9
+ from django.core.exceptions import ImproperlyConfigured
9
10
  from pydantic import ValidationError
10
11
  from typer.testing import CliRunner
11
12
 
@@ -49,10 +50,14 @@ def plugin_name() -> str:
49
50
  return f"addbanneralert{datetime.now().timestamp()}".replace(".", "")
50
51
 
51
52
 
52
- @pytest.fixture(autouse=True, scope="session")
53
+ @pytest.fixture(scope="session")
53
54
  def write_and_install_protocol_and_clean_up(
54
55
  first_patient_id: str, plugin_name: str, token: MaskedValue
55
56
  ) -> Generator[Any, Any, Any]:
57
+
58
+ if not settings.INTEGRATION_TEST_URL:
59
+ raise ImproperlyConfigured("INTEGRATION_TEST_URL is not set")
60
+
56
61
  # write the protocol
57
62
  with chdir(Path("./custom-plugins")):
58
63
  runner.invoke(app, "init", input=plugin_name)
@@ -122,7 +127,10 @@ class Protocol(BaseProtocol):
122
127
 
123
128
  @pytest.mark.integtest
124
129
  def test_protocol_that_adds_banner_alert(
125
- token: MaskedValue, plugin_name: str, first_patient_id: str
130
+ write_and_install_protocol_and_clean_up: None,
131
+ token: MaskedValue,
132
+ plugin_name: str,
133
+ first_patient_id: str,
126
134
  ) -> None:
127
135
  # trigger the event
128
136
  requests.post(
@@ -180,7 +188,7 @@ def test_protocol_that_adds_banner_alert(
180
188
  ],
181
189
  )
182
190
  def test_banner_alert_apply_method_succeeds_with_all_required_fields(
183
- Effect: AddBannerAlert | RemoveBannerAlert, params: dict, expected_payload: str
191
+ Effect: type[AddBannerAlert] | type[RemoveBannerAlert], params: dict, expected_payload: str
184
192
  ) -> None:
185
193
  b = Effect()
186
194
  for k, v in params.items():
@@ -214,7 +222,7 @@ def test_banner_alert_apply_method_succeeds_with_all_required_fields(
214
222
  ],
215
223
  )
216
224
  def test_banner_alert_apply_method_raises_error_without_required_fields(
217
- Effect: AddBannerAlert | RemoveBannerAlert, expected_err_msgs: str
225
+ Effect: type[AddBannerAlert] | type[RemoveBannerAlert], expected_err_msgs: str
218
226
  ) -> None:
219
227
  b = Effect()
220
228
  with pytest.raises(ValidationError) as e:
@@ -49,7 +49,7 @@ class ProtocolCard(_BaseEffect):
49
49
  title: str = ""
50
50
  narrative: str = ""
51
51
  recommendations: list[Recommendation] = []
52
- status: Status = Status.DUE # type: ignore
52
+ status: Status = Status.DUE
53
53
  feedback_enabled: bool = False
54
54
 
55
55
  @property
@@ -107,7 +107,7 @@ def test_apply_method_raises_error_without_patient_id_and_key() -> None:
107
107
  ],
108
108
  )
109
109
  def test_add_recommendations(
110
- init_params: dict[str, str], rec1_params: dict[Any, Any], rec2_params: dict[str, str]
110
+ init_params: dict[Any, Any], rec1_params: dict[Any, Any], rec2_params: dict[Any, Any]
111
111
  ) -> None:
112
112
  p = ProtocolCard(**init_params)
113
113
  p.add_recommendation(**rec1_params)
@@ -156,7 +156,7 @@ def test_add_recommendations(
156
156
  ],
157
157
  )
158
158
  def test_add_recommendations_from_commands(
159
- Command: _BaseCommand, init_params: dict[str, str]
159
+ Command: type[_BaseCommand], init_params: dict[str, str]
160
160
  ) -> None:
161
161
  cmd = Command(**init_params)
162
162
  p = ProtocolCard(patient_id="uuid", key="commands")
@@ -21,6 +21,7 @@ class ClinicalQualityMeasure(BaseProtocol):
21
21
  show_in_population: bool = True
22
22
  can_be_snoozed: bool = True
23
23
  is_abstract: bool = False
24
+ is_predictive: bool = False
24
25
 
25
26
  @classmethod
26
27
  def _meta(cls) -> dict[str, Any]:
canvas_sdk/utils/http.py CHANGED
@@ -1,6 +1,6 @@
1
1
  import time
2
2
  from functools import wraps
3
- from typing import Any, Callable, Mapping, TypeVar
3
+ from typing import Any, Callable, Mapping, TypeVar, cast
4
4
 
5
5
  import requests
6
6
  import statsd
@@ -28,7 +28,7 @@ class Http:
28
28
  self.statsd_client.timing(f"http_{fn.__name__}", timing)
29
29
  return result
30
30
 
31
- return wrapper
31
+ return cast(F, wrapper)
32
32
 
33
33
  @measure_time
34
34
  def get(
@@ -0,0 +1,46 @@
1
+ from django.db import models
2
+
3
+
4
+ class DocumentReviewMode(models.TextChoices):
5
+ """Choices for document reviews."""
6
+
7
+ REVIEW_REQUIRED = "RR", "Review required"
8
+ ALREADY_REVIEWED_OFFLINE = "AR", "Already reviewed offline"
9
+ REVIEW_NOT_REQUIRED = "RN", "Review not required"
10
+
11
+
12
+ class OrderStatus(models.TextChoices):
13
+ """Choices for Order statuses."""
14
+
15
+ PROPOSED = "proposed", "Proposed"
16
+ DRAFT = "draft", "Draft"
17
+ PLANNED = "planned", "Planned"
18
+ REQUESTED = "requested", "Requested"
19
+ RECEIVED = "received", "Received"
20
+ ACCEPTED = "accepted", "Accepted"
21
+ IN_PROGRESS = "in-progress", "In-progress"
22
+ REVIEW = "review", "Review"
23
+ COMPLETED = "completed", "Completed"
24
+ CANCELLED = "cancelled", "Cancelled"
25
+ SUSPENDED = "suspended", "Suspended"
26
+ REJECTED = "rejected", "Rejected"
27
+ FAILED = "failed", "Failed"
28
+ ENTERED_IN_ERROR = "EIE", "Entered in Error"
29
+
30
+
31
+ class ReviewPatientCommunicationMethod(models.TextChoices):
32
+ """Choices for patient communication regarding reviews."""
33
+
34
+ DELEGATED_CALL_CAN_LEAVE_MESSAGE = "DM", "delegate call, can leave message"
35
+ DELEGATED_CALL_NEED_ANSWER = "DA", "delegate call, need patient to answer"
36
+ DELEGATED_LETTER = "DL", "delegate letter"
37
+ DO_NOT_COMMUNICATE = "DC", "do not communicate"
38
+ ALREADY_LEFT_MESSAGE = "AM", "already left message"
39
+ ALREADY_REVIEWED_WITH_PATIENT = "AR", "already reviewed with patient"
40
+
41
+
42
+ class ReviewStatus(models.TextChoices):
43
+ """Status choices for reviews."""
44
+
45
+ STATUS_REVIEWING = "reviewing", "reviewing"
46
+ STATUS_REVIEWED = "reviewed", "reviewed"
@@ -0,0 +1,102 @@
1
+ from django.db import models
2
+
3
+ from canvas_sdk.v1.data.common import (
4
+ DocumentReviewMode,
5
+ OrderStatus,
6
+ ReviewPatientCommunicationMethod,
7
+ ReviewStatus,
8
+ )
9
+ from canvas_sdk.v1.data.patient import Patient
10
+ from canvas_sdk.v1.data.user import CanvasUser
11
+
12
+
13
+ class ImagingOrder(models.Model):
14
+ """Model to read ImagingOrder data."""
15
+
16
+ class Meta:
17
+ managed = False
18
+ app_label = "canvas_sdk"
19
+ db_table = "canvas_sdk_data_api_imagingorder_001"
20
+
21
+ id = models.UUIDField()
22
+ dbid = models.BigIntegerField(primary_key=True)
23
+ created = models.DateTimeField()
24
+ modified = models.DateTimeField()
25
+ originator = models.ForeignKey(CanvasUser, on_delete=models.DO_NOTHING)
26
+ deleted = models.BooleanField()
27
+ committer = models.ForeignKey(CanvasUser, on_delete=models.DO_NOTHING)
28
+ entered_in_error = models.ForeignKey(CanvasUser, on_delete=models.DO_NOTHING)
29
+ patient = models.ForeignKey(Patient, on_delete=models.DO_NOTHING, related_name="imaging_orders")
30
+ # TODO - uncomment when Note model is complete
31
+ # note = models.ForeigneKey(Note, on_delete=models.DO_NOTHING, related_name="imaging_orders")
32
+ imaging = models.CharField()
33
+ # TODO - uncomment when ServiceProvider model is complete
34
+ # imaging_center = models.ForeignKey(ServiceProvider, related_name="imaging_orders", null=True, on_delete=models.DO_NOTHING)
35
+ note_to_radiologist = models.CharField()
36
+ internal_comment = models.CharField()
37
+ status = models.CharField(choices=OrderStatus)
38
+ date_time_ordered = models.DateTimeField()
39
+ priority = models.CharField()
40
+ # TODO - uncomment when Staff model is complete
41
+ # ordering_provider = models.ForeignKey(Staff, on_delete=models.CASCADE, related_name="imaging_orders", null=True)
42
+ delegated = models.BooleanField(default=False)
43
+
44
+
45
+ class ImagingReview(models.Model):
46
+ """Model to read ImagingReview data."""
47
+
48
+ class Meta:
49
+ managed = False
50
+ app_label = "canvas_sdk"
51
+ db_table = "canvas_sdk_data_api_imagingreview_001"
52
+
53
+ id = models.UUIDField()
54
+ dbid = models.BigIntegerField(primary_key=True)
55
+ created = models.DateTimeField()
56
+ modified = models.DateTimeField()
57
+ originator = models.ForeignKey(CanvasUser, on_delete=models.DO_NOTHING)
58
+ deleted = models.BooleanField()
59
+ committer = models.ForeignKey(CanvasUser, on_delete=models.DO_NOTHING)
60
+ entered_in_error = models.ForeignKey(CanvasUser, on_delete=models.DO_NOTHING)
61
+ patient_communication_method = models.CharField(choices=ReviewPatientCommunicationMethod)
62
+ # TODO - uncomment when Note model is complete
63
+ # note = models.ForeignKey(Note, on_delete=models.DO_NOTHING, related_name="imaging_reviews")
64
+ internal_comment = models.CharField()
65
+ message_to_patient = models.CharField()
66
+ is_released_to_patient = models.BooleanField()
67
+ status = models.CharField(choices=ReviewStatus)
68
+ patient = models.ForeignKey(
69
+ Patient, on_delete=models.DO_NOTHING, related_name="imaging_reviews"
70
+ )
71
+
72
+
73
+ class ImagingReport(models.Model):
74
+ """Model to read ImagingReport data."""
75
+
76
+ class ImagingReportSource(models.TextChoices):
77
+ RADIOLOGY_FROM_PATIENT = "RADIOLOGY_PATIENT", "Radiology Report From Patient"
78
+ VERBAL_FROM_PATIENT = "VERBAL_PATIENT", "Verbal Report From Patient"
79
+ DIRECTLY_REPORT = "DIRECTLY_RADIOLOGY", "Directly Radiology Report"
80
+
81
+ class Meta:
82
+ managed = False
83
+ app_label = "canvas_sdk"
84
+ db_table = "canvas_sdk_data_api_imagingreport_001"
85
+
86
+ id = models.UUIDField()
87
+ dbid = models.BigIntegerField(primary_key=True)
88
+ created = models.DateTimeField()
89
+ modified = models.DateTimeField()
90
+ review_mode = models.CharField(choices=DocumentReviewMode)
91
+ junked = models.BooleanField()
92
+ requires_signature = models.BooleanField()
93
+ assigned_date = models.DateTimeField()
94
+ patient = models.ForeignKey(
95
+ Patient, on_delete=models.DO_NOTHING, related_name="imaging_results"
96
+ )
97
+ order = models.ForeignKey(ImagingOrder, on_delete=models.DO_NOTHING, null=True)
98
+ source = models.CharField(choices=ImagingReportSource)
99
+ name = models.CharField()
100
+ result_date = models.DateField()
101
+ original_date = models.DateField()
102
+ review = models.ForeignKey(ImagingReview, null=True, on_delete=models.DO_NOTHING)