canvas 0.48.0__py3-none-any.whl → 0.50.0__py3-none-any.whl

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

Potentially problematic release.


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

@@ -17,6 +17,7 @@ class _BaseCommand(TrackableFieldsModel):
17
17
  key = ""
18
18
  originate_required_fields = ("note_uuid",)
19
19
  edit_required_fields = ("command_uuid",)
20
+ send_required_fields = ("command_uuid",)
20
21
  delete_required_fields = ("command_uuid",)
21
22
  commit_required_fields = ("command_uuid",)
22
23
  enter_in_error_required_fields = ("command_uuid",)
@@ -161,4 +162,14 @@ class _BaseCommand(TrackableFieldsModel):
161
162
  return Recommendation(title=title, button=button, command=command, context=self.values)
162
163
 
163
164
 
164
- __exports__ = ("_BaseCommand",)
165
+ class _SendableCommandMixin:
166
+ def send(self) -> Effect:
167
+ """Fire the send effect the command."""
168
+ self._validate_before_effect("send") # type: ignore[attr-defined]
169
+ return Effect(
170
+ type=f"SEND_{self.constantized_key()}_COMMAND", # type: ignore[attr-defined]
171
+ payload=json.dumps({"command": self.command_uuid}), # type: ignore[attr-defined]
172
+ )
173
+
174
+
175
+ __exports__ = ("_BaseCommand", "_SendableCommandMixin")
@@ -6,10 +6,11 @@ from pydantic import Field
6
6
  from pydantic_core import InitErrorDetails
7
7
 
8
8
  from canvas_sdk.commands.base import _BaseCommand as BaseCommand
9
+ from canvas_sdk.commands.base import _SendableCommandMixin
9
10
  from canvas_sdk.v1.data.lab import LabPartner, LabPartnerTest
10
11
 
11
12
 
12
- class LabOrderCommand(BaseCommand):
13
+ class LabOrderCommand(_SendableCommandMixin, BaseCommand):
13
14
  """A class for managing a Lab Order command within a specific note."""
14
15
 
15
16
  class Meta:
@@ -29,7 +30,7 @@ class LabOrderCommand(BaseCommand):
29
30
  comment: str | None = None
30
31
 
31
32
  def _get_error_details(
32
- self, method: Literal["originate", "edit", "delete", "commit", "enter_in_error"]
33
+ self, method: Literal["originate", "edit", "delete", "commit", "enter_in_error", "send"]
33
34
  ) -> list[InitErrorDetails]:
34
35
  errors = super()._get_error_details(method)
35
36
 
@@ -43,7 +44,11 @@ class LabOrderCommand(BaseCommand):
43
44
  else:
44
45
  query["id"] = self.lab_partner
45
46
 
46
- lab_partner_obj = LabPartner.objects.filter(**query).values("id", "dbid").first()
47
+ lab_partner_obj = (
48
+ LabPartner.objects.filter(**query)
49
+ .values("id", "dbid", "electronic_ordering_enabled")
50
+ .first()
51
+ )
47
52
 
48
53
  if not lab_partner_obj:
