canvas 0.3.0__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 (108) hide show
  1. {canvas-0.3.0.dist-info → canvas-0.4.0.dist-info}/METADATA +2 -1
  2. canvas-0.4.0.dist-info/RECORD +218 -0
  3. canvas_cli/apps/emit/__init__.py +3 -0
  4. canvas_cli/apps/emit/emit.py +67 -0
  5. canvas_cli/apps/emit/event_fixtures/ALLERGY_INTOLERANCE_CREATED.ndjson +1 -0
  6. canvas_cli/apps/emit/event_fixtures/ALLERGY_INTOLERANCE_UPDATED.ndjson +1 -0
  7. canvas_cli/apps/emit/event_fixtures/APPOINTMENT_CANCELED.ndjson +1 -0
  8. canvas_cli/apps/emit/event_fixtures/APPOINTMENT_CHECKED_IN.ndjson +1 -0
  9. canvas_cli/apps/emit/event_fixtures/APPOINTMENT_CREATED.ndjson +1 -0
  10. canvas_cli/apps/emit/event_fixtures/APPOINTMENT_NO_SHOWED.ndjson +1 -0
  11. canvas_cli/apps/emit/event_fixtures/APPOINTMENT_RESCHEDULED.ndjson +1 -0
  12. canvas_cli/apps/emit/event_fixtures/APPOINTMENT_RESTORED.ndjson +1 -0
  13. canvas_cli/apps/emit/event_fixtures/APPOINTMENT_UPDATED.ndjson +2 -0
  14. canvas_cli/apps/emit/event_fixtures/ASSESS_COMMAND__CONDITION_SELECTED.ndjson +1 -0
  15. canvas_cli/apps/emit/event_fixtures/ASSESS_COMMAND__POST_COMMIT.ndjson +3 -0
  16. canvas_cli/apps/emit/event_fixtures/ASSESS_COMMAND__POST_ORIGINATE.ndjson +4 -0
  17. canvas_cli/apps/emit/event_fixtures/ASSESS_COMMAND__POST_UPDATE.ndjson +5 -0
  18. canvas_cli/apps/emit/event_fixtures/ASSESS_COMMAND__PRE_COMMIT.ndjson +3 -0
  19. canvas_cli/apps/emit/event_fixtures/ASSESS_COMMAND__PRE_ORIGINATE.ndjson +4 -0
  20. canvas_cli/apps/emit/event_fixtures/ASSESS_COMMAND__PRE_UPDATE.ndjson +5 -0
  21. canvas_cli/apps/emit/event_fixtures/BILLING_LINE_ITEM_CREATED.ndjson +3 -0
  22. canvas_cli/apps/emit/event_fixtures/BILLING_LINE_ITEM_UPDATED.ndjson +2 -0
  23. canvas_cli/apps/emit/event_fixtures/CONDITION_ASSESSED.ndjson +2 -0
  24. canvas_cli/apps/emit/event_fixtures/CONDITION_CREATED.ndjson +4 -0
  25. canvas_cli/apps/emit/event_fixtures/CONDITION_UPDATED.ndjson +5 -0
  26. canvas_cli/apps/emit/event_fixtures/CRON.ndjson +3 -0
  27. canvas_cli/apps/emit/event_fixtures/ENCOUNTER_CREATED.ndjson +3 -0
  28. canvas_cli/apps/emit/event_fixtures/ENCOUNTER_UPDATED.ndjson +2 -0
  29. canvas_cli/apps/emit/event_fixtures/IMMUNIZATION_CREATED.ndjson +1 -0
  30. canvas_cli/apps/emit/event_fixtures/IMMUNIZATION_STATEMENT_CREATED.ndjson +1 -0
  31. canvas_cli/apps/emit/event_fixtures/IMMUNIZATION_STATEMENT_UPDATED.ndjson +1 -0
  32. canvas_cli/apps/emit/event_fixtures/IMMUNIZATION_UPDATED.ndjson +1 -0
  33. canvas_cli/apps/emit/event_fixtures/INTERVIEW_CREATED.ndjson +1 -0
  34. canvas_cli/apps/emit/event_fixtures/INTERVIEW_UPDATED.ndjson +1 -0
  35. canvas_cli/apps/emit/event_fixtures/LAB_ORDER_CREATED.ndjson +1 -0
  36. canvas_cli/apps/emit/event_fixtures/LAB_ORDER_UPDATED.ndjson +1 -0
  37. canvas_cli/apps/emit/event_fixtures/MEDICATION_LIST_ITEM_CREATED.ndjson +1 -0
  38. canvas_cli/apps/emit/event_fixtures/MEDICATION_LIST_ITEM_UPDATED.ndjson +1 -0
  39. canvas_cli/apps/emit/event_fixtures/MEDICATION_STATEMENT_COMMAND__POST_COMMIT.ndjson +1 -0
  40. canvas_cli/apps/emit/event_fixtures/MEDICATION_STATEMENT_COMMAND__POST_ORIGINATE.ndjson +1 -0
  41. canvas_cli/apps/emit/event_fixtures/MEDICATION_STATEMENT_COMMAND__POST_UPDATE.ndjson +2 -0
  42. canvas_cli/apps/emit/event_fixtures/MEDICATION_STATEMENT_COMMAND__PRE_COMMIT.ndjson +1 -0
  43. canvas_cli/apps/emit/event_fixtures/MEDICATION_STATEMENT_COMMAND__PRE_ORIGINATE.ndjson +1 -0
  44. canvas_cli/apps/emit/event_fixtures/MEDICATION_STATEMENT_COMMAND__PRE_UPDATE.ndjson +2 -0
  45. canvas_cli/apps/emit/event_fixtures/MEDICATION_STATEMENT__MEDICATION__POST_SEARCH.ndjson +2 -0
  46. canvas_cli/apps/emit/event_fixtures/PATIENT_CREATED.ndjson +1 -0
  47. canvas_cli/apps/emit/event_fixtures/PATIENT_UPDATED.ndjson +1 -0
  48. canvas_cli/apps/emit/event_fixtures/PLAN_COMMAND__POST_ORIGINATE.ndjson +1 -0
  49. canvas_cli/apps/emit/event_fixtures/PLAN_COMMAND__PRE_ORIGINATE.ndjson +1 -0
  50. canvas_cli/apps/emit/event_fixtures/QUESTIONNAIRE_COMMAND__POST_COMMIT.ndjson +1 -0
  51. canvas_cli/apps/emit/event_fixtures/QUESTIONNAIRE_COMMAND__POST_ORIGINATE.ndjson +1 -0
  52. canvas_cli/apps/emit/event_fixtures/QUESTIONNAIRE_COMMAND__POST_UPDATE.ndjson +2 -0
  53. canvas_cli/apps/emit/event_fixtures/QUESTIONNAIRE_COMMAND__PRE_COMMIT.ndjson +1 -0
  54. canvas_cli/apps/emit/event_fixtures/QUESTIONNAIRE_COMMAND__PRE_ORIGINATE.ndjson +1 -0
  55. canvas_cli/apps/emit/event_fixtures/QUESTIONNAIRE_COMMAND__PRE_UPDATE.ndjson +2 -0
  56. canvas_cli/apps/emit/event_fixtures/QUESTIONNAIRE__QUESTIONNAIRE__POST_SEARCH.ndjson +4 -0
  57. canvas_cli/apps/emit/event_fixtures/TASK_COMMENT_CREATED.ndjson +1 -0
  58. canvas_cli/apps/emit/event_fixtures/TASK_CREATED.ndjson +1 -0
  59. canvas_cli/apps/emit/event_fixtures/TASK_UPDATED.ndjson +1 -0
  60. canvas_cli/apps/emit/event_fixtures/VITAL_SIGN_CREATED.ndjson +14 -0
  61. canvas_cli/apps/emit/event_fixtures/VITAL_SIGN_UPDATED.ndjson +364 -0
  62. canvas_cli/apps/logs/logs.py +6 -6
  63. canvas_cli/apps/plugin/plugin.py +11 -7
  64. canvas_cli/apps/run_plugins/__init__.py +3 -0
  65. canvas_cli/apps/run_plugins/run_plugins.py +16 -0
  66. canvas_cli/main.py +8 -38
  67. canvas_cli/templates/plugins/default/{{ cookiecutter.__project_slug }}/README.md +0 -1
  68. canvas_cli/templates/plugins/default/{{ cookiecutter.__project_slug }}/protocols/my_protocol.py +1 -1
  69. canvas_cli/tests.py +12 -5
  70. canvas_cli/utils/context/context.py +2 -2
  71. canvas_cli/utils/context/tests.py +5 -4
  72. canvas_cli/utils/print/print.py +1 -1
  73. canvas_cli/utils/print/tests.py +2 -3
  74. canvas_generated/messages/events_pb2.py +2 -2
  75. canvas_generated/messages/events_pb2.pyi +12 -0
  76. canvas_sdk/base.py +2 -1
  77. canvas_sdk/commands/base.py +25 -25
  78. canvas_sdk/commands/tests/protocol/tests.py +5 -3
  79. canvas_sdk/commands/tests/test_utils.py +8 -44
  80. canvas_sdk/commands/tests/unit/tests.py +3 -3
  81. canvas_sdk/data/client.py +1 -1
  82. canvas_sdk/effects/banner_alert/tests.py +12 -4
  83. canvas_sdk/effects/protocol_card/protocol_card.py +1 -1
  84. canvas_sdk/effects/protocol_card/tests.py +2 -2
  85. canvas_sdk/protocols/clinical_quality_measure.py +1 -0
  86. canvas_sdk/utils/http.py +2 -2
  87. canvas_sdk/v1/data/base.py +1 -1
  88. canvas_sdk/v1/data/command.py +27 -0
  89. canvas_sdk/v1/data/common.py +46 -0
  90. canvas_sdk/v1/data/device.py +44 -0
  91. canvas_sdk/v1/data/imaging.py +102 -0
  92. canvas_sdk/v1/data/lab.py +182 -10
  93. canvas_sdk/v1/data/observation.py +117 -0
  94. canvas_sdk/v1/data/patient.py +4 -1
  95. canvas_sdk/v1/data/questionnaire.py +4 -2
  96. canvas_sdk/value_set/tests/test_value_sets.py +9 -6
  97. canvas_sdk/value_set/v2022/intervention.py +0 -24
  98. canvas_sdk/value_set/value_set.py +24 -21
  99. plugin_runner/__init__.py +0 -0
  100. plugin_runner/authentication.py +48 -0
  101. plugin_runner/plugin_runner.py +389 -0
  102. plugin_runner/plugin_synchronizer.py +87 -0
  103. plugin_runner/sandbox.py +273 -0
  104. pubsub/__init__.py +0 -0
  105. pubsub/pubsub.py +38 -0
  106. canvas-0.3.0.dist-info/RECORD +0 -145
  107. {canvas-0.3.0.dist-info → canvas-0.4.0.dist-info}/WHEEL +0 -0
  108. {canvas-0.3.0.dist-info → canvas-0.4.0.dist-info}/entry_points.txt +0 -0
