canvas 0.63.0__py3-none-any.whl → 0.89.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.
Files changed (185) hide show
  1. {canvas-0.63.0.dist-info → canvas-0.89.0.dist-info}/METADATA +4 -1
  2. {canvas-0.63.0.dist-info → canvas-0.89.0.dist-info}/RECORD +184 -98
  3. {canvas-0.63.0.dist-info → canvas-0.89.0.dist-info}/WHEEL +1 -1
  4. canvas_cli/apps/emit/event_fixtures/UNKNOWN.ndjson +1 -0
  5. canvas_cli/apps/logs/logs.py +386 -22
  6. canvas_cli/main.py +3 -1
  7. canvas_cli/templates/plugins/default/{{ cookiecutter.__project_slug }}/tests/test_models.py +46 -4
  8. canvas_cli/utils/context/context.py +13 -13
  9. canvas_cli/utils/validators/manifest_schema.py +26 -1
  10. canvas_generated/messages/effects_pb2.py +5 -5
  11. canvas_generated/messages/effects_pb2.pyi +108 -2
  12. canvas_generated/messages/events_pb2.py +6 -6
  13. canvas_generated/messages/events_pb2.pyi +282 -2
  14. canvas_sdk/clients/__init__.py +1 -0
  15. canvas_sdk/clients/llms/__init__.py +17 -0
  16. canvas_sdk/clients/llms/libraries/__init__.py +11 -0
  17. canvas_sdk/clients/llms/libraries/llm_anthropic.py +87 -0
  18. canvas_sdk/clients/llms/libraries/llm_api.py +143 -0
  19. canvas_sdk/clients/llms/libraries/llm_google.py +92 -0
  20. canvas_sdk/clients/llms/libraries/llm_openai.py +98 -0
  21. canvas_sdk/clients/llms/structures/__init__.py +9 -0
  22. canvas_sdk/clients/llms/structures/llm_response.py +33 -0
  23. canvas_sdk/clients/llms/structures/llm_tokens.py +53 -0
  24. canvas_sdk/clients/llms/structures/llm_turn.py +47 -0
  25. canvas_sdk/clients/llms/structures/settings/__init__.py +13 -0
  26. canvas_sdk/clients/llms/structures/settings/llm_settings.py +27 -0
  27. canvas_sdk/clients/llms/structures/settings/llm_settings_anthropic.py +43 -0
  28. canvas_sdk/clients/llms/structures/settings/llm_settings_gemini.py +40 -0
  29. canvas_sdk/clients/llms/structures/settings/llm_settings_gpt4.py +40 -0
  30. canvas_sdk/clients/llms/structures/settings/llm_settings_gpt5.py +48 -0
  31. canvas_sdk/clients/third_party.py +3 -0
  32. canvas_sdk/commands/__init__.py +12 -0
  33. canvas_sdk/commands/base.py +33 -2
  34. canvas_sdk/commands/commands/adjust_prescription.py +4 -0
  35. canvas_sdk/commands/commands/custom_command.py +86 -0
  36. canvas_sdk/commands/commands/family_history.py +17 -1
  37. canvas_sdk/commands/commands/immunization_statement.py +42 -2
  38. canvas_sdk/commands/commands/medication_statement.py +16 -1
  39. canvas_sdk/commands/commands/past_surgical_history.py +16 -1
  40. canvas_sdk/commands/commands/perform.py +18 -1
  41. canvas_sdk/commands/commands/prescribe.py +8 -9
  42. canvas_sdk/commands/commands/refill.py +5 -5
  43. canvas_sdk/commands/commands/resolve_condition.py +5 -5
  44. canvas_sdk/commands/commands/review/__init__.py +3 -0
  45. canvas_sdk/commands/commands/review/base.py +72 -0
  46. canvas_sdk/commands/commands/review/imaging.py +13 -0
  47. canvas_sdk/commands/commands/review/lab.py +13 -0
  48. canvas_sdk/commands/commands/review/referral.py +13 -0
  49. canvas_sdk/commands/commands/review/uncategorized_document.py +13 -0
  50. canvas_sdk/commands/validation.py +43 -0
  51. canvas_sdk/effects/batch_originate.py +22 -0
  52. canvas_sdk/effects/calendar/__init__.py +13 -3
  53. canvas_sdk/effects/calendar/{create_calendar.py → calendar.py} +19 -5
  54. canvas_sdk/effects/calendar/event.py +172 -0
  55. canvas_sdk/effects/claim_label.py +93 -0
  56. canvas_sdk/effects/claim_line_item.py +47 -0
  57. canvas_sdk/effects/claim_queue.py +49 -0
  58. canvas_sdk/effects/fax/__init__.py +3 -0
  59. canvas_sdk/effects/fax/base.py +77 -0
  60. canvas_sdk/effects/fax/note.py +42 -0
  61. canvas_sdk/effects/metadata.py +15 -1
  62. canvas_sdk/effects/note/__init__.py +8 -1
  63. canvas_sdk/effects/note/appointment.py +135 -7
  64. canvas_sdk/effects/note/base.py +17 -0
  65. canvas_sdk/effects/note/message.py +22 -14
  66. canvas_sdk/effects/note/note.py +150 -1
  67. canvas_sdk/effects/observation/__init__.py +11 -0
  68. canvas_sdk/effects/observation/base.py +206 -0
  69. canvas_sdk/effects/patient/__init__.py +2 -0
  70. canvas_sdk/effects/patient/base.py +8 -0
  71. canvas_sdk/effects/payment/__init__.py +11 -0
  72. canvas_sdk/effects/payment/base.py +355 -0
  73. canvas_sdk/effects/payment/post_claim_payment.py +49 -0
  74. canvas_sdk/effects/send_contact_verification.py +42 -0
  75. canvas_sdk/effects/task/__init__.py +2 -1
  76. canvas_sdk/effects/task/task.py +30 -0
  77. canvas_sdk/effects/validation/__init__.py +3 -0
  78. canvas_sdk/effects/validation/base.py +92 -0
  79. canvas_sdk/events/base.py +15 -0
  80. canvas_sdk/handlers/application.py +7 -7
  81. canvas_sdk/handlers/simple_api/api.py +1 -4
  82. canvas_sdk/handlers/simple_api/websocket.py +1 -4
  83. canvas_sdk/handlers/utils.py +14 -0
  84. canvas_sdk/questionnaires/utils.py +1 -0
  85. canvas_sdk/templates/utils.py +17 -4
  86. canvas_sdk/test_utils/factories/FACTORY_GUIDE.md +362 -0
  87. canvas_sdk/test_utils/factories/__init__.py +115 -0
  88. canvas_sdk/test_utils/factories/calendar.py +24 -0
  89. canvas_sdk/test_utils/factories/claim.py +81 -0
  90. canvas_sdk/test_utils/factories/claim_diagnosis_code.py +16 -0
  91. canvas_sdk/test_utils/factories/coverage.py +17 -0
  92. canvas_sdk/test_utils/factories/imaging.py +74 -0
  93. canvas_sdk/test_utils/factories/lab.py +192 -0
  94. canvas_sdk/test_utils/factories/medication_history.py +75 -0
  95. canvas_sdk/test_utils/factories/note.py +52 -0
  96. canvas_sdk/test_utils/factories/organization.py +50 -0
  97. canvas_sdk/test_utils/factories/practicelocation.py +88 -0
  98. canvas_sdk/test_utils/factories/referral.py +81 -0
  99. canvas_sdk/test_utils/factories/staff.py +111 -0
  100. canvas_sdk/test_utils/factories/task.py +66 -0
  101. canvas_sdk/test_utils/factories/uncategorized_clinical_document.py +48 -0
  102. canvas_sdk/utils/metrics.py +4 -1
  103. canvas_sdk/v1/data/__init__.py +66 -7
  104. canvas_sdk/v1/data/allergy_intolerance.py +5 -11
  105. canvas_sdk/v1/data/appointment.py +18 -4
  106. canvas_sdk/v1/data/assessment.py +2 -12
  107. canvas_sdk/v1/data/banner_alert.py +2 -4
  108. canvas_sdk/v1/data/base.py +53 -14
  109. canvas_sdk/v1/data/billing.py +8 -11
  110. canvas_sdk/v1/data/calendar.py +64 -0
  111. canvas_sdk/v1/data/care_team.py +4 -10
  112. canvas_sdk/v1/data/claim.py +172 -66
  113. canvas_sdk/v1/data/claim_diagnosis_code.py +19 -0
  114. canvas_sdk/v1/data/claim_line_item.py +2 -5
  115. canvas_sdk/v1/data/coding.py +19 -0
  116. canvas_sdk/v1/data/command.py +2 -4
  117. canvas_sdk/v1/data/common.py +10 -0
  118. canvas_sdk/v1/data/compound_medication.py +3 -4
  119. canvas_sdk/v1/data/condition.py +4 -9
  120. canvas_sdk/v1/data/coverage.py +66 -26
  121. canvas_sdk/v1/data/detected_issue.py +20 -20
  122. canvas_sdk/v1/data/device.py +2 -14
  123. canvas_sdk/v1/data/discount.py +2 -5
  124. canvas_sdk/v1/data/encounter.py +44 -0
  125. canvas_sdk/v1/data/facility.py +1 -0
  126. canvas_sdk/v1/data/goal.py +2 -14
  127. canvas_sdk/v1/data/imaging.py +4 -30
  128. canvas_sdk/v1/data/immunization.py +7 -15
  129. canvas_sdk/v1/data/lab.py +12 -65
  130. canvas_sdk/v1/data/line_item_transaction.py +2 -5
  131. canvas_sdk/v1/data/medication.py +3 -8
  132. canvas_sdk/v1/data/medication_history.py +142 -0
  133. canvas_sdk/v1/data/medication_statement.py +41 -0
  134. canvas_sdk/v1/data/message.py +4 -8
  135. canvas_sdk/v1/data/note.py +37 -38
  136. canvas_sdk/v1/data/observation.py +9 -36
  137. canvas_sdk/v1/data/organization.py +70 -9
  138. canvas_sdk/v1/data/patient.py +8 -12
  139. canvas_sdk/v1/data/patient_consent.py +4 -14
  140. canvas_sdk/v1/data/payment_collection.py +2 -5
  141. canvas_sdk/v1/data/posting.py +3 -9
  142. canvas_sdk/v1/data/practicelocation.py +66 -7
  143. canvas_sdk/v1/data/protocol_override.py +3 -4
  144. canvas_sdk/v1/data/protocol_result.py +3 -3
  145. canvas_sdk/v1/data/questionnaire.py +10 -26
  146. canvas_sdk/v1/data/reason_for_visit.py +2 -6
  147. canvas_sdk/v1/data/referral.py +41 -17
  148. canvas_sdk/v1/data/staff.py +34 -26
  149. canvas_sdk/v1/data/stop_medication_event.py +27 -0
  150. canvas_sdk/v1/data/task.py +30 -11
  151. canvas_sdk/v1/data/team.py +2 -4
  152. canvas_sdk/v1/data/uncategorized_clinical_document.py +84 -0
  153. canvas_sdk/v1/data/user.py +14 -0
  154. canvas_sdk/v1/data/utils.py +5 -0
  155. canvas_sdk/value_set/v2026/__init__.py +1 -0
  156. canvas_sdk/value_set/v2026/adverse_event.py +157 -0
  157. canvas_sdk/value_set/v2026/allergy.py +116 -0
  158. canvas_sdk/value_set/v2026/assessment.py +466 -0
  159. canvas_sdk/value_set/v2026/communication.py +496 -0
  160. canvas_sdk/value_set/v2026/condition.py +52934 -0
  161. canvas_sdk/value_set/v2026/device.py +315 -0
  162. canvas_sdk/value_set/v2026/diagnostic_study.py +5243 -0
  163. canvas_sdk/value_set/v2026/encounter.py +2714 -0
  164. canvas_sdk/value_set/v2026/immunization.py +297 -0
  165. canvas_sdk/value_set/v2026/individual_characteristic.py +339 -0
  166. canvas_sdk/value_set/v2026/intervention.py +1703 -0
  167. canvas_sdk/value_set/v2026/laboratory_test.py +1831 -0
  168. canvas_sdk/value_set/v2026/medication.py +8218 -0
  169. canvas_sdk/value_set/v2026/no_qdm_category_assigned.py +26493 -0
  170. canvas_sdk/value_set/v2026/physical_exam.py +342 -0
  171. canvas_sdk/value_set/v2026/procedure.py +27869 -0
  172. canvas_sdk/value_set/v2026/symptom.py +625 -0
  173. logger/logger.py +30 -31
  174. logger/logstash.py +282 -0
  175. logger/pubsub.py +26 -0
  176. plugin_runner/allowed-module-imports.json +940 -9
  177. plugin_runner/generate_allowed_imports.py +1 -0
  178. plugin_runner/installation.py +2 -2
  179. plugin_runner/plugin_runner.py +21 -24
  180. plugin_runner/sandbox.py +34 -0
  181. protobufs/canvas_generated/messages/effects.proto +65 -0
  182. protobufs/canvas_generated/messages/events.proto +150 -51
  183. settings.py +27 -11
  184. canvas_sdk/effects/calendar/create_event.py +0 -43
  185. {canvas-0.63.0.dist-info → canvas-0.89.0.dist-info}/entry_points.txt +0 -0