49
54
  errors.append(
@@ -1,13 +1,43 @@
1
+ import json
2
+ from dataclasses import dataclass
1
3
  from decimal import Decimal
2
4
  from enum import Enum
5
+ from typing import Any
3
6
 
4
7
  from pydantic import Field, conlist
8
+ from pydantic_core import InitErrorDetails
5
9
 
6
- from canvas_sdk.commands.base import _BaseCommand
10
+ from canvas_sdk.commands.base import _BaseCommand, _SendableCommandMixin
7
11
  from canvas_sdk.commands.constants import ClinicalQuantity
12
+ from canvas_sdk.effects import Effect
13
+ from canvas_sdk.effects.compound_medications.compound_medication import (
14
+ CompoundMedication as CompoundMedicationEffect,
15
+ )
16
+ from canvas_sdk.v1.data.compound_medication import CompoundMedication as CompoundMedicationModel
17
+
18
+
19
+ @dataclass
20
+ class CompoundMedicationData:
21
+ """Data for creating a compound medication inline within a prescription."""
22
+
23
+ formulation: str
24
+ potency_unit_code: str
25
+ controlled_substance: str
26
+ controlled_substance_ndc: str = ""
27
+ active: bool = True
8
28
 
29
+ def to_dict(self) -> dict[str, Any]:
30
+ """Convert dataclass to dictionary, excluding None values."""
31
+ return {
32
+ "formulation": self.formulation,
33
+ "potency_unit_code": self.potency_unit_code,
34
+ "controlled_substance": self.controlled_substance,
35
+ "controlled_substance_ndc": self.controlled_substance_ndc,
36
+ "active": self.active,
37
+ }
9
38
 
10
- class PrescribeCommand(_BaseCommand):
39
+
40
+ class PrescribeCommand(_SendableCommandMixin, _BaseCommand):
11
41
  """A class for managing a Prescribe command within a specific note."""
12
42
 
13
43
  class Meta:
@@ -36,6 +66,86 @@ class PrescribeCommand(_BaseCommand):
36
66
  )
37
67
  note_to_pharmacist: str | None = None
38
68
 
69
+ # Compound medication fields
70
+ compound_medication_id: str | None = Field(
71
+ default=None, json_schema_extra={"commands_api_name": "compound_medication_id"}
72
+ )
73
+ compound_medication_data: CompoundMedicationData | None = Field(
74
+ default=None, json_schema_extra={"commands_api_name": "compound_medication_data"}
75
+ )
76
+
77
+ def _get_error_details(self, method: str) -> list[InitErrorDetails]:
78
+ """Add compound medication validation to the base validation."""
79
+ errors = super()._get_error_details(method)
80
+
81
+ # Validate that exactly one medication type is provided
82
+ has_fdb_code = self.fdb_code is not None and self.fdb_code.strip() != ""
83
+ has_compound_medication_id = (
84
+ self.compound_medication_id is not None and self.compound_medication_id.strip() != ""
85
+ )
86
+ has_compound_medication_data = self.compound_medication_data is not None
87
+
88
+ medication_types_provided = sum(
89
+ [has_fdb_code, has_compound_medication_id, has_compound_medication_data]
90
+ )
91
+
92
+ if medication_types_provided > 1:
93
+ errors.append(
94
+ self._create_error_detail(
95
+ "value",
96
+ "Cannot specify multiple medication types. Choose one of: 'fdb_code', 'compound_medication_id', or 'compound_medication_data'.",
97
+ None,
98
+ )
99
+ )
100
+
101
+ # Validate compound medication ID if provided
102
+ if (
103
+ self.compound_medication_id
104
+ and self.compound_medication_id.strip() != ""
105
+ and
106
+ # Check if compound medication exists
107
+ not CompoundMedicationModel.objects.filter(id=self.compound_medication_id).exists()
108
+ ):
109
+ errors.append(
110
+ self._create_error_detail(
111
+ "value",
112
+ f"Compound medication with ID {self.compound_medication_id} does not exist.",
113
+ self.compound_medication_id,
114
+ )
115
+ )
116
+
117
+ # Validate compound medication data if provided
118
+ if self.compound_medication_data is not None:
119
+ compound_med_errors = CompoundMedicationEffect.validate_compound_medication_fields(
120
+ formulation=self.compound_medication_data.formulation,
121
+ potency_unit_code=self.compound_medication_data.potency_unit_code,
122
+ controlled_substance=self.compound_medication_data.controlled_substance,
123
+ controlled_substance_ndc=self.compound_medication_data.controlled_substance_ndc,
124
+ )
125
+ errors.extend(compound_med_errors)
126
+
127
+ return errors
128
+
129
+ def _process_compound_medication_fields(self, data: dict[str, Any]) -> dict[str, Any]:
130
+ """
131
+ Process compound medication fields in prescription data.
132
+
133
+ Args:
134
+ data: Dictionary containing prescription data
135
+
136
+ Returns:
137
+ Processed dictionary with compound medication transformations applied
138
+ """
139
+ # Process nested compound medication values if present
140
+ if "compound_medication_values" in data:
141
+ compound_med_data = data["compound_medication_values"]
142
+ processed_compound_data = CompoundMedicationEffect.process_compound_medication_data(
143
+ compound_med_data
144
+ )
145
+ data["compound_medication_values"] = processed_compound_data
146
+
147
+ return data
148
+
39
149
  @property
