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
canvas_sdk/v1/data/lab.py CHANGED
@@ -3,19 +3,20 @@ from typing import cast
3
3
  from django.db import models
4
4
 
5
5
  from canvas_sdk.v1.data.base import (
6
+ AuditedModel,
6
7
  BaseModelManager,
7
8
  BaseQuerySet,
8
9
  CommittableQuerySetMixin,
9
10
  ForPatientQuerySetMixin,
10
11
  IdentifiableModel,
11
- Model,
12
12
  TimeframeLookupQuerySetMixin,
13
+ TimestampedModel,
13
14
  ValueSetLookupQuerySet,
14
15
  )
15
16
  from canvas_sdk.v1.data.staff import Staff
16
17
 
17
18
 
18
- class LabReportQuerySet(BaseQuerySet, CommittableQuerySetMixin, ForPatientQuerySetMixin):
19
+ class LabReportQuerySet(CommittableQuerySetMixin, ForPatientQuerySetMixin, BaseQuerySet):
19
20
  """A queryset for lab reports."""
20
21
 
21
22
  pass
@@ -32,7 +33,7 @@ class TransmissionType(models.TextChoices):
32
33
  MANUAL = "M", "manual"
33
34
 
34
35
 
35
- class LabReport(IdentifiableModel):
36
+ class LabReport(AuditedModel, IdentifiableModel):
36
37
  """A class representing a lab report."""
37
38
 
38
39
  class Meta:
@@ -40,8 +41,6 @@ class LabReport(IdentifiableModel):
40
41
 
41
42
  objects = cast(LabReportQuerySet, LabReportManager())
42
43
 
43
- created = models.DateTimeField(auto_now_add=True)
44
- modified = models.DateTimeField(auto_now=True)
45
44
  review_mode = models.CharField(max_length=2)
46
45
  junked = models.BooleanField()
47
46
  requires_signature = models.BooleanField()
@@ -60,19 +59,9 @@ class LabReport(IdentifiableModel):
60
59
  original_date = models.DateTimeField()
61
60
  date_performed = models.DateTimeField()
62
61
  custom_document_name = models.CharField(max_length=500)
63
- originator = models.ForeignKey(
64
- "v1.CanvasUser", on_delete=models.DO_NOTHING, null=True, related_name="+"
65
- )
66
- committer = models.ForeignKey(
67
- "v1.CanvasUser", on_delete=models.DO_NOTHING, null=True, related_name="+"
68
- )
69
- entered_in_error = models.ForeignKey(
70
- "v1.CanvasUser", on_delete=models.DO_NOTHING, null=True, related_name="+"
71
- )
72
- deleted = models.BooleanField()
73
62
 
74
63
 
75
- class LabReviewQuerySet(BaseQuerySet, CommittableQuerySetMixin, ForPatientQuerySetMixin):
64
+ class LabReviewQuerySet(CommittableQuerySetMixin, ForPatientQuerySetMixin, BaseQuerySet):
76
65
  """A queryset for lab reviews."""
77
66
 
78
67
  pass