@@ -10,19 +10,17 @@ from canvas_sdk.v1.data.base import (
10
10
  CommittableQuerySetMixin,
11
11
  ForPatientQuerySetMixin,
12
12
  IdentifiableModel,
13
- Model,
13
+ TimestampedModel,
14
14
  ValueSetLookupByNameQuerySet,
15
15
  )
16
16
 
17
17
 
18
- class ResponseOptionSet(Model):
18
+ class ResponseOptionSet(TimestampedModel):
19
19
  """ResponseOptionSet."""
20
20
 
21
21
  class Meta:
22
22
  db_table = "canvas_sdk_data_api_responseoptionset_001"
23
23
 
24
- created = models.DateTimeField(auto_now_add=True)
25
- modified = models.DateTimeField(auto_now=True)
26
24
  status = models.CharField(max_length=2)
27
25
  name = models.CharField(max_length=255)
28
26
  code_system = models.CharField(max_length=255)
@@ -31,14 +29,12 @@ class ResponseOptionSet(Model):
31
29
  use_in_shx = models.BooleanField()
32
30
 
33
31
 
34
- class ResponseOption(Model):
32
+ class ResponseOption(TimestampedModel):
35
33
  """ResponseOption."""
36
34
 
37
35
  class Meta:
38
36
  db_table = "canvas_sdk_data_api_responseoption_001"