40
150
  def values(self) -> dict:
41
151
  """The Prescribe command's field values."""
@@ -46,11 +156,64 @@ class PrescribeCommand(_BaseCommand):
46
156
  str(Decimal(self.quantity_to_dispense)) if self.quantity_to_dispense else None
47
157
  )
48
158
 
159
+ values["compound_medication_values"] = {}
160
+
161
+ if self.is_dirty("compound_medication_id") and self.compound_medication_id:
162
+ values["compound_medication_values"]["id"] = values.pop("compound_medication_id")
163
+
164
+ # Handle compound medication data
165
+ elif (
166
+ "compound_medication_data" in values and values["compound_medication_data"] is not None
167
+ ):
168
+ # Convert CompoundMedicationData to the expected nested structure
169
+ compound_data = values.pop("compound_medication_data")
170
+ if isinstance(compound_data, CompoundMedicationData):
171
+ values["compound_medication_values"] = compound_data.to_dict()
172
+
49
173
  return values
50
174
 
175
+ def originate(self, line_number: int = -1) -> Effect:
176
+ """Originate a new command in the note body with explicit compound medication processing."""
177
+ self._validate_before_effect("originate")
178
+
179
+ # Get raw values and apply explicit processing for compound medications
180
+ raw_data = self.values
181
+ processed_data = self._process_compound_medication_fields(raw_data)
182
+
183
+ return Effect(
184
+ type=f"ORIGINATE_{self.constantized_key()}_COMMAND",
185
+ payload=json.dumps(
186
+ {
187
+ "command": self.command_uuid,
188
+ "note": self.note_uuid,
189
+ "data": processed_data,
190
+ "line_number": line_number,
191
+ }
192
+ ),
193
+ )
194
+
195
+ def edit(self) -> Effect:
196
+ """Edit the command with explicit compound medication processing."""
197
+ self._validate_before_effect("edit")
198
+
199
+ # Get raw values and apply explicit processing for compound medications
200
+ raw_data = self.values
201
+ processed_data = self._process_compound_medication_fields(raw_data)
202
+
203
+ return Effect(
204
+ type=f"EDIT_{self.constantized_key()}_COMMAND",
205
+ payload=json.dumps(
206
+ {
207
+ "command": self.command_uuid,
208
+ "data": processed_data,
209
+ }
210
+ ),
211
+ )
212
+
51
213
 