@@ -81,7 +70,7 @@ class LabReviewQuerySet(BaseQuerySet, CommittableQuerySetMixin, ForPatientQueryS
81
70
  LabReviewManager = BaseModelManager.from_queryset(LabReviewQuerySet)
82
71
 
83
72
 
84
- class LabReview(IdentifiableModel):
73
+ class LabReview(AuditedModel, IdentifiableModel):
85
74
  """A class representing a lab review."""
86
75
 
87
76
  class Meta:
@@ -89,18 +78,6 @@ class LabReview(IdentifiableModel):
89
78
 
90
79
  objects = cast(LabReviewQuerySet, LabReviewManager())
91
80
 
92
- created = models.DateTimeField(auto_now_add=True)
93
- modified = models.DateTimeField(auto_now=True)
94
- originator = models.ForeignKey(
95
- "v1.CanvasUser", on_delete=models.DO_NOTHING, null=True, related_name="+"
96
- )
97
- deleted = models.BooleanField()
98
- committer = models.ForeignKey(
99
- "v1.CanvasUser", on_delete=models.DO_NOTHING, null=True, related_name="+"
100
- )
101
- entered_in_error = models.ForeignKey(
102
- "v1.CanvasUser", on_delete=models.DO_NOTHING, null=True, related_name="+"
103
- )
104
81
  internal_comment = models.TextField()
105
82
  message_to_patient = models.CharField(max_length=2048)
106
83
  status = models.CharField(max_length=50)
@@ -119,13 +96,13 @@ class LabValueTimeframeLookupQuerySetMixin(TimeframeLookupQuerySetMixin):
119
96
  return "report__original_date"
120
97
 
121
98
 
122
- class LabValueQuerySet(ValueSetLookupQuerySet, LabValueTimeframeLookupQuerySetMixin):
99
+ class LabValueQuerySet(LabValueTimeframeLookupQuerySetMixin, ValueSetLookupQuerySet):
123
100
  """LabValueQuerySet."""
124
101
 
125
102
  pass
126
103
 
127
104
 
128
- class LabValue(IdentifiableModel):
105
+ class LabValue(TimestampedModel, IdentifiableModel):
129
106
  """A class representing a lab value."""
130
107
 
131
108
  class Meta:
@@ -133,8 +110,6 @@ class LabValue(IdentifiableModel):
133
110
 
134
111
  objects = LabValueQuerySet.as_manager()
135
112
 
136
- created = models.DateTimeField(auto_now_add=True)
137
- modified = models.DateTimeField(auto_now=True)
138
113
  report = models.ForeignKey(
139
114
  "LabReport", on_delete=models.DO_NOTHING, related_name="values", null=True
140
115
  )
@@ -148,14 +123,12 @@ class LabValue(IdentifiableModel):
148
123
  observation_status = models.CharField(max_length=24)
149
124
 
150
125
 
151
- class LabValueCoding(Model):
126
+ class LabValueCoding(TimestampedModel):
152
127
  """A class representing a lab value coding."""
153
128
 
154
129
  class Meta:
155
130
  db_table = "canvas_sdk_data_api_labvaluecoding_001"
156
131
 
157
- created = models.DateTimeField(auto_now_add=True)
158
- modified = models.DateTimeField(auto_now=True)
159
132
  value = models.ForeignKey(
160
133
  LabValue, on_delete=models.DO_NOTHING, related_name="codings", null=True
161
134
  )
@@ -164,7 +137,7 @@ class LabValueCoding(Model):
164
137
  system = models.CharField(max_length=128)
165
138
 
166
139
 
167
- class LabOrder(IdentifiableModel):
140
+ class LabOrder(AuditedModel, IdentifiableModel):
168
141
  """A class representing a lab order."""
169
142
 
170
143
  class SpecimenCollectionType(models.TextChoices):
@@ -192,18 +165,6 @@ class LabOrder(IdentifiableModel):
192
165
  class Meta:
193
166
  db_table = "canvas_sdk_data_api_laborder_001"
194
167
 
195
- created = models.DateTimeField(auto_now_add=True)
196
- modified = models.DateTimeField(auto_now=True)
197
- originator = models.ForeignKey(
198
- "v1.CanvasUser", on_delete=models.DO_NOTHING, null=True, related_name="+"
199
- )
200
- deleted = models.BooleanField()
201
- committer = models.ForeignKey(
202
- "v1.CanvasUser", on_delete=models.DO_NOTHING, null=True, related_name="+"
203
- )
204
- entered_in_error = models.ForeignKey(
205
- "v1.CanvasUser", on_delete=models.DO_NOTHING, null=True, related_name="+"
206
- )
207
168
  patient = models.ForeignKey(
208
169
  "v1.Patient", on_delete=models.DO_NOTHING, related_name="lab_orders", null=True
209
170
  )
@@ -238,7 +199,7 @@ class LabOrder(IdentifiableModel):
238
199
  reports = models.ManyToManyField("v1.LabReport", through="v1.LabTest")
239
200
 
240
201
 
241
- class LabOrderReason(Model):
202
+ class LabOrderReason(AuditedModel):
242
203
  """A class representing a lab order reason."""
243
204
 
244
205
  class LabReasonMode(models.TextChoices):
@@ -252,32 +213,18 @@ class LabOrderReason(Model):
252
213
  class Meta:
253
214
  db_table = "canvas_sdk_data_api_laborderreason_001"
254
215
 
255
- created = models.DateTimeField(auto_now_add=True)
256
- modified = models.DateTimeField(auto_now=True)
257
- originator = models.ForeignKey(
258
- "v1.CanvasUser", on_delete=models.DO_NOTHING, null=True, related_name="+"
259
- )
260
- deleted = models.BooleanField()
261
- committer = models.ForeignKey(
262
- "v1.CanvasUser", on_delete=models.DO_NOTHING, null=True, related_name="+"
263
- )
264
- entered_in_error = models.ForeignKey(
265
- "v1.CanvasUser", on_delete=models.DO_NOTHING, null=True, related_name="+"
266
- )
267
216
  order = models.ForeignKey(
268
217
  LabOrder, on_delete=models.DO_NOTHING, related_name="reasons", null=True
269
218
  )
270
219
  mode = models.CharField(max_length=30, choices=LabReasonMode)
271
220
 
272
221
 
273
- class LabOrderReasonCondition(Model):
222
+ class LabOrderReasonCondition(TimestampedModel):
274
223
  """A class representing a lab order reason's condition."""
275
224
 
276
225
  class Meta:
277
226
  db_table = "canvas_sdk_data_api_laborderreasoncondition_001"
278
227
 
279
- created = models.DateTimeField(auto_now_add=True)
280
- modified = models.DateTimeField(auto_now=True)
281
228
  reason = models.ForeignKey(
282
229
  LabOrderReason, on_delete=models.DO_NOTHING, related_name="reason_conditions", null=True
283
230
  )
@@ -1,7 +1,7 @@
1
1
  from django.db import models
2
2
  from django.db.models import QuerySet
3
3
 
4
- from canvas_sdk.v1.data.base import Model
4
+ from canvas_sdk.v1.data.base import TimestampedModel
5
5
 
6
6
 
7
7
  class AbstractLineItemQuerySet(models.QuerySet):
@@ -12,7 +12,7 @@ class AbstractLineItemQuerySet(models.QuerySet):
12
12
  return self.filter(entered_in_error__isnull=True)
13
13
 
14
14
 
15
- class AbstractLineItemTransaction(Model):
15
+ class AbstractLineItemTransaction(TimestampedModel):
16
16
  """Abstract class with common properties for both payments and adjustments."""
17
17
 
18
18
  class Meta:
@@ -28,9 +28,6 @@ class AbstractLineItemTransaction(Model):
28
28
  )