39
37
 
40
- created = models.DateTimeField(auto_now_add=True)
41
- modified = models.DateTimeField(auto_now=True)
42
38
  status = models.CharField(max_length=2)
43
39
  name = models.CharField(max_length=255)
44
40
  code = models.CharField(max_length=100)
@@ -50,14 +46,12 @@ class ResponseOption(Model):
50
46
  ordering = models.IntegerField()
51
47
 
52
48
 
53
- class Question(IdentifiableModel):
49
+ class Question(TimestampedModel, IdentifiableModel):
54
50
  """Question."""
55
51
 
56
52
  class Meta:
57
53
  db_table = "canvas_sdk_data_api_question_001"
58
54
 
59
- created = models.DateTimeField(auto_now_add=True)
60
- modified = models.DateTimeField(auto_now=True)
61
55
  status = models.CharField(max_length=2)
62
56
  name = models.CharField(max_length=255)
63
57
  response_option_set = models.ForeignKey(
@@ -78,7 +72,7 @@ class QuestionnaireValueSetLookupQuerySet(ValueSetLookupByNameQuerySet):
78
72
  return Q(code_system=system, code__in=codes)
79
73
 
80
74
 
81
- class Questionnaire(IdentifiableModel):
75
+ class Questionnaire(TimestampedModel, IdentifiableModel):
82
76
  """Questionnaire."""
83
77
 
84
78
  class Meta:
@@ -86,8 +80,6 @@ class Questionnaire(IdentifiableModel):
86
80
 
87
81
  objects = models.Manager.from_queryset(QuestionnaireValueSetLookupQuerySet)()
88
82
 
89
- created = models.DateTimeField(auto_now_add=True)
90
- modified = models.DateTimeField(auto_now=True)
91
83
  status = models.CharField(max_length=2)
92
84
  name = models.CharField(max_length=255)
93
85
  expected_completion_time = models.FloatField()
@@ -104,20 +96,18 @@ class Questionnaire(IdentifiableModel):
104
96
  carry_forward = models.TextField()
105
97
 
106
98
 
107
- class QuestionnaireQuestionMap(Model):
99
+ class QuestionnaireQuestionMap(TimestampedModel):
108
100
  """QuestionnaireQuestionMap."""
109
101
 
110
102
  class Meta:
111
103
  db_table = "canvas_sdk_data_api_questionnairequestionmap_001"
112
104
 
113
- created = models.DateTimeField(auto_now_add=True)
114
- modified = models.DateTimeField(auto_now=True)
115
105
  status = models.CharField(max_length=2)
116
106
  questionnaire = models.ForeignKey(Questionnaire, on_delete=models.DO_NOTHING, null=True)
117
107
  question = models.ForeignKey(Question, on_delete=models.DO_NOTHING, null=True)
118
108
 
119
109
 
120
- class InterviewQuerySet(BaseQuerySet, ForPatientQuerySetMixin, CommittableQuerySetMixin):
110
+ class InterviewQuerySet(ForPatientQuerySetMixin, CommittableQuerySetMixin, BaseQuerySet):
121
111
  """InterviewQuerySet."""
122
112
 
123
113
  pass
@@ -126,7 +116,7 @@ class InterviewQuerySet(BaseQuerySet, ForPatientQuerySetMixin, CommittableQueryS
126
116
  InterviewManager = BaseModelManager.from_queryset(InterviewQuerySet)
127
117
 
128
118
 
129
- class Interview(IdentifiableModel):
119
+ class Interview(TimestampedModel, IdentifiableModel):
130
120
  """Interview."""
131
121
 
132
122
  class Meta:
@@ -155,31 +145,25 @@ class Interview(IdentifiableModel):
155
145
  through="v1.InterviewQuestionnaireMap",
156
146
  )
157
147
  progress_status = models.CharField(max_length=3)
158
- created = models.DateTimeField(auto_now_add=True)
159
- modified = models.DateTimeField(auto_now=True)
160
148
 
161
149
 
162
- class InterviewQuestionnaireMap(Model):
150
+ class InterviewQuestionnaireMap(TimestampedModel):
163
151
  """InterviewQuestionnaireMap."""
164
152
 
165
153
  class Meta:
166
154
  db_table = "canvas_sdk_data_api_interviewquestionnairemap_001"
167
155
 
168
- created = models.DateTimeField(auto_now_add=True)
169
- modified = models.DateTimeField(auto_now=True)
170
156
  status = models.CharField(max_length=2)
171
157
  interview = models.ForeignKey(Interview, on_delete=models.DO_NOTHING, null=True)
172
158
  questionnaire = models.ForeignKey(Questionnaire, on_delete=models.DO_NOTHING, null=True)
173
159
 
174
160
 
175
- class InterviewQuestionResponse(Model):
161
+ class InterviewQuestionResponse(TimestampedModel):
176
162
  """InterviewQuestionResponse."""
177
163
 
178
164
  class Meta:
179
165
  db_table = "canvas_sdk_data_api_interviewquestionresponse_001"
180
166
 
181
- created = models.DateTimeField(auto_now_add=True)
182
- modified = models.DateTimeField(auto_now=True)
183
167
  status = models.CharField(max_length=2)
184
168
  interview = models.ForeignKey(
185
169
  Interview, on_delete=models.DO_NOTHING, related_name="interview_responses", null=True
@@ -2,9 +2,10 @@ from django.contrib.postgres.fields import ArrayField
2
2
  from django.db import models
3
3
 
4
4
  from canvas_sdk.v1.data.base import IdentifiableModel
5
+ from canvas_sdk.v1.data.coding import Coding
5
6
 
6
7
 
7
- class ReasonForVisitSettingCoding(IdentifiableModel):
8
+ class ReasonForVisitSettingCoding(IdentifiableModel, Coding):
8
9
  """ReasonForVisitSettingCoding."""
9
10
 
10
11
  class Meta:
@@ -12,11 +13,6 @@ class ReasonForVisitSettingCoding(IdentifiableModel):
12
13
 
13
14
  objects: models.Manager["ReasonForVisitSettingCoding"]
14
15
 
15
- code = models.CharField(max_length=255)
16
- display = models.CharField(max_length=1000)
17
- system = models.CharField(max_length=255)
18
- version = models.CharField(max_length=255)
19
-
20
16
  duration = ArrayField(models.DurationField())
21
17
 
22
18
 
@@ -1,29 +1,26 @@
1
1
  import json
2
+ from typing import cast
2
3
 
3
4
  from django.db import models
4
5
 
5
- from canvas_sdk.v1.data.base import IdentifiableModel
6
+ from canvas_sdk.v1.data.base import (
7
+ AuditedModel,
8
+ BaseModelManager,
9
+ BaseQuerySet,
10
+ CommittableQuerySetMixin,
11
+ ForPatientQuerySetMixin,
12
+ IdentifiableModel,
13
+ TimestampedModel,
14
+ )
6
15
  from canvas_sdk.v1.data.task import Task
7
16
 
8
17
 
9
- class Referral(IdentifiableModel):
18
+ class Referral(AuditedModel, IdentifiableModel):
10
19
  """Referral."""
11
20
 
12
21
  class Meta:
13
22
  db_table = "canvas_sdk_data_api_referral_001"
14
23
 
15
- created = models.DateTimeField()
16
- modified = models.DateTimeField()
17
- originator = models.ForeignKey(
18
- "v1.CanvasUser", on_delete=models.DO_NOTHING, null=True, related_name="+"
19
- )
20
- deleted = models.BooleanField()
21
- committer = models.ForeignKey(
22
- "v1.CanvasUser", on_delete=models.DO_NOTHING, null=True, related_name="+"
23
- )
24
- entered_in_error = models.ForeignKey(
25
- "v1.CanvasUser", on_delete=models.DO_NOTHING, null=True, related_name="+"
26
- )
27
24
  patient = models.ForeignKey("v1.Patient", on_delete=models.DO_NOTHING)
28
25
  note = models.ForeignKey("v1.Note", on_delete=models.DO_NOTHING)
29
26
  service_provider = models.ForeignKey(
@@ -66,14 +63,38 @@ class Referral(IdentifiableModel):
66
63
  return f"Referral {self.id}"
67
64
 
68
65
 
69
- class ReferralReport(IdentifiableModel):
66
+ class ReferralReviewQuerySet(CommittableQuerySetMixin, ForPatientQuerySetMixin, BaseQuerySet):
67
+ """A queryset for referral reviews."""
68
+
69
+ pass
70
+
71
+
72
+ ReferralReviewManager = BaseModelManager.from_queryset(ReferralReviewQuerySet)
73
+
74
+
75
+ class ReferralReview(AuditedModel, IdentifiableModel):
76
+ """ReferralReview."""
77
+
78
+ class Meta:
79
+ db_table = "canvas_sdk_data_api_referralreview_001"
80
+
81
+ objects = cast(ReferralReviewQuerySet, ReferralReviewManager())
82
+
83
+ internal_comment = models.TextField()
84
+ message_to_patient = models.CharField(max_length=2048)
85
+ status = models.CharField(max_length=50)
86
+ patient = models.ForeignKey(
87
+ "v1.Patient", on_delete=models.DO_NOTHING, related_name="referral_reviews", null=True
88
+ )
89
+ patient_communication_method = models.CharField(max_length=30)
90
+
91
+
92
+ class ReferralReport(TimestampedModel, IdentifiableModel):
70
93
  """ReferralReport."""
71
94
 
72
95
  class Meta:
73
96
  db_table = "canvas_sdk_data_api_referralreport_001"
74
97
 
75
- created = models.DateTimeField(auto_now_add=True)
76
- modified = models.DateTimeField(auto_now=True)
77
98
  originator = models.ForeignKey(
78
99
  "v1.CanvasUser", on_delete=models.DO_NOTHING, null=True, related_name="+"
79
100
  )
@@ -94,6 +115,9 @@ class ReferralReport(IdentifiableModel):
94
115
  Referral, on_delete=models.DO_NOTHING, related_name="reports", null=True
95
116
  )
96
117
  specialty = models.CharField(max_length=250)
118
+ review = models.ForeignKey(
119
+ "ReferralReview", related_name="reports", null=True, blank=True, on_delete=models.SET_NULL
120
+ )
97
121
  original_date = models.DateField(null=True)
98
122
  comment = models.TextField()
99
123
  priority = models.BooleanField(default=False)
@@ -5,7 +5,7 @@ from django.db import models
5
5
  from django.db.models.enums import TextChoices
6
6
  from timezone_utils.fields import TimeZoneField
7
7
 
8
- from canvas_sdk.v1.data.base import IdentifiableModel, Model
8
+ from canvas_sdk.v1.data.base import IdentifiableModel, Model, TimestampedModel
9
9
  from canvas_sdk.v1.data.common import (
10
10
  AddressState,
11
11
  AddressType,
@@ -19,7 +19,7 @@ from canvas_sdk.v1.data.common import (
19
19
  from canvas_sdk.v1.data.utils import create_key
20
20
 
21
21
 
22
- class Staff(Model):
22
+ class Staff(TimestampedModel):
23
23
  """Staff."""
24
24
 
25
25
  class Meta:
@@ -35,8 +35,6 @@ class Staff(Model):
35
35
  editable=False,
36
36
  default=create_key,
37
37
  )
38
- created = models.DateTimeField(auto_now_add=True)
39
- modified = models.DateTimeField(auto_now=True)
40
38
  prefix = models.CharField(max_length=100)
41
39
  suffix = models.CharField(max_length=100)
42
40
  first_name = models.CharField(max_length=255)
@@ -44,7 +42,7 @@ class Staff(Model):
44
42
  last_name = models.CharField(max_length=255)
45
43
  maiden_name = models.CharField(max_length=255)
46
44
  nickname = models.CharField(max_length=255)
47
- previous_names = models.JSONField()
45
+ previous_names = models.JSONField(default=list)
48
46
  birth_date = models.DateField(null=True)
49
47
  sex_at_birth = models.CharField(choices=PersonSex.choices, max_length=3)
50
48
  sexual_orientation_term = models.CharField(max_length=255)
@@ -57,14 +55,14 @@ class Staff(Model):
57
55
  cultural_ethnicity_codes = ArrayField(models.CharField(max_length=100))
58
56
  cultural_ethnicity_terms = ArrayField(models.CharField(max_length=255))
59
57
  last_known_timezone = TimeZoneField(null=True)
60
- active = models.BooleanField()
58
+ active = models.BooleanField(default=True)
61
59
  primary_practice_location = models.ForeignKey(
62
60
  "v1.PracticeLocation", on_delete=models.DO_NOTHING, null=True
63
61
  )
64
62
  npi_number = models.CharField(max_length=10)
65
63
  nadean_number = models.CharField(max_length=20)
66
64
  group_npi_number = models.CharField(max_length=10)
67
- bill_through_organization = models.BooleanField()
65
+ bill_through_organization = models.BooleanField(default=True)
68
66
  tax_id = models.CharField(max_length=25)
69
67
  tax_id_type = models.CharField(choices=TaxIDType.choices, max_length=1)
70
68
  spi_number = models.CharField(max_length=50)
@@ -72,9 +70,9 @@ class Staff(Model):
72
70
  # language = models.ForeignKey('v1.Language', on_delete=models.DO_NOTHING, related_name="staff_speakers", null=True)
73
71
  # language_secondary = models.ForeignKey('v1.Language', on_delete=models.DO_NOTHING, related_name="staff_secondary_speakers", null=True)
74
72
  personal_meeting_room_link = models.URLField(null=True)
75
- state = models.JSONField()
76
- user = models.ForeignKey("v1.CanvasUser", on_delete=models.DO_NOTHING, null=True)
77
- schedule_column_ordering = models.IntegerField()
73
+ state = models.JSONField(default=dict, blank=True)
74
+ user = models.OneToOneField("v1.CanvasUser", on_delete=models.DO_NOTHING, null=True)
75
+ schedule_column_ordering = models.IntegerField(default=999)
78
76
  default_supervising_provider = models.ForeignKey(
79
77
  "v1.Staff", on_delete=models.DO_NOTHING, related_name="supervising_team", null=True
80
78
  )
@@ -135,10 +133,14 @@ class StaffContactPoint(IdentifiableModel):
135
133
 
136
134
  system = models.CharField(choices=ContactPointSystem.choices, max_length=20)
137
135
  value = models.CharField(max_length=100)
138
- use = models.CharField(choices=ContactPointUse.choices, max_length=20)
136
+ use = models.CharField(
137
+ choices=ContactPointUse.choices, max_length=20, default=ContactPointUse.HOME
138
+ )
139
139
  use_notes = models.CharField(max_length=255)
140
- rank = models.IntegerField()
141
- state = models.CharField(choices=ContactPointState.choices, max_length=20)
140
+ rank = models.IntegerField(default=1)
141
+ state = models.CharField(
142
+ choices=ContactPointState.choices, max_length=20, default=ContactPointState.ACTIVE
143
+ )
142
144
  staff = models.ForeignKey(Staff, on_delete=models.DO_NOTHING, related_name="telecom")
143
145
 
144
146
 
@@ -148,31 +150,31 @@ class StaffAddress(IdentifiableModel):
148
150
  class Meta:
149
151
  db_table = "canvas_sdk_data_api_staffaddress_001"
150
152
 
151
- line1 = models.CharField(max_length=255)
152
- line2 = models.CharField(max_length=255)
153
+ line1 = models.CharField(max_length=255, default="", blank=True)
154
+ line2 = models.CharField(max_length=255, default="", blank=True)
153
155
  city = models.CharField(max_length=255)
154
- district = models.CharField(max_length=255)
156
+ district = models.CharField(max_length=255, blank=True, default="")
155
157
  state_code = models.CharField(max_length=2)
156
158
  postal_code = models.CharField(max_length=255)
157
- use = models.CharField(choices=AddressUse.choices, max_length=10)
158
- type = models.CharField(choices=AddressType.choices, max_length=10)
159
- longitude = models.FloatField()
160
- latitude = models.FloatField()
161
- start = models.DateField()
162
- end = models.DateField()
159
+ use = models.CharField(choices=AddressUse.choices, max_length=10, default=AddressUse.HOME)
160
+ type = models.CharField(choices=AddressType.choices, max_length=10, default=AddressType.BOTH)
161
+ longitude = models.FloatField(null=True, default=None, blank=True)
162
+ latitude = models.FloatField(null=True, default=None, blank=True)
163
+ start = models.DateField(null=True, blank=True)
164
+ end = models.DateField(null=True, blank=True)
163
165
  country = models.CharField(max_length=255)
164
- state = models.CharField(choices=AddressState.choices, max_length=20)
166
+ state = models.CharField(
167
+ choices=AddressState.choices, max_length=20, default=AddressState.ACTIVE
168
+ )
165
169
  staff = models.ForeignKey(Staff, on_delete=models.DO_NOTHING, related_name="addresses")
166
170
 
167
171
 
168
- class StaffPhoto(Model):
172
+ class StaffPhoto(TimestampedModel):
169
173
  """StaffPhoto."""
170
174
 
171
175
  class Meta:
172
176
  db_table = "canvas_sdk_data_api_staffphoto_001"
173
177
 
174
- created = models.DateTimeField(auto_now_add=True)
175
- modified = models.DateTimeField(auto_now=True)
176
178
  staff = models.ForeignKey(Staff, on_delete=models.CASCADE, related_name="photos")
177
179
  url = models.CharField(
178
180
  default="https://d3hn0m4rbsz438.cloudfront.net/avatar1.png", max_length=512
@@ -185,6 +187,12 @@ class StaffRole(Model):
185
187
 
186
188
  class Meta:
187
189
  db_table = "canvas_sdk_data_api_staffrole_001"
190
+ constraints = [
191
+ models.UniqueConstraint(
192
+ fields=["staff", "internal_code"],
193
+ name="staff_internal_code_unique",
194
+ )
195
+ ]
188
196
 
189
197
  class RoleDomain(TextChoices):
190
198
  CLINICAL = "CLI", "Clinical"
@@ -0,0 +1,27 @@
1
+ from django.db import models
2
+
3
+ from canvas_sdk.v1.data.base import AuditedModel, IdentifiableModel
4
+
5
+
6
+ class StopMedicationEvent(AuditedModel, IdentifiableModel):
7
+ """StopMedicationEvent."""
8
+
9
+ class Meta:
10
+ db_table = "canvas_sdk_data_api_stopmedicationevent_001"
11
+
12
+ patient = models.ForeignKey(
13
+ "v1.Patient", on_delete=models.DO_NOTHING, related_name="stopped_medications"
14
+ )
15
+ note = models.ForeignKey(
16
+ "v1.Note", on_delete=models.DO_NOTHING, related_name="stopped_medications"
17
+ )
18
+ medication = models.ForeignKey(
19
+ "v1.Medication",
20
+ on_delete=models.DO_NOTHING,
21
+ related_name="stopmedicationevent_set",
22
+ null=True,
23
+ )
24
+ rationale = models.CharField(max_length=1024, default="")
25
+
26
+
27
+ __exports__ = ("StopMedicationEvent",)
@@ -1,7 +1,7 @@
1
1
  from django.contrib.postgres.fields import ArrayField
2
2
  from django.db import models
3
3
 
4
- from canvas_sdk.v1.data.base import IdentifiableModel, Model
4
+ from canvas_sdk.v1.data.base import IdentifiableModel, Model, TimestampedModel
5
5
  from canvas_sdk.v1.data.common import ColorEnum, Origin
6
6
 
7
7
 
@@ -31,16 +31,15 @@ class TaskLabelModule(models.TextChoices):
31
31
 
32
32
  CLAIMS = "claims", "Claims"
33
33
  TASKS = "tasks", "Tasks"
34
+ APPOINTMENTS = "appointments", "Appointments"
34
35
 
35
36
 
36
- class Task(IdentifiableModel):
37
+ class Task(TimestampedModel, IdentifiableModel):
37
38
  """Task."""
38
39
 
39
40
  class Meta:
40
41
  db_table = "canvas_sdk_data_api_task_001"
41
42
 
42
- created = models.DateTimeField(auto_now_add=True)
43
- modified = models.DateTimeField(auto_now=True)
44
43
  creator = models.ForeignKey(
45
44
  "v1.Staff", on_delete=models.DO_NOTHING, related_name="creator_tasks", null=True
46
45
  )
@@ -60,14 +59,12 @@ class Task(IdentifiableModel):
60
59
  status = models.CharField(choices=TaskStatus.choices, max_length=9)
61
60
 
62
61
 
63
- class TaskComment(IdentifiableModel):
62
+ class TaskComment(TimestampedModel, IdentifiableModel):
64
63
  """TaskComment."""
65
64
 
66
65
  class Meta:
67
66
  db_table = "canvas_sdk_data_api_taskcomment_001"
68
67
 
69
- created = models.DateTimeField(auto_now_add=True)
70
- modified = models.DateTimeField(auto_now=True)
71
68
  creator = models.ForeignKey(
72
69
  "v1.Staff", on_delete=models.DO_NOTHING, related_name="comments", null=True
73
70
  )
@@ -82,12 +79,22 @@ class TaskLabel(IdentifiableModel):
82
79
  db_table = "canvas_sdk_data_api_tasklabel_001"
83
80
 
84
81
  tasks = models.ManyToManyField(Task, related_name="labels", through="TaskTaskLabel") # type: ignore[var-annotated]
82
+ claims = models.ManyToManyField("v1.Claim", related_name="labels", through="v1.ClaimLabel")
83
+ appointments = models.ManyToManyField(
84
+ "v1.Appointment", related_name="labels", through="v1.AppointmentLabel"
85
+ )
85
86
  position = models.IntegerField()
86
- color = models.CharField(choices=ColorEnum.choices, max_length=50)
87
- task_association = ArrayField(models.CharField(choices=Origin.choices, max_length=32))
87
+ color = models.CharField(choices=ColorEnum.choices, max_length=50, blank=True, default="")
88
+ task_association = ArrayField(
89
+ models.CharField(choices=Origin.choices, max_length=32), blank=True, default=list
90
+ )
88
91
  name = models.CharField(max_length=255)
89
- active = models.BooleanField()
90
- modules = ArrayField(models.CharField(choices=TaskLabelModule.choices, max_length=32))
92
+ active = models.BooleanField(default=True)
93
+ modules = ArrayField(
94
+ models.CharField(choices=TaskLabelModule.choices, max_length=32),
95
+ blank=True,
96
+ default=list,
97
+ )
91
98
 
92
99
 
93
100
  class TaskTaskLabel(Model):
@@ -100,6 +107,17 @@ class TaskTaskLabel(Model):
100
107
  task = models.ForeignKey(Task, on_delete=models.DO_NOTHING, null=True)
101
108
 
102
109
 
110
+ class TaskMetadata(IdentifiableModel):
111
+ """TaskMetadata."""
112
+
113
+ class Meta:
114
+ db_table = "canvas_sdk_data_api_taskmetadata_001"
115
+
116
+ task = models.ForeignKey(Task, on_delete=models.CASCADE, related_name="metadata")
117
+ key = models.CharField(max_length=32)
118
+ value = models.CharField(max_length=255)
119
+
120
+
103
121
  __exports__ = (
104
122
  "TaskType",
105
123
  "EventType",
@@ -109,4 +127,5 @@ __exports__ = (
109
127
  "TaskComment",
110
128
  "TaskLabel",
111
129
  "TaskTaskLabel",
130
+ "TaskMetadata",
112
131
  )
@@ -1,7 +1,7 @@
1
1
  from django.contrib.postgres.fields import ArrayField
2
2
  from django.db import models
3
3
 
4
- from canvas_sdk.v1.data.base import IdentifiableModel
4
+ from canvas_sdk.v1.data.base import IdentifiableModel, TimestampedModel
5
5
  from canvas_sdk.v1.data.common import ContactPointState, ContactPointSystem, ContactPointUse
6
6
 
7
7
 
@@ -39,14 +39,12 @@ class TeamResponsibility(models.TextChoices):
39
39
  REVIEW_COVERAGES = "REVIEW_COVERAGES", "Review incomplete patient coverages"
40
40
 
41
41
 
42
- class Team(IdentifiableModel):
42
+ class Team(TimestampedModel, IdentifiableModel):
43
43
  """Team."""
44
44
 
45
45
  class Meta:
46
46
  db_table = "canvas_sdk_data_api_team_001"
47
47
 
48
- created = models.DateTimeField(auto_now_add=True)
49
- modified = models.DateTimeField(auto_now=True)
50
48
  name = models.CharField(max_length=200)
51
49
  responsibilities = ArrayField(
52
50
  models.CharField(choices=TeamResponsibility.choices, max_length=64)
@@ -0,0 +1,84 @@
1
+ from typing import cast
2
+
3
+ from django.db import models
4
+
5
+ from canvas_sdk.v1.data.base import (
6
+ AuditedModel,
7
+ BaseModelManager,
8
+ BaseQuerySet,
9
+ CommittableQuerySetMixin,
10
+ ForPatientQuerySetMixin,
11
+ IdentifiableModel,
12
+ TimestampedModel,
13
+ )
14
+
15
+
16
+ class UncategorizedClinicalDocumentReviewQuerySet(
17
+ CommittableQuerySetMixin, ForPatientQuerySetMixin, BaseQuerySet
18
+ ):
19
+ """A queryset for uncategorized clinical document reviews."""
20
+
21
+ pass
22
+
23
+
24
+ UncategorizedClinicalDocumentReviewManager = BaseModelManager.from_queryset(
25
+ UncategorizedClinicalDocumentReviewQuerySet
26
+ )
27
+
28
+
29
+ class UncategorizedClinicalDocumentReview(AuditedModel, IdentifiableModel):
30
+ """UncategorizedClinicalDocumentReview."""
31
+
32
+ class Meta:
33
+ db_table = "canvas_sdk_data_api_uncategorizeddocumentreview_001"
34
+
35
+ objects = cast(
36
+ UncategorizedClinicalDocumentReviewQuerySet, UncategorizedClinicalDocumentReviewManager()
37
+ )
38
+
39
+ internal_comment = models.TextField()
40
+ message_to_patient = models.CharField(max_length=2048)
41
+ status = models.CharField(max_length=50)
42
+ patient = models.ForeignKey(
43
+ "v1.Patient",
44
+ on_delete=models.DO_NOTHING,
45
+ related_name="uncategorized_clinical_document_reviews",
46
+ null=True,
47
+ )
48
+ patient_communication_method = models.CharField(max_length=30)
49
+
50
+
51
+ class UncategorizedClinicalDocument(TimestampedModel, IdentifiableModel):
52
+ """UncategorizedClinicalDocument."""
53
+
54
+ class Meta:
55
+ db_table = "canvas_sdk_data_api_uncategorizedclinicaldocument_001"
56
+
57
+ patient = models.ForeignKey("v1.Patient", on_delete=models.DO_NOTHING, related_name="+")
58
+ originator = models.ForeignKey(
59
+ "v1.CanvasUser", on_delete=models.DO_NOTHING, null=True, related_name="+"
60
+ )
61
+ assigned_by = models.ForeignKey(
62
+ "v1.CanvasUser", on_delete=models.DO_NOTHING, null=True, related_name="+"
63
+ )
64
+ review = models.ForeignKey(
65
+ "v1.UncategorizedClinicalDocumentReview",
66
+ related_name="reports",
67
+ null=True,
68
+ blank=True,
69
+ on_delete=models.SET_NULL,
70
+ )
71
+ team = models.ForeignKey("v1.Team", on_delete=models.DO_NOTHING, null=True)
72
+
73
+ name = models.CharField(max_length=255)
74
+ review_mode = models.CharField(max_length=2)
75
+ junked = models.BooleanField(default=False)
76
+ requires_signature = models.BooleanField(default=False)
77
+ assigned_date = models.DateTimeField(null=True)
78
+ team_assigned_date = models.DateTimeField(null=True)
79
+ original_date = models.DateField(null=True)
80
+ comment = models.TextField(default="", blank=True)
81
+ priority = models.BooleanField(default=False)
82
+
83
+
84
+ __exports__ = ("UncategorizedClinicalDocumentReview", "UncategorizedClinicalDocument")
@@ -1,7 +1,13 @@
1
+ from functools import cached_property
2
+ from typing import TYPE_CHECKING
3
+
1
4
  from django.db import models
2
5
 
3
6
  from canvas_sdk.v1.data.base import Model
4
7
 
8
+ if TYPE_CHECKING:
9
+ from canvas_sdk.v1.data import Patient, Staff
10
+
5
11
 
6
12
  class CanvasUser(Model):
7
13
  """A class representing a Canvas User."""
@@ -13,6 +19,14 @@ class CanvasUser(Model):
13
19
  phone_number = models.CharField(db_column="phone_number", max_length=255)
14
20
  last_invite_date_time = models.DateTimeField(null=True, blank=True)
15
21
  is_portal_registered = models.BooleanField(default=False)
22
+ is_staff = models.BooleanField(default=False)
23
+
24
+ @cached_property
25
+ def person_subclass(self) -> "Staff | Patient":
26
+ """
27
+ Return either the related Staff or Patient object.
28
+ """
29
+ return self.staff if self.is_staff else self.patient
16
30
 
17
31
 
18
32
  __exports__ = ("CanvasUser",)
@@ -29,4 +29,9 @@ def generate_mrn(length: int = 9, max_attempts: int = 100) -> str:
29
29
  raise RuntimeError(f"Unable to generate a unique MRN after {max_attempts} attempts")
30
30
 
31
31
 
32
+ def empty_note_body() -> list[dict[str, str]]:
33
+ """Generates an empty note body with 15 empty text elements."""
34
+ return [{"type": "text", "value": ""}] * 15
35
+
36
+
32
37
  __exports__ = ()
@@ -0,0 +1 @@
1
+ __exports__ = ()