@@ -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(
@@ -66,7 +66,7 @@ class ValueSetLookupQuerySet(models.QuerySet):
66
66
  """
67
67
  This method can be overridden if a Q object with different filtering options is needed.
68
68
  """
69
- return Q(codings__system=system, codings_code_in=codes)
69
+ return Q(codings__system=system, codings__code__in=codes)
70
70
 
71
71
 
72
72
  class ValueSetLookupByNameQuerySet(ValueSetLookupQuerySet):
@@ -0,0 +1,27 @@
1
+ from django.db import models
2
+
3
+ from canvas_sdk.v1.data.patient import Patient
4
+ from canvas_sdk.v1.data.user import CanvasUser
5
+
6
+
7
+ class Command(models.Model):
8
+ """Command."""
9
+
10
+ class Meta:
11
+ managed = False
12
+ app_label = "canvas_sdk"
13
+ db_table = "canvas_sdk_data_commands_command_001"
14
+
15
+ id = models.UUIDField()
16
+ dbid = models.BigIntegerField(primary_key=True)
17
+ created = models.DateTimeField()
18
+ modified = models.DateTimeField()
19
+ originator = models.ForeignKey(CanvasUser, on_delete=models.DO_NOTHING)
20
+ committer = models.ForeignKey(CanvasUser, on_delete=models.DO_NOTHING)
21
+ entered_in_error = models.ForeignKey(CanvasUser, on_delete=models.DO_NOTHING)
22
+ state = models.CharField()
23
+ patient = models.ForeignKey(Patient, on_delete=models.DO_NOTHING)
24
+ note_id = models.BigIntegerField()
25
+ schema_key = models.TextField()
26
+ data = models.JSONField()
27
+ origination_source = models.CharField()
@@ -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,44 @@
1
+ from django.db import models
2
+
3
+ from canvas_sdk.v1.data import Patient
4
+ from canvas_sdk.v1.data.user import CanvasUser
5
+
6
+
7
+ class Device(models.Model):
8
+ """Device."""
9
+
10
+ class Meta:
11
+ managed = False
12
+ app_label = "canvas_sdk"
13
+ db_table = "canvas_sdk_data_api_device_001"
14
+
15
+ id = models.UUIDField()
16
+ dbid = models.BigIntegerField(primary_key=True)
17
+ created = models.DateTimeField()
18
+ modified = models.DateTimeField()
19
+ originator = models.ForeignKey(CanvasUser, on_delete=models.DO_NOTHING)
20
+ committer = models.ForeignKey(CanvasUser, on_delete=models.DO_NOTHING)
21
+ entered_in_error = models.ForeignKey(CanvasUser, on_delete=models.DO_NOTHING)
22
+ patient = models.ForeignKey(Patient, on_delete=models.DO_NOTHING, related_name="devices")
23
+ note_id = models.BigIntegerField()
24
+ deleted = models.BooleanField()
25
+ labeled_contains_NRL = models.BooleanField()
26
+ assigning_authority = models.CharField()
27
+ scoping_entity = models.CharField()
28
+ udi = models.CharField()
29
+ di = models.CharField()
30
+ issuing_agency = models.CharField()
31
+ lot_number = models.CharField()
32
+ brand_name = models.CharField()
33
+ mri_safety_status = models.CharField()
34
+ version_model_number = models.CharField()
35
+ company_name = models.CharField()
36
+ gmdnPTName = models.TextField()
37
+ status = models.CharField()
38
+ expiration_date = models.DateField()
39
+ expiration_date_original = models.CharField()
40
+ serial_number = models.CharField()
41
+ manufacturing_date_original = models.CharField()
42
+ manufacturing_date = models.DateField()
43
+ manufacturer = models.CharField()
44
+ procedure_id = models.BigIntegerField()
@@ -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)
canvas_sdk/v1/data/lab.py CHANGED
@@ -1,10 +1,21 @@
1
1
  from django.db import models