29
29
  amount = models.DecimalField(max_digits=8, decimal_places=2)
30
30
 
31
- created = models.DateTimeField(auto_now_add=True)
32
- modified = models.DateTimeField(auto_now=True)
33
-
34
31
 
35
32
  class NewLineItemPayment(AbstractLineItemTransaction):
36
33
  """Subclass that represents a payment on a billing line item."""
@@ -8,9 +8,9 @@ from canvas_sdk.v1.data.base import (
8
8
  CommittableQuerySetMixin,
9
9
  ForPatientQuerySetMixin,
10
10
  IdentifiableModel,
11
- Model,
12
11
  ValueSetLookupQuerySet,
13
12
  )
13
+ from canvas_sdk.v1.data.coding import Coding
14
14
 
15
15
 
16
16
  class Status(TextChoices):
@@ -20,7 +20,7 @@ class Status(TextChoices):
20
20
  INACTIVE = "inactive", "inactive"
21
21
 
22
22
 
23
- class MedicationQuerySet(ValueSetLookupQuerySet, CommittableQuerySetMixin, ForPatientQuerySetMixin):
23
+ class MedicationQuerySet(CommittableQuerySetMixin, ForPatientQuerySetMixin, ValueSetLookupQuerySet):
24
24
  """MedicationQuerySet."""
