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
@@ -0,0 +1,192 @@
1
+ from typing import Any
2
+
3
+ import factory
4
+ from django.utils import timezone
5
+
6
+ from canvas_sdk.v1.data import (
7
+ LabOrder,
8
+ LabOrderReason,
9
+ LabOrderReasonCondition,
10
+ LabPartner,
11
+ LabPartnerTest,
12
+ LabReport,
13
+ LabReview,
14
+ LabTest,
15
+ LabValue,
16
+ LabValueCoding,
17
+ )
18
+ from canvas_sdk.v1.data.common import (
19
+ DocumentReviewMode,
20
+ ReviewPatientCommunicationMethod,
21
+ ReviewStatus,
22
+ )
23
+ from canvas_sdk.v1.data.lab import TransmissionType
24
+
25
+
26
+ class LabReportFactory(factory.django.DjangoModelFactory[LabReport]):
27
+ """Factory for creating a LabReport."""
28
+
29
+ class Meta:
30
+ model = LabReport
31
+
32
+ review_mode = DocumentReviewMode.REVIEW_REQUIRED
33
+ junked = False
34
+ requires_signature = False
35
+ assigned_date = factory.LazyFunction(lambda: timezone.now())
36
+ patient = factory.SubFactory("canvas_sdk.test_utils.factories.PatientFactory")
37
+ transmission_type = TransmissionType.HL7
38
+ for_test_only = False
39
+ external_id = factory.Faker("uuid4")
40
+ version = 1
41
+ requisition_number = factory.Faker("bothify", text="REQ-########")
42
+ review = None # Optional field
43
+ original_date = factory.LazyFunction(lambda: timezone.now())
44
+ date_performed = factory.LazyFunction(lambda: timezone.now())
45
+ custom_document_name = factory.Faker("text", max_nb_chars=500)
46
+
47
+
48
+ class LabReviewFactory(factory.django.DjangoModelFactory[LabReview]):
49
+ """Factory for creating a LabReview."""
50
+
51
+ class Meta:
52
+ model = LabReview
53
+
54
+ internal_comment = factory.Faker("paragraph")
55
+ message_to_patient = factory.Faker("text", max_nb_chars=2048)
56
+ status = ReviewStatus.STATUS_REVIEWING
57
+ patient = factory.SubFactory("canvas_sdk.test_utils.factories.PatientFactory")
58
+ patient_communication_method = ReviewPatientCommunicationMethod.DELEGATED_CALL_CAN_LEAVE_MESSAGE
59
+
60
+
61
+ class LabValueFactory(factory.django.DjangoModelFactory[LabValue]):
62
+ """Factory for creating a LabValue."""
63
+
64
+ class Meta:
65
+ model = LabValue
66
+
67
+ report = factory.SubFactory(LabReportFactory)
68
+ value = factory.Faker("bothify", text="##.#")
69
+ units = factory.Faker("random_element", elements=["mg/dL", "mmol/L", "g/dL", "%", "U/L"])
70
+ abnormal_flag = factory.Faker("random_element", elements=["", "H", "L", "HH", "LL"])
71
+ reference_range = factory.Faker("bothify", text="#.#-##.#")
72
+ low_threshold = factory.Faker("bothify", text="#.#")
73
+ high_threshold = factory.Faker("bothify", text="##.#")
74
+ comment = factory.Faker("sentence")
75
+ observation_status = factory.Faker(
76
+ "random_element", elements=["final", "preliminary", "corrected"]
77
+ )
78
+
79
+
80
+ class LabValueCodingFactory(factory.django.DjangoModelFactory[LabValueCoding]):
81
+ """Factory for creating a LabValueCoding."""
82
+
83
+ class Meta:
84
+ model = LabValueCoding
85
+
86
+ value = factory.SubFactory(LabValueFactory)
87
+ code = factory.Faker("bothify", text="#####-#")
88
+ name = factory.Faker("text", max_nb_chars=256)
89
+ system = factory.Faker("random_element", elements=["LOINC", "SNOMED", "CPT"])
90
+
91
+
92
+ class LabOrderFactory(factory.django.DjangoModelFactory[LabOrder]):
93
+ """Factory for creating a LabOrder."""
94
+
95
+ class Meta:
96
+ model = LabOrder
97
+ skip_postgeneration_save = True
98
+
99
+ patient = factory.SubFactory("canvas_sdk.test_utils.factories.PatientFactory")
100
+ ontology_lab_partner = factory.Faker("company")
101
+ note = factory.SubFactory("canvas_sdk.test_utils.factories.NoteFactory")
102
+ comment = factory.Faker("text", max_nb_chars=128)
103
+ requisition_number = factory.Faker("bothify", text="REQ-########")
104
+ is_patient_bill = False
105
+ date_ordered = factory.LazyFunction(lambda: timezone.now())
106
+ fasting_status = None # Optional field
107
+ specimen_collection_type = LabOrder.SpecimenCollectionType.ON_LOCATION
108
+ transmission_type = TransmissionType.HL7
109
+ courtesy_copy_type = None # Optional field
110
+ courtesy_copy_number = ""
111
+ courtesy_copy_text = ""
112
+ ordering_provider = factory.SubFactory("canvas_sdk.test_utils.factories.StaffFactory")
113
+ parent_order = None # Optional field
114
+ healthgorilla_id = ""
115
+ manual_processing_status = None # Optional field
116
+ manual_processing_comment = None # Optional field
117
+ labcorp_abn_url = ""
118
+
119
+ @factory.post_generation
120
+ def reports(self, create: Any, extracted: Any, **kwargs: Any) -> None:
121
+ """Handle many-to-many relationship for reports."""
122
+ if not create:
123
+ return
124
+
125
+ if extracted:
126
+ for report in extracted:
127
+ self.reports.add(report)
128
+
129
+
130
+ class LabOrderReasonFactory(factory.django.DjangoModelFactory[LabOrderReason]):
131
+ """Factory for creating a LabOrderReason."""
132
+
133
+ class Meta:
134
+ model = LabOrderReason
135
+
136
+ order = factory.SubFactory(LabOrderFactory)
137
+ mode = LabOrderReason.LabReasonMode.MONITOR
138
+
139
+
140
+ class LabOrderReasonConditionFactory(factory.django.DjangoModelFactory[LabOrderReasonCondition]):
141
+ """Factory for creating a LabOrderReasonCondition."""
142
+
143
+ class Meta:
144
+ model = LabOrderReasonCondition
145
+
146
+ reason = factory.SubFactory(LabOrderReasonFactory)
147
+ condition = None # Optional field - would need a ConditionFactory
148
+
149
+
150
+ class LabTestFactory(factory.django.DjangoModelFactory[LabTest]):
151
+ """Factory for creating a LabTest."""
152
+
153
+ class Meta:
154
+ model = LabTest
155
+
156
+ ontology_test_name = factory.Faker("text", max_nb_chars=512)
157
+ ontology_test_code = factory.Faker("bothify", text="####-#")
158
+ status = LabTest.LabTestOrderStatus.NEW
159
+ report = factory.SubFactory(LabReportFactory)
160
+ aoe_code = ""
161
+ procedure_class = ""
162
+ specimen_type = factory.Faker("random_element", elements=["blood", "urine", "serum", "plasma"])
163
+ specimen_source_code = factory.Faker("bothify", text="###")
164
+ specimen_source_description = factory.Faker("text", max_nb_chars=255)
165
+ specimen_source_coding_system = factory.Faker("random_element", elements=["LOINC", "SNOMED"])
166
+ order = factory.SubFactory(LabOrderFactory)
167
+
168
+
169
+ class LabPartnerFactory(factory.django.DjangoModelFactory[LabPartner]):
170
+ """Factory for creating a LabPartner."""
171
+
172
+ class Meta:
173
+ model = LabPartner
174
+
175
+ name = factory.Faker("company")
176
+ active = True
177
+ electronic_ordering_enabled = True
178
+ keywords = factory.Faker("words", nb=5)
179
+ default_lab_account_number = factory.Faker("bothify", text="LAB-######")
180
+
181
+
182
+ class LabPartnerTestFactory(factory.django.DjangoModelFactory[LabPartnerTest]):
183
+ """Factory for creating a LabPartnerTest."""
184
+
185
+ class Meta:
186
+ model = LabPartnerTest
187
+
188
+ lab_partner = factory.SubFactory(LabPartnerFactory)
189
+ order_code = factory.Faker("bothify", text="####")
190
+ order_name = factory.Faker("text", max_nb_chars=256)
191
+ keywords = factory.Faker("words", nb=5)
192
+ cpt_code = factory.Faker("bothify", text="#####")
@@ -0,0 +1,75 @@
1
+ import datetime
2
+
3
+ import factory
4
+ from django.utils import timezone
5
+ from factory.fuzzy import FuzzyDate, FuzzyDateTime
6
+
7
+ from canvas_sdk.test_utils.factories.patient import PatientFactory
8
+ from canvas_sdk.v1.data.medication_history import (
9
+ MedicationHistoryMedication,
10
+ MedicationHistoryMedicationCoding,
11
+ MedicationHistoryResponse,
12
+ MedicationHistoryResponseStatus,
13
+ )
14
+
15
+
16
+ class MedicationHistoryMedicationFactory(
17
+ factory.django.DjangoModelFactory[MedicationHistoryMedication]
18
+ ):
19
+ """Factory for creating a MedicationHistoryMedication."""
20
+
21
+ class Meta:
22
+ model = MedicationHistoryMedication
23
+
24
+ patient = factory.SubFactory(PatientFactory)
25
+ last_fill_date = FuzzyDateTime(
26
+ start_dt=timezone.now() - datetime.timedelta(days=365), end_dt=timezone.now()
27
+ )
28
+
29
+ drug_description = factory.Faker("word")
30
+ strength_value = "10"
31
+ strength_form = "tablet"
32
+ strength_unit_of_measure = "mg"
33
+ quantity = 30.0
34
+ quantity_unit_of_measure = "tablets"
35
+ days_supply = 30
36
+ sig = factory.Faker("sentence", nb_words=4)
37
+
38
+
39
+ class MedicationHistoryMedicationCodingFactory(
40
+ factory.django.DjangoModelFactory[MedicationHistoryMedicationCoding]
41
+ ):
42
+ """Factory for creating a MedicationHistoryMedicationCoding."""
43
+
44
+ class Meta:
45
+ model = MedicationHistoryMedicationCoding
46
+
47
+ medication = factory.SubFactory(MedicationHistoryMedicationFactory)
48
+
49
+ system = "http://www.nlm.nih.gov/research/umls/rxnorm"
50
+ version = "1.0"
51
+ code = factory.Faker("numerify", text="######")
52
+ display = factory.Faker("word")
53
+ user_selected = False
54
+
55
+
56
+ class MedicationHistoryResponseFactory(
57
+ factory.django.DjangoModelFactory[MedicationHistoryResponse]
58
+ ):
59
+ """Factory for creating a MedicationHistoryResponse."""
60
+
61
+ class Meta:
62
+ model = MedicationHistoryResponse
63
+
64
+ patient = factory.SubFactory(PatientFactory)
65
+ status = MedicationHistoryResponseStatus.STATUS_APPROVED
66
+ start_date = FuzzyDate(
67
+ start_date=datetime.date.today() - datetime.timedelta(days=365),
68
+ end_date=datetime.date.today(),
69
+ )
70
+ end_date = FuzzyDate(
71
+ start_date=datetime.date.today(),
72
+ end_date=datetime.date.today() + datetime.timedelta(days=365),
73
+ )
74
+ message_id = factory.Faker("uuid4")
75
+ related_to_message_id = factory.Faker("uuid4")
@@ -0,0 +1,52 @@
1
+ from typing import Any
2
+
3
+ import factory
4
+
5
+ from canvas_sdk.v1.data import Note, NoteStateChangeEvent, NoteType
6
+ from canvas_sdk.v1.data.note import NoteStates
7
+
8
+
9
+ class NoteFactory(factory.django.DjangoModelFactory[Note]):
10
+ """Factory for creating Note."""
11
+
12
+ class Meta:
13
+ model = Note
14
+
15
+ location = factory.SubFactory("canvas_sdk.test_utils.factories.PracticeLocationFactory")
16
+ originator = factory.SelfAttribute("provider.user")
17
+ provider = factory.SubFactory("canvas_sdk.test_utils.factories.StaffFactory")
18
+ patient = factory.SubFactory("canvas_sdk.test_utils.factories.PatientFactory")
19
+ note_type_version = factory.SubFactory("canvas_sdk.test_utils.factories.NoteTypeFactory")
20
+
21
+ @factory.post_generation
22
+ def create_initial_state_change_event(self, create: Any, extracted: Any, **kwargs: Any) -> None:
23
+ """Create an initial NoteStateChangeEvent when a Note is created."""
24
+ if not create:
25
+ return
26
+
27
+ NoteStateChangeEventFactory.create(note=self, state=NoteStates.NEW)
28
+
29
+
30
+ class NoteStateChangeEventFactory(factory.django.DjangoModelFactory[NoteStateChangeEvent]):
31
+ """Factory for creating NoteStateChangeEvent."""
32
+
33
+ class Meta:
34
+ model = NoteStateChangeEvent
35
+
36
+ note = factory.SubFactory(NoteFactory)
37
+ state = NoteStates.NEW
38
+ originator = factory.SelfAttribute("note.originator")
39
+
40
+
41
+ class NoteTypeFactory(factory.django.DjangoModelFactory[NoteType]):
42
+ """Factory for creating NoteType."""
43
+
44
+ class Meta:
45
+ model = NoteType
46
+
47
+ available_places_of_service = ["01"]
48
+ name = factory.Faker("sentence", nb_words=1)
49
+ code = factory.Faker("sentence", nb_words=1)
50
+ system = factory.Faker("sentence", nb_words=1)
51
+ icon = factory.Faker("sentence", nb_words=1)
52
+ display = factory.Faker("sentence", nb_words=1)
@@ -0,0 +1,50 @@
1
+ import factory
2
+
3
+ from canvas_sdk.v1.data import Organization, OrganizationAddress, OrganizationContactPoint
4
+ from canvas_sdk.v1.data.common import ContactPointSystem, ContactPointUse
5
+
6
+
7
+ class OrganizationFactory(factory.django.DjangoModelFactory[Organization]):
8
+ """Factory for creating Organization."""
9
+
10
+ class Meta:
11
+ model = Organization
12
+
13
+ short_name = "Canvas Medical"
14
+ full_name = "Canvas Medical, Inc."
15
+ logo_url = "https://s3-us-west-2.amazonaws.com/canvas-pcp-assets/canvas_logo_large.png"
16
+ background_image_url = "https://s3-us-west-2.amazonaws.com/canvas-pcp-assets/santa-cruz-low.jpg"
17
+ background_gradient = (
18
+ "linear-gradient(to top, rgb(231, 201, 154) 0%, rgb(220, 210, 192) 29%, "
19
+ "rgb(156, 175, 191) 90%, rgb(147, 166, 189) 100%)"
20
+ )
21
+ tax_id = "123456"
22
+
23
+
24
+ class OrganizationAddressFactory(factory.django.DjangoModelFactory[OrganizationAddress]):
25
+ """Factory for creating OrganizationAddress."""
26
+
27
+ class Meta:
28
+ model = OrganizationAddress
29
+
30
+ organization = factory.SubFactory(OrganizationFactory)
31
+ line1 = "456 Organization Ave"
32
+ line2 = "#2"
33
+ city = "San Francisco"
34
+ district = "Sunset"
35
+ state_code = "CA"
36
+ postal_code = "94112"
37
+ country = "USA"
38
+
39
+
40
+ class OrganizationContactPointFactory(factory.django.DjangoModelFactory[OrganizationContactPoint]):
41
+ """Factory for creating OrganizationContactPoint."""
42
+
43
+ class Meta:
44
+ model = OrganizationContactPoint
45
+
46
+ organization = factory.SubFactory(OrganizationFactory)
47
+ system = ContactPointSystem.PHONE
48
+ value = "8003701416"
49
+ use = ContactPointUse.WORK
50
+ rank = 1
@@ -0,0 +1,88 @@
1
+ from datetime import date
2
+
3
+ import factory
4
+
5
+ from canvas_sdk.v1.data import (
6
+ PracticeLocation,
7
+ PracticeLocationAddress,
8
+ PracticeLocationContactPoint,
9
+ PracticeLocationSetting,
10
+ )
11
+ from canvas_sdk.v1.data.common import (
12
+ AddressState,
13
+ AddressType,
14
+ AddressUse,
15
+ ContactPointSystem,
16
+ ContactPointUse,
17
+ )
18
+
19
+
20
+ class PracticeLocationSettingFactory(factory.django.DjangoModelFactory[PracticeLocationSetting]):
21
+ """Factory for PracticeLocationSetting."""
22
+
23
+ class Meta:
24
+ model = PracticeLocationSetting
25
+ django_get_or_create = ("name",)
26
+
27
+ name = factory.Sequence(lambda n: f"location_setting_{n}")
28
+ value = {"random": "json"}
29
+
30
+
31
+ class PracticeLocationFactory(factory.django.DjangoModelFactory[PracticeLocation]):
32
+ """Factory for PracticeLocation."""
33
+
34
+ class Meta:
35
+ model = PracticeLocation
36
+
37
+ organization = factory.SubFactory(
38
+ "canvas_sdk.test_utils.factories.organization.OrganizationFactory"
39
+ )
40
+ short_name = "Family Doctors of SF"
41
+ full_name = "Family Doctors of San Francisco"
42
+ setting = factory.RelatedFactory(PracticeLocationSettingFactory, "practice_location")
43
+ bill_through_organization = True
44
+ billing_location_name = "Billing Location Name"
45
+ tax_id = "123456789"
46
+ tax_id_type = "E"
47
+ npi_number = "1234567890"
48
+ group_npi_number = "112233445"
49
+
50
+
51
+ class PracticeLocationAddressFactory(factory.django.DjangoModelFactory[PracticeLocationAddress]):
52
+ """Factory for PracticeLocationAddress."""
53
+
54
+ class Meta:
55
+ model = PracticeLocationAddress
56
+
57
+ practice_location = factory.SubFactory(
58
+ "canvas_sdk.test_utils.factories.PracticeLocationFactory"
59
+ )
60
+ line1 = "1234 Golden Gate Ave."
61
+ line2 = "Suite 456"
62
+ city = "San Francisco"
63
+ district = ""
64
+ state_code = "CA"
65
+ postal_code = "94100"
66
+ use = AddressUse.WORK
67
+ type = AddressType.BOTH
68
+ longitude = -122.476944
69
+ latitude = 37.769722
70
+ start = date(year=2015, month=10, day=10)
71
+ end = None
72
+ country = "USA"
73
+ state = AddressState.ACTIVE
74
+
75
+
76
+ class PracticeLocationContactPointFactory(
77
+ factory.django.DjangoModelFactory[PracticeLocationContactPoint]
78
+ ):
79
+ """Factory for creating PracticeLocationContactPoint."""
80
+
81
+ class Meta:
82
+ model = PracticeLocationContactPoint
83
+
84
+ practice_location = factory.SubFactory(PracticeLocationFactory)
85
+ system = ContactPointSystem.PHONE
86
+ value = "8003701416"
87
+ use = ContactPointUse.WORK
88
+ rank = 1
@@ -0,0 +1,81 @@
1
+ import datetime
2
+ import json
3
+ from typing import Any
4
+
5
+ import factory
6
+ from django.utils import timezone
7
+ from factory.fuzzy import FuzzyDate
8
+
9
+ from canvas_sdk.v1.data import Referral, ReferralReport, ReferralReview
10
+
11
+
12
+ class ReferralFactory(factory.django.DjangoModelFactory[Referral]):
13
+ """Factory for creating a Referral."""
14
+
15
+ class Meta:
16
+ model = Referral
17
+
18
+ patient = factory.SubFactory("canvas_sdk.test_utils.factories.PatientFactory")
19
+ note = factory.SubFactory("canvas_sdk.test_utils.factories.NoteFactory")
20
+ service_provider = None # Optional field
21
+ clinical_question = factory.Faker("text", max_nb_chars=50)
22
+ priority = factory.Faker("random_element", elements=["routine", "urgent", "stat"])
23
+ include_visit_note = False
24
+ notes = factory.Faker("paragraph")
25
+ date_referred = factory.LazyFunction(lambda: timezone.now())
26
+ forwarded = False
27
+ internal_comment = factory.Faker("paragraph")
28
+ internal_task_comment = None # Optional field
29
+ ignored = False
30
+ task_ids = factory.LazyFunction(lambda: json.dumps([]))
31
+
32
+ @factory.post_generation
33
+ def assessments(self, create: Any, extracted: Any, **kwargs: Any) -> None:
34
+ """Handle many-to-many relationship for assessments."""
35
+ if not create:
36
+ return
37
+
38
+ if extracted:
39
+ for assessment in extracted:
40
+ self.assessments.add(assessment)
41
+
42
+
43
+ class ReferralReviewFactory(factory.django.DjangoModelFactory[ReferralReview]):
44
+ """Factory for creating a ReferralReview."""
45
+
46
+ class Meta:
47
+ model = ReferralReview
48
+
49
+ internal_comment = factory.Faker("paragraph")
50
+ message_to_patient = factory.Faker("sentence", nb_words=20)
51
+ status = factory.Faker("random_element", elements=["pending", "reviewed", "completed"])
52
+ patient = factory.SubFactory("canvas_sdk.test_utils.factories.PatientFactory")
53
+ patient_communication_method = factory.Faker(
54
+ "random_element", elements=["email", "phone", "portal", "mail"]
55
+ )
56
+
57
+
58
+ class ReferralReportFactory(factory.django.DjangoModelFactory[ReferralReport]):
59
+ """Factory for creating a ReferralReport."""
60
+
61
+ class Meta:
62
+ model = ReferralReport
63
+
64
+ originator = factory.SubFactory("canvas_sdk.test_utils.factories.CanvasUserFactory")
65
+ review_mode = factory.Faker("random_element", elements=["IN", "OT"])
66
+ assigned_by = factory.SubFactory("canvas_sdk.test_utils.factories.CanvasUserFactory")
67
+ junked = False
68
+ requires_signature = factory.Faker("boolean")
69
+ assigned_date = factory.LazyFunction(lambda: timezone.now())
70
+ team_assigned_date = None
71
+ team = None
72
+ patient = factory.SubFactory("canvas_sdk.test_utils.factories.PatientFactory")
73
+ referral = factory.SubFactory(ReferralFactory)
74
+ specialty = factory.Faker("job")
75
+ review = None
76
+ original_date = FuzzyDate(
77
+ start_date=datetime.date.today() - datetime.timedelta(days=365),
78
+ end_date=datetime.date.today(),
79
+ )
80
+ comment = factory.Faker("paragraph")
81
+ priority = False
@@ -0,0 +1,111 @@
1
+ import datetime
2
+
3
+ import factory
4
+ from dateutil.relativedelta import relativedelta
5
+
6
+ from canvas_sdk.v1.data import (
7
+ Staff,
8
+ StaffAddress,
9
+ StaffContactPoint,
10
+ StaffLicense,
11
+ StaffPhoto,
12
+ StaffRole,
13
+ )
14
+ from canvas_sdk.v1.data.common import ContactPointSystem, ContactPointUse
15
+
16
+
17
+ class StaffAddressFactory(factory.django.DjangoModelFactory[StaffAddress]):
18
+ """Factory for creating StaffAddress."""
19
+
20
+ class Meta:
21
+ model = StaffAddress
22
+
23
+ line1 = "1234 Main Street"
24
+ line2 = "Apt 3"
25
+ city = "San Francisco"
26
+ district = "Sunset"
27
+ state_code = "CA"
28
+ postal_code = "94112"
29
+ country = "USA"
30
+ staff = factory.SubFactory("canvas_sdk.test_utils.factories.StaffFactory")
31
+
32
+
33
+ class StaffPhotoFactory(factory.django.DjangoModelFactory[StaffPhoto]):
34
+ """Factory for creating StaffPhoto."""
35
+
36
+ class Meta:
37
+ model = StaffPhoto
38
+
39
+ url = ""
40
+ staff = factory.SubFactory("canvas_sdk.test_utils.factories.StaffFactory")
41
+
42
+
43
+ class StaffRoleFactory(factory.django.DjangoModelFactory[StaffRole]):
44
+ """Factory for creating StaffRole."""
45
+
46
+ class Meta:
47
+ model = StaffRole
48
+ django_get_or_create = ("internal_code", "staff")
49
+
50
+ internal_code = "MD"
51
+ name = "Physician"
52
+ public_abbreviation = "MD"
53
+ domain = StaffRole.RoleDomain.CLINICAL
54
+ domain_privilege_level = 100000
55
+ permissions = factory.LazyFunction(lambda: {})
56
+ staff = factory.SubFactory("canvas_sdk.test_utils.factories.StaffFactory")
57
+
58
+
59
+ class StaffLicenseFactory(factory.django.DjangoModelFactory[StaffLicense]):
60
+ """Factory for creating StaffLicense."""
61
+
62
+ class Meta:
63
+ model = StaffLicense
64
+
65
+ issuing_authority_long_name = "MEDICAL BOARD OF CALIFORNIA"
66
+ issuing_authority_url = "http://www.mbc.ca.gov/"
67
+ license_or_certification_identifier = "A60695"
68
+ issuance_date = factory.LazyFunction(datetime.date.today)
69
+ expiration_date = factory.LazyFunction(lambda: datetime.date.today() + relativedelta(years=2))
70
+ staff = factory.SubFactory("canvas_sdk.test_utils.factories.StaffFactory")
71
+
72
+
73
+ class StaffContactPointFactory(factory.django.DjangoModelFactory[StaffContactPoint]):
74
+ """Factory for creating StaffContactPoint."""
75
+
76
+ class Meta:
77
+ model = StaffContactPoint
78
+
79
+ value = "8883331212"
80
+ system = ContactPointSystem.PHONE
81
+ use = ContactPointUse.HOME
82
+ staff = factory.SubFactory("canvas_sdk.test_utils.factories.StaffFactory")
83
+
84
+
85
+ class StaffFactory(factory.django.DjangoModelFactory[Staff]):
86
+ """Factory for creating Staff."""
87
+
88
+ class Meta:
89
+ model = Staff
90
+ django_get_or_create = ("user",)
91
+
92
+ first_name = factory.Faker("first_name")
93
+ middle_name = factory.Faker("first_name")
94
+ last_name = factory.Faker("last_name")
95
+ npi_number = "1111155556"
96
+ group_npi_number = "123456789"
97
+ tax_id = "98711111"
98
+ spi_number = 5630156655001
99
+ address = factory.RelatedFactory(StaffAddressFactory, "staff")
100
+ telecom = factory.RelatedFactory(StaffContactPointFactory, "staff")
101
+ primary_practice_location = factory.SubFactory(
102
+ "canvas_sdk.test_utils.factories.PracticeLocationFactory"
103
+ )
104
+ photos = factory.RelatedFactory(StaffPhotoFactory, "staff")
105
+ role = factory.RelatedFactory(StaffRoleFactory, "staff")
106
+ license = factory.RelatedFactory(StaffLicenseFactory, "staff")
107
+ birth_date = factory.Faker("date_object")
108
+
109
+ user = factory.SubFactory(
110
+ "canvas_sdk.test_utils.factories.user.CanvasUserFactory",
111
+ )