2
2
 
3
3
  from canvas_sdk.v1.data.base import CommittableModelManager
4
+ from canvas_sdk.v1.data.condition import Condition
4
5
  from canvas_sdk.v1.data.patient import Patient
6
+
7
+ # from canvas_sdk.v1.data.staff import Staff
5
8
  from canvas_sdk.v1.data.user import CanvasUser
6
9
 
7
10
 
11
+ class TransmissionType(models.TextChoices):
12
+ """Choices for transmission types."""
13
+
14
+ FAX = "F", "fax"
15
+ HL7 = "H", "hl7"
16
+ MANUAL = "M", "manual"
17
+
18
+
8
19
  class LabReport(models.Model):
9
20
  """A class representing a lab report."""
10
21
 
@@ -23,19 +34,23 @@ class LabReport(models.Model):
23
34
  junked = models.BooleanField()
24
35
  requires_signature = models.BooleanField()
25
36
  assigned_date = models.DateTimeField()
26
- patient = models.ForeignKey(Patient, on_delete=models.DO_NOTHING, related_name="lab_reports")
27
- transmission_type = models.CharField()
37
+ patient = models.ForeignKey(
38
+ Patient, on_delete=models.DO_NOTHING, related_name="lab_reports", null=True
39
+ )
40
+ transmission_type = models.CharField(choices=TransmissionType)
28
41
  for_test_only = models.BooleanField()