25
25
 
26
26
  def active(self) -> Self:
@@ -59,17 +59,12 @@ class Medication(IdentifiableModel):
59
59
  erx_quantity = models.FloatField()
60
60
 
61
61
 
62
- class MedicationCoding(Model):
62
+ class MedicationCoding(Coding):
63
63
  """MedicationCoding."""
64
64
 
65
65
  class Meta:
66
66
  db_table = "canvas_sdk_data_api_medicationcoding_001"
67
67
 
68
- system = models.CharField(max_length=255)
69
- version = models.CharField(max_length=255)
70
- code = models.CharField(max_length=255)
71
- display = models.CharField(max_length=1000)
72
- user_selected = models.BooleanField()
73
68
  medication = models.ForeignKey(
74
69
  Medication, on_delete=models.DO_NOTHING, related_name="codings", null=True
75
70
  )
@@ -0,0 +1,142 @@
1
+ from django.contrib.postgres.fields import ArrayField
2
+ from django.db import models
3
+ from django.db.models import TextChoices
4
+
5
+ from canvas_sdk.v1.data.base import (
6
+ IdentifiableModel,
7
+ TimestampedModel,
8
+ )
9
+ from canvas_sdk.v1.data.coding import Coding
10
+
11
+
12
+ class MedicationHistoryMedication(TimestampedModel, IdentifiableModel):
13
+ """MedicationHistoryMedication."""
14
+
15
+ class Meta:
16
+ db_table = "canvas_sdk_data_api_medicationhistorymedication_001"
17
+
18
+ patient = models.ForeignKey(
19
+ "v1.Patient",
20
+ on_delete=models.DO_NOTHING,
21
+ related_name="medication_history_medications",
22
+ null=True,
23
+ )
24
+
25
+ drug_description = models.TextField(blank=True, default="")
26
+
27
+ strength_value = models.CharField(max_length=255, blank=True, default="")
28
+ strength_form = models.CharField(max_length=255, blank=True, default="")
29
+ strength_unit_of_measure = models.CharField(max_length=255, blank=True, default="")
30
+
31
+ quantity = models.FloatField(null=True)
32
+ quantity_unit_of_measure = models.CharField(max_length=255, blank=True, default="")
33
+ quantity_code_list_qualifier = models.CharField(max_length=255, blank=True, default="")
34
+
35
+ days_supply = models.IntegerField(null=True)
36
+
37
+ last_fill_date = models.DateTimeField(db_index=True)
38
+ written_date = models.DateTimeField(blank=True, null=True)
39
+
40
+ other_date = models.DateTimeField(blank=True, null=True)
41
+ other_date_qualifier = models.CharField(max_length=255, blank=True, default="")
42
+
43
+ substitutions = models.BooleanField(null=True)
44
+
45
+ refills_remaining = models.IntegerField(null=True)
46
+
47
+ diagnosis_code = models.CharField(max_length=255, blank=True, default="")
48
+ diagnosis_qualifier = models.CharField(max_length=255, blank=True, default="")
49
+ diagnosis_description = models.CharField(max_length=255, blank=True, default="")
50
+
51
+ secondary_diagnosis_code = models.CharField(max_length=255, blank=True, default="")
52
+ secondary_diagnosis_qualifier = models.CharField(max_length=255, blank=True, default="")
53
+ secondary_diagnosis_description = models.CharField(max_length=255, blank=True, default="")
54
+
55
+ dea_schedule = models.CharField(max_length=255, blank=True, default="")
56
+
57
+ potency_unit_code = models.CharField(max_length=20, blank=True, default="")
58
+ etc_path_id = ArrayField(base_field=models.IntegerField(), null=True)
59
+ etc_path_name = ArrayField(base_field=models.CharField(max_length=255), null=True)
60
+
61
+ fill_number = models.IntegerField(blank=True, null=True)
62
+
63
+ prescriber_order_number = models.CharField(max_length=255, blank=True, default="")
64
+
65
+ source_description = models.CharField(max_length=255, blank=True, default="")
66
+ source_qualifier = models.CharField(max_length=255, blank=True, default="")
67
+ source_payer_id = models.CharField(max_length=255, blank=True, default="")
68
+ source_type = models.CharField(max_length=255, blank=True, default="")
69
+
70
+ note = models.TextField(blank=True, default="")
71
+ sig = models.TextField(blank=True, default="")
72
+
73
+ prior_authorization_status = models.CharField(max_length=255, blank=True, default="")
74
+ prior_authorization = models.CharField(max_length=255, blank=True, default="")
75
+
76
+ pharmacy_name = models.CharField(max_length=255, blank=True, default="")
77
+ pharmacy_ncpdp_id = models.CharField(max_length=255, blank=True, default="")
78
+ pharmacy_npi = models.CharField(max_length=255, blank=True, default="")
79
+
80
+ prescriber_business_name = models.CharField(max_length=255, blank=True, default="")
81
+ prescriber_first_name = models.CharField(max_length=255, blank=True, default="")
82
+ prescriber_last_name = models.CharField(max_length=255, blank=True, default="")
83
+ prescriber_npi = models.CharField(max_length=255, blank=True, default="")
84
+ prescriber_dea_number = models.CharField(max_length=255, blank=True, default="")
85
+
86
+
87
+ class MedicationHistoryMedicationCoding(Coding):
88
+ """MedicationHistoryMedicationCoding."""
89
+
90
+ class Meta:
91
+ db_table = "canvas_sdk_data_api_medicationhistorymedicationcoding_001"
92
+
93
+ medication = models.ForeignKey(
94
+ MedicationHistoryMedication, on_delete=models.CASCADE, related_name="codings"
95
+ )
96
+
97
+
98
+ class MedicationHistoryResponseStatus(TextChoices):
99
+ """MedicationHistoryResponseStatus."""
100
+
101
+ STATUS_APPROVED = "approved"
102
+ STATUS_DENIED = "denied"
103
+
104
+
105
+ class MedicationHistoryResponse(TimestampedModel, IdentifiableModel):
106
+ """MedicationHistoryResponse."""
107
+
108
+ class Meta:
109
+ db_table = "canvas_sdk_data_api_medicationhistoryresponse_001"
110
+
111
+ patient = models.ForeignKey(
112
+ "v1.Patient",
113
+ on_delete=models.CASCADE,
114
+ related_name="medication_history_responses",
115
+ )
116
+ staff = models.ForeignKey(
117
+ "v1.Staff",
118
+ on_delete=models.CASCADE,
119
+ related_name="medication_history_responses",
120
+ null=True,
121
+ )
122
+
123
+ message_id = models.CharField(max_length=35, blank=True, default="", db_index=True)
124
+ related_to_message_id = models.CharField(max_length=35, blank=True, default="", db_index=True)
125
+
126
+ status = models.CharField(choices=MedicationHistoryResponseStatus.choices, max_length=20)
127
+
128
+ reason = models.TextField(blank=True, default="")
129
+ reason_code = models.CharField(max_length=2, blank=True, default="")
130
+
131
+ note = models.TextField(blank=True, default="")
132
+
133
+ start_date = models.DateField()
134
+ end_date = models.DateField()
135
+
136
+
137
+ __exports__ = (
138
+ "MedicationHistoryMedication",
139
+ "MedicationHistoryMedicationCoding",
140
+ "MedicationHistoryResponseStatus",
141
+ "MedicationHistoryResponse",
142
+ )
@@ -0,0 +1,41 @@
1
+ from django.db import models
2
+
3
+ from canvas_sdk.v1.data.base import AuditedModel, IdentifiableModel
4
+
5
+
6
+ class MedicationStatement(AuditedModel, IdentifiableModel):
7
+ """MedicationStatement."""
8
+
9
+ class Meta:
10
+ db_table = "canvas_sdk_data_api_medicationstatement_001"
11
+
12
+ patient = models.ForeignKey(
13
+ "v1.Patient", on_delete=models.DO_NOTHING, related_name="medication_statements"
14
+ )
15
+ note = models.ForeignKey(
16
+ "v1.Note", on_delete=models.DO_NOTHING, related_name="medication_statements"
17
+ )
18
+ medication = models.ForeignKey(
19
+ "v1.Medication",
20
+ on_delete=models.DO_NOTHING,
21
+ related_name="medication_statements",
22
+ null=True,
23
+ )
24
+ indications = models.ManyToManyField(
25
+ "v1.Assessment",
26
+ related_name="treatments_stated",
27
+ db_table="canvas_sdk_data_api_medicationstatement_indications_001",
28
+ )
29
+ start_date_original_input = models.CharField(max_length=255, default="")
30
+ start_date = models.DateField(default=None, null=True)
31
+ end_date_original_input = models.CharField(max_length=255, default="")
32
+ end_date = models.DateField(default=None, null=True)
33
+ dose_quantity = models.FloatField(null=True)
34
+ dose_form = models.CharField(max_length=255, default="")
35
+ dose_route = models.CharField(max_length=255, default="")
36
+ dose_frequency = models.FloatField(null=True)
37
+ dose_frequency_interval = models.CharField(max_length=255, default="")
38
+ sig_original_input = models.CharField(max_length=1000, default="")
39
+
40
+
41
+ __exports__ = ("MedicationStatement",)
@@ -1,6 +1,6 @@
1
1
  from django.db import models