52
214
  __exports__ = (
53
215
  "PrescribeCommand",
216
+ "CompoundMedicationData",
54
217
  # Not defined here but used in a current plugin
55
218
  "ClinicalQuantity",
56
219
  "Decimal",
@@ -0,0 +1,3 @@
1
+ from canvas_sdk.effects.compound_medications.compound_medication import CompoundMedication
2
+
3
+ __all__ = __exports__ = ("CompoundMedication",)
@@ -0,0 +1,275 @@
1
+ import json
2
+ from typing import Any
3
+
4
+ from pydantic_core import InitErrorDetails, PydanticCustomError
5
+
6
+ from canvas_generated.messages.effects_pb2 import Effect
7
+ from canvas_sdk.base import TrackableFieldsModel
8
+ from canvas_sdk.v1.data.compound_medication import CompoundMedication as CompoundMedicationModel
9
+
10
+
11
+ class CompoundMedication(TrackableFieldsModel):
12
+ """Effect to create or update a Compound Medication record."""
13
+
14
+ class Meta:
15
+ effect_type = "COMPOUND_MEDICATION"
16
+
17
+ instance_id: str | None = None
18
+ formulation: str | None = None
19
+ potency_unit_code: str | None = None
20
+ controlled_substance: str | None = None
21
+ controlled_substance_ndc: str | None = None
22
+ active: bool | None = None
23
+
24
+ @property
25
+ def values(self) -> dict[str, Any]:
26
+ """Return the values of the compound medication as a dictionary, only including dirty (modified) fields."""
27
+ return super().values
28
+
29
+ @staticmethod
30
+ def process_formulation(formulation: str | None) -> str | None:
31
+ """
32
+ Process compound medication formulation by stripping whitespace.
33
+
34
+ Args:
35
+ formulation: The formulation string to process
36
+
37
+ Returns:
38
+ Processed formulation string, or None if input was None
39
+ """
40
+ if formulation is None:
41
+ return None
42
+ return formulation.strip()
43
+
44
+ @staticmethod
45
+ def process_ndc(ndc: str | None) -> str | None:
46
+ """
47
+ Process compound medication NDC by removing dashes.
48
+
49
+ Args:
50
+ ndc: The NDC string to process
51
+
52
+ Returns:
53
+ Processed NDC string with dashes removed, or None if input was None
54
+ """
55
+ if ndc is None:
56
+ return None
57
+ return ndc.replace("-", "")
58
+
59
+ @staticmethod
60
+ def process_compound_medication_data(data: dict[str, Any]) -> dict[str, Any]:
61
+ """
62
+ Process compound medication data by applying all necessary transformations.
63
+
64
+ Args:
65
+ data: Dictionary containing compound medication data
66
+
67
+ Returns:
68
+ Processed dictionary with transformations applied
69
+ """
70
+ processed_data = data.copy()
71
+
72
+ # Process formulation
73
+ if "formulation" in processed_data and processed_data["formulation"] is not None:
74
+ processed_data["formulation"] = CompoundMedication.process_formulation(
75
+ processed_data["formulation"]
76
+ )
77
+
78
+ # Process NDC
79
+ if (
80
+ "controlled_substance_ndc" in processed_data
81
+ and processed_data["controlled_substance_ndc"] is not None
82
+ ):
83
+ processed_data["controlled_substance_ndc"] = CompoundMedication.process_ndc(
84
+ processed_data["controlled_substance_ndc"]
85
+ )
86
+
87
+ return processed_data
88
+
89
+ @staticmethod
90
+ def validate_compound_medication_fields(
91
+ formulation: str | None,
92
+ potency_unit_code: str | None,
93
+ controlled_substance: str | None,
94
+ controlled_substance_ndc: str | None,
95
+ ) -> list[InitErrorDetails]:
96
+ """
97
+ Static method to validate compound medication fields.
98
+
99
+ Args:
100
+ formulation: The formulation value to validate
101
+ potency_unit_code: The potency unit code to validate
102
+ controlled_substance: The controlled substance to validate
103
+ controlled_substance_ndc: The NDC to validate
104
+
105
+ Returns:
106
+ List of InitErrorDetails for any validation errors
107
+ """
108
+
109
+ def create_error(error_type: str, message: str, value: Any) -> InitErrorDetails:
110
+ """Helper function to mimic _create_error_details."""
111
+ return InitErrorDetails(
112
+ {"type": PydanticCustomError(error_type, message), "input": value}
113
+ )
114
+
115
+ errors = []
116
+
117
+ # Formulation validation
118
+ if formulation is not None:
119
+ stripped_formulation = formulation.strip()
120
+ if not stripped_formulation:
121
+ errors.append(
122
+ create_error(
123
+ "value",
124
+ "Field 'formulation' cannot be empty.",
125
+ formulation,
126
+ )
127
+ )
128
+ elif len(stripped_formulation) > 105:
129
+ errors.append(
130
+ create_error(
131
+ "value",
132
+ "Field 'formulation' must be 105 characters or less.",
133
+ formulation,
134
+ )
135
+ )
136
+
137
+ # Potency unit code validation
138
+ if potency_unit_code and potency_unit_code not in [
139
+ choice[0] for choice in CompoundMedicationModel.PotencyUnits.choices
140
+ ]:
141
+ errors.append(
142
+ create_error(
143
+ "value",
144
+ f"Invalid potency unit code: {potency_unit_code}. Must be one of: {[choice[0] for choice in CompoundMedicationModel.PotencyUnits.choices]}",
145
+ potency_unit_code,
146
+ )
147
+ )
148
+
149
+ # Controlled substance validation
150
+ if controlled_substance and controlled_substance not in [
151
+ choice[0] for choice in CompoundMedicationModel.ControlledSubstanceOptions.choices
152
+ ]:
153
+ errors.append(
154
+ create_error(
155
+ "value",
156
+ f"Invalid controlled substance: {controlled_substance}. Must be one of: {[choice[0] for choice in CompoundMedicationModel.ControlledSubstanceOptions.choices]}",
157
+ controlled_substance,
158
+ )
159
+ )
160
+
161
+ # NDC validation - required when controlled substance is not "N" (Not Scheduled)
162
+ if (
163
+ controlled_substance
164
+ and controlled_substance
165
+ != CompoundMedicationModel.ControlledSubstanceOptions.SCHEDULE_NOT_SCHEDULED.value
166
+ and (not controlled_substance_ndc or not controlled_substance_ndc.strip())
167
+ ):
168
+ errors.append(
169
+ create_error(
170
+ "value",
171
+ "NDC is required when a Controlled Substance is specified.",
172
+ controlled_substance_ndc,
173
+ )
174
+ )
175
+
176
+ return errors
177
+
178
+ def _get_error_details(self, method: Any) -> list[InitErrorDetails]:
179
+ errors = super()._get_error_details(method)
180
+
181
+ if method == "create":
182
+ if not self.formulation:
183
+ errors.append(
184
+ self._create_error_detail(
185
+ "missing",
186
+ "Field 'formulation' is required to create a compound medication.",
187
+ None,
188
+ )
189
+ )
190
+
191
+ if not self.potency_unit_code:
192
+ errors.append(
193
+ self._create_error_detail(
194
+ "missing",
195
+ "Field 'potency_unit_code' is required to create a compound medication.",
196
+ None,
197
+ )
198
+ )
199
+
200
+ if not self.controlled_substance:
201
+ errors.append(
202
+ self._create_error_detail(
203
+ "missing",
204
+ "Field 'controlled_substance' is required to create a compound medication.",
205
+ None,
206
+ )
207
+ )
208
+
209
+ elif method == "update":
210
+ if not self.instance_id:
211
+ errors.append(
212
+ self._create_error_detail(
213
+ "missing",
214
+ "Field 'instance_id' is required to update a compound medication.",
215
+ None,
216
+ )
217
+ )
218
+
219
+ if (
220
+ self.instance_id
221
+ and not CompoundMedicationModel.objects.filter(id=self.instance_id).exists()
222
+ ):
223
+ errors.append(
224
+ self._create_error_detail(
225
+ "value",
226
+ f"Compound medication with ID {self.instance_id} does not exist.",
227
+ self.instance_id,
228
+ )
229
+ )
230
+
231
+ compound_med_errors = self.validate_compound_medication_fields(
232
+ formulation=self.formulation,
233
+ potency_unit_code=self.potency_unit_code,
234
+ controlled_substance=self.controlled_substance,
235
+ controlled_substance_ndc=self.controlled_substance_ndc,
236
+ )
237
+ errors.extend(compound_med_errors)
238
+
239
+ return errors
240
+
241
+ def create(self) -> Effect:
242
+ """Create a new Compound Medication."""
243
+ self._validate_before_effect("create")
244
+
245
+ # Get raw values and apply explicit processing
246
+ raw_data = self.values
247
+ processed_data = self.process_compound_medication_data(raw_data)
248
+
249
+ payload = {"data": processed_data}
250
+ if self.active is None:
251
+ payload["data"]["active"] = True
252
+
253
+ return Effect(
254
+ type=f"CREATE_{self.Meta.effect_type}",
255
+ payload=json.dumps(payload),
256
+ )
257
+
258
+ def update(self) -> Effect:
259
+ """Update an existing Compound Medication."""
260
+ self._validate_before_effect("update")
261
+
262
+ # Get raw values and apply explicit processing
263
+ raw_data = self.values
264
+ processed_data = self.process_compound_medication_data(raw_data)
265
+
266
+ payload = {"data": processed_data}
267
+ payload["data"]["instance_id"] = str(self.instance_id)
268
+
269
+ return Effect(
270
+ type=f"UPDATE_{self.Meta.effect_type}",
271
+ payload=json.dumps(payload),
272
+ )
273
+
274
+
275
+ __exports__ = ("CompoundMedication",)
@@ -9,6 +9,7 @@ from .charge_description_master import ChargeDescriptionMaster
9
9
  from .claim import Claim, ClaimCoverage, ClaimPatient, ClaimQueue, InstallmentPlan
10
10
  from .claim_line_item import ClaimLineItem
11
11
  from .command import Command
12
+ from .compound_medication import CompoundMedication
12
13
  from .condition import Condition, ConditionCoding
13
14
  from .coverage import Coverage, Transactor, TransactorAddress, TransactorPhone
14
15
  from .detected_issue import DetectedIssue, DetectedIssueEvidence
@@ -107,6 +108,7 @@ __all__ = __exports__ = (
107
108
  "ClaimPatient",
108
109
  "ClaimQueue",
109
110
  "Command",
111
+ "CompoundMedication",
110
112
  "Condition",
111
113
  "ConditionCoding",
112
114
  "Coverage",
@@ -0,0 +1,67 @@
1
+ from django.db import models
2
+ from django.db.models import TextChoices
3
+
4
+
5
+ class CompoundMedication(models.Model):
6
+ """CompoundMedication."""
7
+
8
+ class Meta:
9
+ managed = False
10
+ db_table = "canvas_sdk_data_api_compoundmedication_001"
11
+
12
+ class PotencyUnits(TextChoices):
13
+ """Potency Units."""
14
+
15
+ APPLICATOR = "C62412", "Applicator"
16
+ BLISTER = "C54564", "Blister"
17
+ CAPLET = "C64696", "Caplet"
18
+ CAPSULE = "C48480", "Capsule"
19
+ EACH = "C64933", "Each"
20
+ FILM = "C53499", "Film"
21
+ GRAM = "C48155", "Gram"
22
+ GUM = "C69124", "Gum"
23
+ IMPLANT = "C48499", "Implant"
24
+ INSERT = "C62276", "Insert"
25
+ KIT = "C48504", "Kit"
26
+ LANCET = "C120263", "Lancet"
27
+ LOZENGE = "C48506", "Lozenge"
28
+ MILLILITER = "C28254", "Milliliter"
29
+ PACKET = "C48521", "Packet"
30
+ PAD = "C65032", "Pad"
31
+ PATCH = "C48524", "Patch"
32
+ PEN_NEEDLE = "C120216", "Pen Needle"
33
+ RING = "C62609", "Ring"
34
+ SPONGE = "C53502", "Sponge"
35
+ STICK = "C53503", "Stick"
36
+ STRIP = "C48538", "Strip"
37
+ SUPPOSITORY = "C48539", "Suppository"
38
+ SWAB = "C53504", "Swab"
39
+ TABLET = "C48542", "Tablet"
40
+ TROCHE = "C48548", "Troche"
41
+ UNSPECIFIED = "C38046", "Unspecified"
42
+ WAFER = "C48552", "Wafer"
43
+
44
+ class ControlledSubstanceOptions(TextChoices):
45
+ """Controlled Substance Options."""
46
+
47
+ SCHEDULE_NOT_SCHEDULED = "N", "None"
48
+ SCHEDULE_II = "II", "Schedule II"
49
+ SCHEDULE_III = "III", "Schedule III"
50
+ SCHEDULE_IV = "IV", "Schedule IV"
51
+ SCHEDULE_V = "V", "Schedule V"
52
+
53
+ id = models.UUIDField()
54
+ dbid = models.BigIntegerField(primary_key=True)
55
+ active = models.BooleanField(default=True)
56
+ formulation = models.CharField(max_length=105)
57
+ potency_unit_code = models.CharField(max_length=20, choices=PotencyUnits.choices)
58
+ controlled_substance = models.CharField(
59
+ max_length=3, choices=ControlledSubstanceOptions.choices
60
+ )
61
+ controlled_substance_ndc = models.CharField(max_length=20, blank=True, default="")
62
+
63
+ def __str__(self) -> str:
64
+ return f'CompoundMedication: "{self.formulation}"'
65
+
66
+
67
+ __exports__ = ("CompoundMedication",)
@@ -43,7 +43,8 @@
43
43
  "VitalsCommand"
44
44
  ],
45
45
  "canvas_sdk.commands.base": [
46
- "_BaseCommand"
46
+ "_BaseCommand",
47
+ "_SendableCommandMixin"
47
48
  ],
48
49
  "canvas_sdk.commands.commands.adjust_prescription": [
49
50
  "AdjustPrescriptionCommand"
@@ -112,6 +113,7 @@
112
113
  ],
113
114
  "canvas_sdk.commands.commands.prescribe": [
114
115
  "ClinicalQuantity",
116
+ "CompoundMedicationData",
115
117
  "Decimal",
116
118
  "PrescribeCommand"
117
119
  ],
@@ -204,6 +206,12 @@
204
206
  "canvas_sdk.effects.billing_line_item.update_billing_line_item": [
205
207
  "UpdateBillingLineItem"
206
208
  ],
209
+ "canvas_sdk.effects.compound_medications": [
210
+ "CompoundMedication"
211
+ ],
212
+ "canvas_sdk.effects.compound_medications.compound_medication": [
213
+ "CompoundMedication"
214
+ ],
207
215
  "canvas_sdk.effects.launch_modal": [
208
216
  "LaunchModalEffect"
209
217
  ],
@@ -491,6 +499,7 @@
491
499
  "ClaimPatient",
492
500
  "ClaimQueue",
493
501
  "Command",
502
+ "CompoundMedication",
494
503
  "Condition",
495
504
  "ConditionCoding",
496
505
  "Coverage",
@@ -640,6 +649,9 @@
640
649
  "ReviewStatus",
641
650
  "TaxIDType"
642
651
  ],
652
+ "canvas_sdk.v1.data.compound_medication": [
653
+ "CompoundMedication"
654
+ ],
643
655
  "canvas_sdk.v1.data.condition": [
644
656
  "ClinicalStatus",
645
657
  "Condition",
plugin_runner/sandbox.py CHANGED
@@ -216,8 +216,15 @@ THIRD_PARTY_MODULES = {
216
216
  "jwt": {
217
217
  "decode",
218
218
  "encode",
219
+ "PyJWKClient",
220
+ "ExpiredSignatureError",
221
+ "InvalidTokenError",
219
222
  },
220
223
  "pydantic": {
224
+ "BaseModel",
225
+ "conint",
226
+ "constr",
227
+ "Field",
221
228
  "ValidationError",
222
229
  },
223
230
  "rapidfuzz": {