29
42
  external_id = models.CharField()
30
43
  version = models.IntegerField()
31
44
  requisition_number = models.CharField()
32
- review = models.ForeignKey("LabReview", related_name="reports", on_delete=models.DO_NOTHING)
45
+ review = models.ForeignKey(
46
+ "LabReview", related_name="reports", on_delete=models.DO_NOTHING, null=True
47
+ )
33
48
  original_date = models.DateTimeField()
34
49
  date_performed = models.DateTimeField()
35
50
  custom_document_name = models.CharField()
36
51
  originator = models.ForeignKey(CanvasUser, on_delete=models.DO_NOTHING)
37
- committer = models.ForeignKey(CanvasUser, on_delete=models.DO_NOTHING)
38
- entered_in_error = models.ForeignKey(CanvasUser, on_delete=models.DO_NOTHING)
52
+ committer = models.ForeignKey(CanvasUser, on_delete=models.DO_NOTHING, null=True)
53
+ entered_in_error = models.ForeignKey(CanvasUser, on_delete=models.DO_NOTHING, null=True)
39
54
  deleted = models.BooleanField()
40
55
 
41
56
 
@@ -55,12 +70,12 @@ class LabReview(models.Model):
55
70
  modified = models.DateTimeField()
56
71
  originator = models.ForeignKey(CanvasUser, on_delete=models.DO_NOTHING)