2
2
 
3
- from canvas_sdk.v1.data.base import IdentifiableModel
3
+ from canvas_sdk.v1.data.base import IdentifiableModel, TimestampedModel
4
4
 
5
5
 
6
6
  class TransmissionChannel(models.TextChoices):
@@ -12,14 +12,12 @@ class TransmissionChannel(models.TextChoices):
12
12
  NOOP = "noop", "No-op"
13
13
 
14
14
 
15
- class Message(IdentifiableModel):
15
+ class Message(TimestampedModel, IdentifiableModel):
16
16
  """Message."""
17
17
 
18
18
  class Meta:
19
19
  db_table = "canvas_sdk_data_api_message_001"
20
20
 
21
- created = models.DateTimeField(auto_now_add=True)
22
- modified = models.DateTimeField(auto_now=True)
23
21
  content = models.TextField()
24
22
  sender = models.ForeignKey(
25
23
  "v1.CanvasUser", on_delete=models.DO_NOTHING, related_name="sent_messages", null=True
@@ -30,7 +28,7 @@ class Message(IdentifiableModel):
30
28
  note = models.ForeignKey(
31
29
  "v1.Note", on_delete=models.DO_NOTHING, related_name="message", null=True
32
30
  )
33
- read = models.BooleanField()
31
+ read = models.DateTimeField(null=True, blank=True)
34
32
 
35
33
 
36
34
  class MessageAttachment(IdentifiableModel):
@@ -46,14 +44,12 @@ class MessageAttachment(IdentifiableModel):
46
44
  )
47
45
 
48
46
 
49
- class MessageTransmission(IdentifiableModel):
47
+ class MessageTransmission(TimestampedModel, IdentifiableModel):
50
48
  """Message Transmission."""
51
49
 
52
50
  class Meta:
53
51
  db_table = "canvas_sdk_data_api_messagetransmission_001"
54
52
 
55
- created = models.DateTimeField(auto_now_add=True)
56
- modified = models.DateTimeField(auto_now=True)
57
53
  message = models.ForeignKey(
58
54
  "v1.Message", on_delete=models.DO_NOTHING, related_name="transmissions", null=True
59
55
  )
@@ -1,8 +1,13 @@
1
+ import uuid
2
+
1
3
  from django.contrib.postgres.fields import ArrayField
2
4
  from django.db import models
5
+ from django.utils import timezone
3
6
 
4
- from canvas_sdk.v1.data.base import IdentifiableModel
7
+ from canvas_sdk.v1.data.base import IdentifiableModel, TimestampedModel
5
8
  from canvas_sdk.v1.data.claim import Claim
9
+ from canvas_sdk.v1.data.coding import Coding
10
+ from canvas_sdk.v1.data.utils import empty_note_body
6
11
 
7
12
 
8
13
  class NoteTypeCategories(models.TextChoices):