57
72
  deleted = models.BooleanField()
58
- committer = models.ForeignKey(CanvasUser, on_delete=models.DO_NOTHING)
59
- entered_in_error = models.ForeignKey(CanvasUser, on_delete=models.DO_NOTHING)
73
+ committer = models.ForeignKey(CanvasUser, on_delete=models.DO_NOTHING, null=True)
74
+ entered_in_error = models.ForeignKey(CanvasUser, on_delete=models.DO_NOTHING, null=True)
60
75
  internal_comment = models.TextField()
61
76
  message_to_patient = models.CharField()
62
77
  status = models.CharField()
63
- patient = models.ForeignKey(Patient, on_delete=models.DO_NOTHING)
78
+ patient = models.ForeignKey(Patient, on_delete=models.DO_NOTHING, related_name="lab_reviews")
64
79
  patient_communication_method = models.CharField()
65
80
 
66
81
 
@@ -76,7 +91,9 @@ class LabValue(models.Model):
76
91
  dbid = models.BigIntegerField(primary_key=True)
77
92
  created = models.DateTimeField()
78
93
  modified = models.DateTimeField()
79
- report = models.ForeignKey("LabReport", related_name="values", on_delete=models.DO_NOTHING)
94
+ report = models.ForeignKey(
95
+ "LabReport", related_name="values", on_delete=models.DO_NOTHING, null=True
96
+ )
80
97
  value = models.TextField()
81
98
  units = models.CharField()
82
99
  abnormal_flag = models.CharField()
@@ -98,7 +115,162 @@ class LabValueCoding(models.Model):
98
115
  dbid = models.BigIntegerField(primary_key=True)
99
116
  created = models.DateTimeField()
100
117
  modified = models.DateTimeField()
101
- value = models.ForeignKey(LabValue, on_delete=models.DO_NOTHING, related_name="codings")
118
+ value = models.ForeignKey(
119
+ LabValue, on_delete=models.DO_NOTHING, related_name="codings", null=True
120
+ )
102
121
  code = models.CharField()