@@ -103,6 +108,7 @@ class NoteStates(models.TextChoices):
103
108
  RECALLED = "RCL", "Recalled"
104
109
  UNDELETED = "UND", "Undeleted"
105
110
  DISCHARGED = "DSC", "Discharged"
111
+ SIGNED = "SGN", "Signed"
106
112
  # Appointment note
107
113
  SCHEDULING = "SCH", "Scheduling"
108
114
  BOOKED = "BKD", "Booked"
@@ -114,7 +120,7 @@ class NoteStates(models.TextChoices):
114
120
  CONFIRM_IMPORT = "CNF", "Confirmed"
115
121
 
116
122
 
117
- class NoteType(IdentifiableModel):
123
+ class NoteType(TimestampedModel, IdentifiableModel, Coding):
118
124
  """NoteType."""
119
125
 
120
126
  objects: models.Manager["NoteType"]
@@ -122,45 +128,37 @@ class NoteType(IdentifiableModel):
122
128
  class Meta:
123
129
  db_table = "canvas_sdk_data_api_notetype_001"
124
130
 
125
- created = models.DateTimeField(auto_now_add=True)
126
- modified = models.DateTimeField(auto_now=True)
127
- system = models.CharField(max_length=255)
128
- version = models.CharField(max_length=255)
129
- code = models.CharField(max_length=255)
130
- display = models.CharField(max_length=1000)
131
- user_selected = models.BooleanField()
132
131
  name = models.CharField(max_length=250)
133
132
  icon = models.CharField(max_length=250)
134
133
  category = models.CharField(choices=NoteTypeCategories.choices, max_length=50)
135
- rank = models.PositiveIntegerField()
136
- is_default_appointment_type = models.BooleanField()
137
- is_scheduleable = models.BooleanField()
138
- is_telehealth = models.BooleanField()
139
- is_billable = models.BooleanField()
140
- defer_place_of_service_to_practice_location = models.BooleanField()
134
+ rank = models.PositiveIntegerField(default=1)
135
+ is_default_appointment_type = models.BooleanField(default=False)
136
+ is_scheduleable = models.BooleanField(default=True)
137
+ is_telehealth = models.BooleanField(default=False)
138
+ is_billable = models.BooleanField(default=True)
139
+ defer_place_of_service_to_practice_location = models.BooleanField(default=False)
141
140
  available_places_of_service = ArrayField(
142
141
  models.CharField(choices=PracticeLocationPOS.choices, max_length=5)
143
142
  )
144
143
  default_place_of_service = models.CharField(choices=PracticeLocationPOS.choices, max_length=5)
145
- is_system_managed = models.BooleanField()
146
- is_visible = models.BooleanField()
147
- is_active = models.BooleanField()
148
- unique_identifier = models.UUIDField()
149
- deprecated_at = models.DateTimeField()
150
- is_patient_required = models.BooleanField()
151
- allow_custom_title = models.BooleanField()
152
- is_scheduleable_via_patient_portal = models.BooleanField()
153
- online_duration = models.IntegerField()
154
-
155
-
156
- class Note(IdentifiableModel):
144
+ is_system_managed = models.BooleanField(default=False, editable=False)
145
+ is_visible = models.BooleanField(default=True)
146
+ is_active = models.BooleanField(default=True)
147
+ unique_identifier = models.UUIDField(default=uuid.uuid4, editable=False)
148
+ deprecated_at = models.DateTimeField(null=True, editable=False)
149
+ is_patient_required = models.BooleanField(default=False)
150
+ allow_custom_title = models.BooleanField(default=False)
151
+ is_scheduleable_via_patient_portal = models.BooleanField(default=False)
152
+ online_duration = models.IntegerField(default=0)
153
+ is_sig_required = models.BooleanField(default=True)
154
+
155
+
156
+ class Note(TimestampedModel, IdentifiableModel):
157
157
  """Note."""
158
158
 
159
159
  class Meta:
160
160
  db_table = "canvas_sdk_data_api_note_001"
161
161
 
162
- created = models.DateTimeField(auto_now_add=True)
163
- modified = models.DateTimeField(auto_now=True)
164
162
  patient = models.ForeignKey(
165
163
  "v1.Patient", on_delete=models.DO_NOTHING, related_name="notes", null=True
166
164
  )
@@ -169,19 +167,19 @@ class Note(IdentifiableModel):
169
167
  )
170
168
  note_type = models.CharField(choices=NoteTypes.choices, null=True, max_length=50)
171
169
  note_type_version = models.ForeignKey(
172
- "v1.NoteType", on_delete=models.DO_NOTHING, related_name="notes", null=True
170
+ "v1.NoteType", on_delete=models.DO_NOTHING, related_name="notes"
173
171
  )
174
- title = models.TextField()
175
- body = models.JSONField()
172
+ title = models.TextField(default="", blank=True)
173
+ body = models.JSONField(default=empty_note_body)
176
174
  originator = models.ForeignKey("v1.CanvasUser", on_delete=models.DO_NOTHING, null=True)
177
175
  last_modified_by_staff = models.ForeignKey("v1.Staff", on_delete=models.DO_NOTHING, null=True)
178
176
  checksum = models.CharField(max_length=32)
179
177
  billing_note = models.TextField()
180
178
  # TODO -implement InpatientStay model
181
179
  # inpatient_stay = models.ForeignKey("v1.InpatientStay", on_delete=models.DO_NOTHING, null=True)
182
- related_data = models.JSONField()
180
+ related_data = models.JSONField(default=dict, blank=True)
183
181
  location = models.ForeignKey("v1.PracticeLocation", on_delete=models.DO_NOTHING, null=True)
184
- datetime_of_service = models.DateTimeField()
182
+ datetime_of_service = models.DateTimeField(default=timezone.now)
185
183
  place_of_service = models.CharField(max_length=255)
186
184
 
187
185
  def get_claim(self) -> Claim | None:
@@ -192,14 +190,13 @@ class Note(IdentifiableModel):
192
190
  return self.claims.order_by("-created").first()
193
191
 
194
192
 
195
- class NoteStateChangeEvent(IdentifiableModel):
193
+ class NoteStateChangeEvent(TimestampedModel, IdentifiableModel):
196
194
  """NoteStateChangeEvent."""
197
195
 
198
196
  class Meta:
197
+ ordering = ("created", "id")
199
198
  db_table = "canvas_sdk_data_api_notestatechangeevent_001"
200
199
 
201
- created = models.DateTimeField()
202
- modified = models.DateTimeField()
203
200
  note = models.ForeignKey("v1.Note", on_delete=models.DO_NOTHING, related_name="state_history")
204
201
  originator = models.ForeignKey("v1.CanvasUser", on_delete=models.DO_NOTHING, null=True)
205
202
  state = models.CharField(choices=NoteStates.choices, max_length=3)
@@ -217,7 +214,9 @@ class CurrentNoteStateEvent(IdentifiableModel):
217
214
  db_table = "canvas_sdk_data_current_note_state_001"
218
215
 
219
216
  state = models.CharField(choices=NoteStates.choices, max_length=3)
220
- note = models.ForeignKey("v1.Note", on_delete=models.DO_NOTHING, related_name="current_state")
217
+ note = models.OneToOneField(
218
+ "v1.Note", on_delete=models.DO_NOTHING, related_name="current_state"
219
+ )
221
220
 
222
221
  def editable(self) -> bool:
223
222
  """Returns a boolean to indicate if the related note can be edited."""