103
122
  name = models.CharField()
104
123
  system = models.CharField()
124
+
125
+
126
+ class LabOrder(models.Model):
127
+ """A class representing a lab order."""
128
+
129
+ class SpecimenCollectionType(models.TextChoices):
130
+ """Choices for specimen collection types."""
131
+
132
+ ON_LOCATION = "L", "on location"
133
+ PATIENT_SERVICE_CENTER = "P", "patient service center"
134
+ OTHER = "O", "other"
135
+
136
+ class CourtesyCopyType(models.TextChoices):
137
+ """Choices for courtesy copy types."""
138
+
139
+ ACCOUNT = "A", "account"
140
+ FAX = "F", "fax"
141
+ PATIENT = "P", "patient"
142
+
143
+ class ManualProcessingStatus(models.TextChoices):
144
+ """Choices for manual processing statuses."""
145
+
146
+ MANUAL_PROCESSING_STATUS_NEEDS_REVIEW = "NEEDS_REVIEW", "Needs Review"
147
+ MANUAL_PROCESSING_STATUS_IN_PROGRESS = "IN_PROGRESS", "In Progress"
148
+ MANUAL_PROCESSING_STATUS_PROCESSED = "PROCESSED", "Processed"
149
+ MANUAL_PROCESSING_STATUS_FLAGGED = "FLAGGED", "Flagged"
150
+
151
+ class Meta:
152
+ managed = False
153
+ app_label = "canvas_sdk"
154
+ db_table = "canvas_sdk_data_api_laborder_001"
155
+
156
+ id = models.UUIDField()
157
+ dbid = models.BigIntegerField(primary_key=True)
158
+ created = models.DateTimeField()
159
+ modified = models.DateTimeField()
160
+ originator = models.ForeignKey(CanvasUser, on_delete=models.DO_NOTHING)
161
+ deleted = models.BooleanField()
162
+ committer = models.ForeignKey(CanvasUser, on_delete=models.DO_NOTHING, null=True)
163
+ entered_in_error = models.ForeignKey(CanvasUser, on_delete=models.DO_NOTHING, null=True)
164
+ patient = models.ForeignKey(Patient, on_delete=models.DO_NOTHING, related_name="lab_orders")
165
+ ontology_lab_partner = models.CharField()
166
+ # TODO - uncomment when the Note model is finished
167
+ # note = models.ForeignKey("Note", on_delete=models.DO_NOTHING)
168
+ comment = models.CharField()
169
+ requisition_number = models.CharField()
170
+ is_patient_bill = models.BooleanField(null=True)
171
+ date_ordered = models.DateTimeField()
172
+ fasting_status = models.BooleanField(null=True)
173
+ specimen_collection_type = models.CharField(choices=SpecimenCollectionType, null=True)
174
+ transmission_type = models.CharField(choices=TransmissionType, null=True)
175
+ courtesy_copy_type = models.CharField(choices=CourtesyCopyType, null=True)
176
+ courtesy_copy_number = models.CharField()
177
+ courtesy_copy_text = models.CharField()
178
+ # TODO - uncomment when Staff model is added
179
+ # ordering_provider = models.ForeignKey(Staff, on_delete=models.DO_NOTHING, null=True)
180
+ parent_order = models.ForeignKey("LabOrder", on_delete=models.DO_NOTHING, null=True)
181
+ healthgorilla_id = models.CharField()
182
+ manual_processing_status = models.CharField(choices=ManualProcessingStatus)
183
+ manual_processing_comment = models.CharField()
184
+ labcorp_abn_url = models.URLField()
185
+
186
+
187
+ class LabOrderReason(models.Model):
188
+ """A class representing a lab order reason."""
189
+
190
+ class LabReasonMode(models.TextChoices):
191
+ """Choices for lab order reasons."""
192
+
193
+ MONITOR = "MO", "monitor"
194
+ INVESTIGATE = "IN", "investigate"
195
+ SCREEN_FOR = "SF", "screen for"
196
+ UNKNOWN = "UNK", "unknown"
197
+
198
+ class Meta:
199
+ managed = False
200
+ app_label = "canvas_sdk"
201
+ db_table = "canvas_sdk_data_api_laborderreason_001"
202
+
203
+ dbid = models.BigIntegerField(primary_key=True)
204
+ created = models.DateTimeField()
205
+ modified = models.DateTimeField()
206
+ originator = models.ForeignKey(CanvasUser, on_delete=models.DO_NOTHING)
207
+ deleted = models.BooleanField()
208
+ committer = models.ForeignKey(CanvasUser, on_delete=models.DO_NOTHING)
209
+ entered_in_error = models.ForeignKey(CanvasUser, on_delete=models.DO_NOTHING)
210
+ order = models.ForeignKey(LabOrder, on_delete=models.DO_NOTHING, related_name="reasons")
211
+ mode = models.CharField(max_length=30, choices=LabReasonMode)
212
+
213
+
214
+ class LabOrderReasonCondition(models.Model):
215
+ """A class representing a lab order reason's condition."""
216
+
217
+ class Meta:
218
+ managed = False
219
+ app_label = "canvas_sdk"
220
+ db_table = "canvas_sdk_data_api_laborderreasoncondition_001"
221
+
222
+ dbid = models.BigIntegerField(primary_key=True)
223
+ created = models.DateTimeField()
224
+ modified = models.DateTimeField()
225
+ reason = models.ForeignKey(
226
+ LabOrderReason, on_delete=models.DO_NOTHING, related_name="reason_conditions", null=True
227
+ )
228
+ condition = models.ForeignKey(
229
+ Condition,
230
+ on_delete=models.DO_NOTHING,
231
+ related_name="lab_order_reason_conditions",
232
+ null=True,
233
+ )
234
+
235
+
236
+ class LabTest(models.Model):
237
+ """A class representing a lab test."""
238
+
239
+ class LabTestOrderStatus(models.TextChoices):
240
+ """Choicees for lab test order statuses."""
241
+
242
+ NEW = "NE", "new"
243
+ STAGED_FOR_REQUISITION = "SR", "staged for requisition"
244
+ SENDING = "SE", "sending"
245
+ SENDING_FAILED = "SF", "sending failed"
246
+ PROCESSING = "PR", "processing"
247
+ PROCESSING_FAILED = "PF", "processing failed"
248
+ RECEIVED = "RE", "received"
249
+ REVIEWED = "RV", "reviewed"
250
+ INACTIVE = "IN", "inactive"
251
+
252
+ class Meta:
253
+ managed = False
254
+ app_label = "canvas_sdk"
255
+ db_table = "canvas_sdk_data_api_labtest_001"
256
+
257
+ id = models.UUIDField()
258
+ dbid = models.BigIntegerField(primary_key=True)
259
+ ontology_test_name = models.CharField(max_length=512, blank=True, default="")
260
+ ontology_test_code = models.CharField(max_length=512, blank=True, default="")
261
+ status = models.CharField(max_length=30, choices=LabTestOrderStatus)
262
+ report = models.ForeignKey(
263
+ LabReport, on_delete=models.DO_NOTHING, null=True, related_name="tests"
264
+ )
265
+ aoe_code = models.CharField(max_length=10, default="")
266
+ procedure_class = models.CharField(max_length=10, default="")
267
+ specimen_type = models.CharField()
268
+ specimen_source_code = models.CharField()
269
+ specimen_source_description = models.CharField()
270
+ specimen_source_coding_system = models.CharField()
271
+ order = models.ForeignKey(
272
+ LabOrder, on_delete=models.DO_NOTHING, related_name="tests", null=True
273
+ )
274
+
275
+ def __str__(self) -> str:
276
+ return f"{self.ontology_test_name}: f{self.ontology_test_code}"