canvas 0.21.0__py3-none-any.whl → 0.22.1__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.
- {canvas-0.21.0.dist-info → canvas-0.22.1.dist-info}/METADATA +1 -1
- {canvas-0.21.0.dist-info → canvas-0.22.1.dist-info}/RECORD +31 -25
- canvas_generated/messages/effects_pb2.py +2 -2
- canvas_generated/messages/effects_pb2.pyi +40 -0
- canvas_generated/messages/events_pb2.py +2 -2
- canvas_generated/messages/events_pb2.pyi +108 -0
- canvas_sdk/commands/__init__.py +8 -0
- canvas_sdk/commands/base.py +1 -0
- canvas_sdk/commands/commands/__init__.py +0 -0
- canvas_sdk/commands/commands/adjust_prescription.py +24 -0
- canvas_sdk/commands/commands/imaging_order.py +39 -0
- canvas_sdk/commands/commands/instruct.py +17 -1
- canvas_sdk/commands/commands/lab_order.py +11 -6
- canvas_sdk/commands/commands/prescribe.py +1 -1
- canvas_sdk/commands/commands/questionnaire/__init__.py +102 -0
- canvas_sdk/commands/commands/questionnaire/question.py +134 -0
- canvas_sdk/commands/commands/refer.py +50 -0
- canvas_sdk/commands/commands/refill.py +28 -0
- canvas_sdk/commands/commands/resolve_condition.py +43 -0
- canvas_sdk/commands/constants.py +34 -0
- canvas_sdk/commands/tests/protocol/tests.py +10 -1
- canvas_sdk/commands/tests/test_utils.py +4 -1
- canvas_sdk/effects/banner_alert/tests.py +10 -2
- canvas_sdk/v1/data/condition.py +4 -2
- canvas_sdk/v1/data/medication.py +4 -2
- plugin_runner/installation.py +1 -2
- plugin_runner/plugin_runner.py +34 -2
- protobufs/canvas_generated/messages/effects.proto +25 -1
- protobufs/canvas_generated/messages/events.proto +54 -36
- canvas_sdk/commands/commands/questionnaire.py +0 -16
- {canvas-0.21.0.dist-info → canvas-0.22.1.dist-info}/WHEEL +0 -0
- {canvas-0.21.0.dist-info → canvas-0.22.1.dist-info}/entry_points.txt +0 -0
|
@@ -108,6 +108,26 @@ class EventType(int, metaclass=_enum_type_wrapper.EnumTypeWrapper):
|
|
|
108
108
|
MEDICATION_STATEMENT__MEDICATION__PRE_SEARCH: _ClassVar[EventType]
|
|
109
109
|
MEDICATION_STATEMENT__MEDICATION__POST_SEARCH: _ClassVar[EventType]
|
|
110
110
|
MEDICATION_STATEMENT__MEDICATION__SELECTED: _ClassVar[EventType]
|
|
111
|
+
ADJUST_PRESCRIPTION_COMMAND__PRE_ORIGINATE: _ClassVar[EventType]
|
|
112
|
+
ADJUST_PRESCRIPTION_COMMAND__POST_ORIGINATE: _ClassVar[EventType]
|
|
113
|
+
ADJUST_PRESCRIPTION_COMMAND__PRE_UPDATE: _ClassVar[EventType]
|
|
114
|
+
ADJUST_PRESCRIPTION_COMMAND__POST_UPDATE: _ClassVar[EventType]
|
|
115
|
+
ADJUST_PRESCRIPTION_COMMAND__PRE_COMMIT: _ClassVar[EventType]
|
|
116
|
+
ADJUST_PRESCRIPTION_COMMAND__POST_COMMIT: _ClassVar[EventType]
|
|
117
|
+
ADJUST_PRESCRIPTION_COMMAND__PRE_DELETE: _ClassVar[EventType]
|
|
118
|
+
ADJUST_PRESCRIPTION_COMMAND__POST_DELETE: _ClassVar[EventType]
|
|
119
|
+
ADJUST_PRESCRIPTION_COMMAND__PRE_ENTER_IN_ERROR: _ClassVar[EventType]
|
|
120
|
+
ADJUST_PRESCRIPTION_COMMAND__POST_ENTER_IN_ERROR: _ClassVar[EventType]
|
|
121
|
+
ADJUST_PRESCRIPTION_COMMAND__PRE_EXECUTE_ACTION: _ClassVar[EventType]
|
|
122
|
+
ADJUST_PRESCRIPTION_COMMAND__POST_EXECUTE_ACTION: _ClassVar[EventType]
|
|
123
|
+
ADJUST_PRESCRIPTION__PRESCRIBE__POST_SEARCH: _ClassVar[EventType]
|
|
124
|
+
ADJUST_PRESCRIPTION__PRESCRIBE__PRE_SEARCH: _ClassVar[EventType]
|
|
125
|
+
ADJUST_PRESCRIPTION__INDICATIONS__PRE_SEARCH: _ClassVar[EventType]
|
|
126
|
+
ADJUST_PRESCRIPTION__INDICATIONS__POST_SEARCH: _ClassVar[EventType]
|
|
127
|
+
ADJUST_PRESCRIPTION__PHARMACY__PRE_SEARCH: _ClassVar[EventType]
|
|
128
|
+
ADJUST_PRESCRIPTION__PHARMACY__POST_SEARCH: _ClassVar[EventType]
|
|
129
|
+
ADJUST_PRESCRIPTION__CHANGE_MEDICATION_TO__PRE_SEARCH: _ClassVar[EventType]
|
|
130
|
+
ADJUST_PRESCRIPTION__CHANGE_MEDICATION_TO__POST_SEARCH: _ClassVar[EventType]
|
|
111
131
|
ALLERGY_COMMAND__PRE_ORIGINATE: _ClassVar[EventType]
|
|
112
132
|
ALLERGY_COMMAND__POST_ORIGINATE: _ClassVar[EventType]
|
|
113
133
|
ALLERGY_COMMAND__PRE_UPDATE: _ClassVar[EventType]
|
|
@@ -484,6 +504,26 @@ class EventType(int, metaclass=_enum_type_wrapper.EnumTypeWrapper):
|
|
|
484
504
|
REASON_FOR_VISIT_COMMAND__POST_INSERTED_INTO_NOTE: _ClassVar[EventType]
|
|
485
505
|
REASON_FOR_VISIT__CODING__POST_SEARCH: _ClassVar[EventType]
|
|
486
506
|
REASON_FOR_VISIT__CODING__PRE_SEARCH: _ClassVar[EventType]
|
|
507
|
+
REFER_COMMAND__PRE_ORIGINATE: _ClassVar[EventType]
|
|
508
|
+
REFER_COMMAND__POST_ORIGINATE: _ClassVar[EventType]
|
|
509
|
+
REFER_COMMAND__PRE_UPDATE: _ClassVar[EventType]
|
|
510
|
+
REFER_COMMAND__POST_UPDATE: _ClassVar[EventType]
|
|
511
|
+
REFER_COMMAND__PRE_COMMIT: _ClassVar[EventType]
|
|
512
|
+
REFER_COMMAND__POST_COMMIT: _ClassVar[EventType]
|
|
513
|
+
REFER_COMMAND__PRE_DELETE: _ClassVar[EventType]
|
|
514
|
+
REFER_COMMAND__POST_DELETE: _ClassVar[EventType]
|
|
515
|
+
REFER_COMMAND__PRE_ENTER_IN_ERROR: _ClassVar[EventType]
|
|
516
|
+
REFER_COMMAND__POST_ENTER_IN_ERROR: _ClassVar[EventType]
|
|
517
|
+
REFER_COMMAND__PRE_EXECUTE_ACTION: _ClassVar[EventType]
|
|
518
|
+
REFER_COMMAND__POST_EXECUTE_ACTION: _ClassVar[EventType]
|
|
519
|
+
REFER_COMMAND__REFER_TO__POST_SEARCH: _ClassVar[EventType]
|
|
520
|
+
REFER_COMMAND__REFER_TO__PRE_SEARCH: _ClassVar[EventType]
|
|
521
|
+
REFER_COMMAND__INDICATIONS__POST_SEARCH: _ClassVar[EventType]
|
|
522
|
+
REFER_COMMAND__INDICATIONS__PRE_SEARCH: _ClassVar[EventType]
|
|
523
|
+
REFER_COMMAND__DOCUMENTS_TO_INCLUDE__POST_SEARCH: _ClassVar[EventType]
|
|
524
|
+
REFER_COMMAND__DOCUMENTS_TO_INCLUDE__PRE_SEARCH: _ClassVar[EventType]
|
|
525
|
+
REFER_COMMAND__LINKED_ITEMS__POST_SEARCH: _ClassVar[EventType]
|
|
526
|
+
REFER_COMMAND__LINKED_ITEMS_INCLUDE__PRE_SEARCH: _ClassVar[EventType]
|
|
487
527
|
REFILL_COMMAND__PRE_ORIGINATE: _ClassVar[EventType]
|
|
488
528
|
REFILL_COMMAND__POST_ORIGINATE: _ClassVar[EventType]
|
|
489
529
|
REFILL_COMMAND__PRE_UPDATE: _ClassVar[EventType]
|
|
@@ -518,6 +558,20 @@ class EventType(int, metaclass=_enum_type_wrapper.EnumTypeWrapper):
|
|
|
518
558
|
REMOVE_ALLERGY_COMMAND__POST_INSERTED_INTO_NOTE: _ClassVar[EventType]
|
|
519
559
|
REMOVE_ALLERGY__ALLERGY__PRE_SEARCH: _ClassVar[EventType]
|
|
520
560
|
REMOVE_ALLERGY__ALLERGY__POST_SEARCH: _ClassVar[EventType]
|
|
561
|
+
RESOLVE_CONDITION_COMMAND__PRE_ORIGINATE: _ClassVar[EventType]
|
|
562
|
+
RESOLVE_CONDITION_COMMAND__POST_ORIGINATE: _ClassVar[EventType]
|
|
563
|
+
RESOLVE_CONDITION_COMMAND__PRE_UPDATE: _ClassVar[EventType]
|
|
564
|
+
RESOLVE_CONDITION_COMMAND__POST_UPDATE: _ClassVar[EventType]
|
|
565
|
+
RESOLVE_CONDITION_COMMAND__PRE_COMMIT: _ClassVar[EventType]
|
|
566
|
+
RESOLVE_CONDITION_COMMAND__POST_COMMIT: _ClassVar[EventType]
|
|
567
|
+
RESOLVE_CONDITION_COMMAND__PRE_DELETE: _ClassVar[EventType]
|
|
568
|
+
RESOLVE_CONDITION_COMMAND__POST_DELETE: _ClassVar[EventType]
|
|
569
|
+
RESOLVE_CONDITION_COMMAND__PRE_ENTER_IN_ERROR: _ClassVar[EventType]
|
|
570
|
+
RESOLVE_CONDITION_COMMAND__POST_ENTER_IN_ERROR: _ClassVar[EventType]
|
|
571
|
+
RESOLVE_CONDITION_COMMAND__PRE_EXECUTE_ACTION: _ClassVar[EventType]
|
|
572
|
+
RESOLVE_CONDITION_COMMAND__POST_EXECUTE_ACTION: _ClassVar[EventType]
|
|
573
|
+
RESOLVE_CONDITION__CONDITION__PRE_SEARCH: _ClassVar[EventType]
|
|
574
|
+
RESOLVE_CONDITION__CONDITION__POST_SEARCH: _ClassVar[EventType]
|
|
521
575
|
ROS_COMMAND__PRE_ORIGINATE: _ClassVar[EventType]
|
|
522
576
|
ROS_COMMAND__POST_ORIGINATE: _ClassVar[EventType]
|
|
523
577
|
ROS_COMMAND__PRE_UPDATE: _ClassVar[EventType]
|
|
@@ -842,6 +896,26 @@ ASSESS_COMMAND__CONDITION_SELECTED: EventType
|
|
|
842
896
|
MEDICATION_STATEMENT__MEDICATION__PRE_SEARCH: EventType
|
|
843
897
|
MEDICATION_STATEMENT__MEDICATION__POST_SEARCH: EventType
|
|
844
898
|
MEDICATION_STATEMENT__MEDICATION__SELECTED: EventType
|
|
899
|
+
ADJUST_PRESCRIPTION_COMMAND__PRE_ORIGINATE: EventType
|
|
900
|
+
ADJUST_PRESCRIPTION_COMMAND__POST_ORIGINATE: EventType
|
|
901
|
+
ADJUST_PRESCRIPTION_COMMAND__PRE_UPDATE: EventType
|
|
902
|
+
ADJUST_PRESCRIPTION_COMMAND__POST_UPDATE: EventType
|
|
903
|
+
ADJUST_PRESCRIPTION_COMMAND__PRE_COMMIT: EventType
|
|
904
|
+
ADJUST_PRESCRIPTION_COMMAND__POST_COMMIT: EventType
|
|
905
|
+
ADJUST_PRESCRIPTION_COMMAND__PRE_DELETE: EventType
|
|
906
|
+
ADJUST_PRESCRIPTION_COMMAND__POST_DELETE: EventType
|
|
907
|
+
ADJUST_PRESCRIPTION_COMMAND__PRE_ENTER_IN_ERROR: EventType
|
|
908
|
+
ADJUST_PRESCRIPTION_COMMAND__POST_ENTER_IN_ERROR: EventType
|
|
909
|
+
ADJUST_PRESCRIPTION_COMMAND__PRE_EXECUTE_ACTION: EventType
|
|
910
|
+
ADJUST_PRESCRIPTION_COMMAND__POST_EXECUTE_ACTION: EventType
|
|
911
|
+
ADJUST_PRESCRIPTION__PRESCRIBE__POST_SEARCH: EventType
|
|
912
|
+
ADJUST_PRESCRIPTION__PRESCRIBE__PRE_SEARCH: EventType
|
|
913
|
+
ADJUST_PRESCRIPTION__INDICATIONS__PRE_SEARCH: EventType
|
|
914
|
+
ADJUST_PRESCRIPTION__INDICATIONS__POST_SEARCH: EventType
|
|
915
|
+
ADJUST_PRESCRIPTION__PHARMACY__PRE_SEARCH: EventType
|
|
916
|
+
ADJUST_PRESCRIPTION__PHARMACY__POST_SEARCH: EventType
|
|
917
|
+
ADJUST_PRESCRIPTION__CHANGE_MEDICATION_TO__PRE_SEARCH: EventType
|
|
918
|
+
ADJUST_PRESCRIPTION__CHANGE_MEDICATION_TO__POST_SEARCH: EventType
|
|
845
919
|
ALLERGY_COMMAND__PRE_ORIGINATE: EventType
|
|
846
920
|
ALLERGY_COMMAND__POST_ORIGINATE: EventType
|
|
847
921
|
ALLERGY_COMMAND__PRE_UPDATE: EventType
|
|
@@ -1218,6 +1292,26 @@ REASON_FOR_VISIT_COMMAND__POST_EXECUTE_ACTION: EventType
|
|
|
1218
1292
|
REASON_FOR_VISIT_COMMAND__POST_INSERTED_INTO_NOTE: EventType
|
|
1219
1293
|
REASON_FOR_VISIT__CODING__POST_SEARCH: EventType
|
|
1220
1294
|
REASON_FOR_VISIT__CODING__PRE_SEARCH: EventType
|
|
1295
|
+
REFER_COMMAND__PRE_ORIGINATE: EventType
|
|
1296
|
+
REFER_COMMAND__POST_ORIGINATE: EventType
|
|
1297
|
+
REFER_COMMAND__PRE_UPDATE: EventType
|
|
1298
|
+
REFER_COMMAND__POST_UPDATE: EventType
|
|
1299
|
+
REFER_COMMAND__PRE_COMMIT: EventType
|
|
1300
|
+
REFER_COMMAND__POST_COMMIT: EventType
|
|
1301
|
+
REFER_COMMAND__PRE_DELETE: EventType
|
|
1302
|
+
REFER_COMMAND__POST_DELETE: EventType
|
|
1303
|
+
REFER_COMMAND__PRE_ENTER_IN_ERROR: EventType
|
|
1304
|
+
REFER_COMMAND__POST_ENTER_IN_ERROR: EventType
|
|
1305
|
+
REFER_COMMAND__PRE_EXECUTE_ACTION: EventType
|
|
1306
|
+
REFER_COMMAND__POST_EXECUTE_ACTION: EventType
|
|
1307
|
+
REFER_COMMAND__REFER_TO__POST_SEARCH: EventType
|
|
1308
|
+
REFER_COMMAND__REFER_TO__PRE_SEARCH: EventType
|
|
1309
|
+
REFER_COMMAND__INDICATIONS__POST_SEARCH: EventType
|
|
1310
|
+
REFER_COMMAND__INDICATIONS__PRE_SEARCH: EventType
|
|
1311
|
+
REFER_COMMAND__DOCUMENTS_TO_INCLUDE__POST_SEARCH: EventType
|
|
1312
|
+
REFER_COMMAND__DOCUMENTS_TO_INCLUDE__PRE_SEARCH: EventType
|
|
1313
|
+
REFER_COMMAND__LINKED_ITEMS__POST_SEARCH: EventType
|
|
1314
|
+
REFER_COMMAND__LINKED_ITEMS_INCLUDE__PRE_SEARCH: EventType
|
|
1221
1315
|
REFILL_COMMAND__PRE_ORIGINATE: EventType
|
|
1222
1316
|
REFILL_COMMAND__POST_ORIGINATE: EventType
|
|
1223
1317
|
REFILL_COMMAND__PRE_UPDATE: EventType
|
|
@@ -1252,6 +1346,20 @@ REMOVE_ALLERGY_COMMAND__POST_EXECUTE_ACTION: EventType
|
|
|
1252
1346
|
REMOVE_ALLERGY_COMMAND__POST_INSERTED_INTO_NOTE: EventType
|
|
1253
1347
|
REMOVE_ALLERGY__ALLERGY__PRE_SEARCH: EventType
|
|
1254
1348
|
REMOVE_ALLERGY__ALLERGY__POST_SEARCH: EventType
|
|
1349
|
+
RESOLVE_CONDITION_COMMAND__PRE_ORIGINATE: EventType
|
|
1350
|
+
RESOLVE_CONDITION_COMMAND__POST_ORIGINATE: EventType
|
|
1351
|
+
RESOLVE_CONDITION_COMMAND__PRE_UPDATE: EventType
|
|
1352
|
+
RESOLVE_CONDITION_COMMAND__POST_UPDATE: EventType
|
|
1353
|
+
RESOLVE_CONDITION_COMMAND__PRE_COMMIT: EventType
|
|
1354
|
+
RESOLVE_CONDITION_COMMAND__POST_COMMIT: EventType
|
|
1355
|
+
RESOLVE_CONDITION_COMMAND__PRE_DELETE: EventType
|
|
1356
|
+
RESOLVE_CONDITION_COMMAND__POST_DELETE: EventType
|
|
1357
|
+
RESOLVE_CONDITION_COMMAND__PRE_ENTER_IN_ERROR: EventType
|
|
1358
|
+
RESOLVE_CONDITION_COMMAND__POST_ENTER_IN_ERROR: EventType
|
|
1359
|
+
RESOLVE_CONDITION_COMMAND__PRE_EXECUTE_ACTION: EventType
|
|
1360
|
+
RESOLVE_CONDITION_COMMAND__POST_EXECUTE_ACTION: EventType
|
|
1361
|
+
RESOLVE_CONDITION__CONDITION__PRE_SEARCH: EventType
|
|
1362
|
+
RESOLVE_CONDITION__CONDITION__POST_SEARCH: EventType
|
|
1255
1363
|
ROS_COMMAND__PRE_ORIGINATE: EventType
|
|
1256
1364
|
ROS_COMMAND__POST_ORIGINATE: EventType
|
|
1257
1365
|
ROS_COMMAND__PRE_UPDATE: EventType
|
canvas_sdk/commands/__init__.py
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
from canvas_sdk.commands.commands.adjust_prescription import AdjustPrescriptionCommand
|
|
1
2
|
from canvas_sdk.commands.commands.allergy import AllergyCommand
|
|
2
3
|
from canvas_sdk.commands.commands.assess import AssessCommand
|
|
3
4
|
from canvas_sdk.commands.commands.close_goal import CloseGoalCommand
|
|
@@ -9,6 +10,7 @@ from canvas_sdk.commands.commands.goal import GoalCommand
|
|
|
9
10
|
from canvas_sdk.commands.commands.history_present_illness import (
|
|
10
11
|
HistoryOfPresentIllnessCommand,
|
|
11
12
|
)
|
|
13
|
+
from canvas_sdk.commands.commands.imaging_order import ImagingOrderCommand
|
|
12
14
|
from canvas_sdk.commands.commands.instruct import InstructCommand
|
|
13
15
|
from canvas_sdk.commands.commands.lab_order import LabOrderCommand
|
|
14
16
|
from canvas_sdk.commands.commands.medical_history import MedicalHistoryCommand
|
|
@@ -21,8 +23,10 @@ from canvas_sdk.commands.commands.plan import PlanCommand
|
|
|
21
23
|
from canvas_sdk.commands.commands.prescribe import PrescribeCommand
|
|
22
24
|
from canvas_sdk.commands.commands.questionnaire import QuestionnaireCommand
|
|
23
25
|
from canvas_sdk.commands.commands.reason_for_visit import ReasonForVisitCommand
|
|
26
|
+
from canvas_sdk.commands.commands.refer import ReferCommand
|
|
24
27
|
from canvas_sdk.commands.commands.refill import RefillCommand
|
|
25
28
|
from canvas_sdk.commands.commands.remove_allergy import RemoveAllergyCommand
|
|
29
|
+
from canvas_sdk.commands.commands.resolve_condition import ResolveConditionCommand
|
|
26
30
|
from canvas_sdk.commands.commands.review_of_systems import ReviewOfSystemsCommand
|
|
27
31
|
from canvas_sdk.commands.commands.stop_medication import StopMedicationCommand
|
|
28
32
|
from canvas_sdk.commands.commands.structured_assessment import StructuredAssessmentCommand
|
|
@@ -32,6 +36,7 @@ from canvas_sdk.commands.commands.update_goal import UpdateGoalCommand
|
|
|
32
36
|
from canvas_sdk.commands.commands.vitals import VitalsCommand
|
|
33
37
|
|
|
34
38
|
__all__ = (
|
|
39
|
+
"AdjustPrescriptionCommand",
|
|
35
40
|
"AllergyCommand",
|
|
36
41
|
"AssessCommand",
|
|
37
42
|
"CloseGoalCommand",
|
|
@@ -40,6 +45,7 @@ __all__ = (
|
|
|
40
45
|
"FollowUpCommand",
|
|
41
46
|
"GoalCommand",
|
|
42
47
|
"HistoryOfPresentIllnessCommand",
|
|
48
|
+
"ImagingOrderCommand",
|
|
43
49
|
"InstructCommand",
|
|
44
50
|
"LabOrderCommand",
|
|
45
51
|
"MedicalHistoryCommand",
|
|
@@ -51,8 +57,10 @@ __all__ = (
|
|
|
51
57
|
"PhysicalExamCommand",
|
|
52
58
|
"QuestionnaireCommand",
|
|
53
59
|
"ReasonForVisitCommand",
|
|
60
|
+
"ReferCommand",
|
|
54
61
|
"RefillCommand",
|
|
55
62
|
"RemoveAllergyCommand",
|
|
63
|
+
"ResolveConditionCommand",
|
|
56
64
|
"ReviewOfSystemsCommand",
|
|
57
65
|
"StopMedicationCommand",
|
|
58
66
|
"StructuredAssessmentCommand",
|
canvas_sdk/commands/base.py
CHANGED
|
File without changes
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
from pydantic import Field
|
|
2
|
+
|
|
3
|
+
from canvas_sdk.commands.commands.refill import RefillCommand
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class AdjustPrescriptionCommand(RefillCommand):
|
|
7
|
+
"""A class for managing Adjust Prescription command within a specific note."""
|
|
8
|
+
|
|
9
|
+
class Meta:
|
|
10
|
+
key = "adjustPrescription"
|
|
11
|
+
commit_required_fields = (
|
|
12
|
+
"fdb_code",
|
|
13
|
+
"sig",
|
|
14
|
+
"quantity_to_dispense",
|
|
15
|
+
"type_to_dispense",
|
|
16
|
+
"refills",
|
|
17
|
+
"substitutions",
|
|
18
|
+
"prescriber_id",
|
|
19
|
+
"new_fdb_code",
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
new_fdb_code: str | None = Field(
|
|
23
|
+
default=None, json_schema_extra={"commands_api_name": "change_medication_to"}
|
|
24
|
+
)
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
from enum import Enum
|
|
2
|
+
|
|
3
|
+
from canvas_sdk.commands.base import _BaseCommand as BaseCommand
|
|
4
|
+
from canvas_sdk.commands.constants import ServiceProvider
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class ImagingOrderCommand(BaseCommand):
|
|
8
|
+
"""A class for managing an Imaging Order command within a specific note."""
|
|
9
|
+
|
|
10
|
+
class Meta:
|
|
11
|
+
key = "imagingOrder"
|
|
12
|
+
commit_required_fields = (
|
|
13
|
+
"image_code",
|
|
14
|
+
"diagnosis_codes",
|
|
15
|
+
"ordering_provider",
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
class Priority(Enum):
|
|
19
|
+
ROUTINE = "Routine"
|
|
20
|
+
URGENT = "Urgent"
|
|
21
|
+
|
|
22
|
+
image_code: str | None = None
|
|
23
|
+
diagnosis_codes: list[str] = []
|
|
24
|
+
priority: Priority | None = None
|
|
25
|
+
additional_details: str | None = None
|
|
26
|
+
service_provider: ServiceProvider | None = None
|
|
27
|
+
comment: str | None = None
|
|
28
|
+
ordering_provider_key: str | None = None
|
|
29
|
+
linked_items_urns: list[str] | None = None
|
|
30
|
+
|
|
31
|
+
@property
|
|
32
|
+
def values(self) -> dict:
|
|
33
|
+
"""The Imaging Order command's field values."""
|
|
34
|
+
values = super().values
|
|
35
|
+
|
|
36
|
+
if self.is_dirty("service_provider"):
|
|
37
|
+
values["service_provider"] = self.service_provider.__dict__
|
|
38
|
+
|
|
39
|
+
return values
|
|
@@ -1,4 +1,7 @@
|
|
|
1
|
+
from pydantic_core import InitErrorDetails
|
|
2
|
+
|
|
1
3
|
from canvas_sdk.commands.base import _BaseCommand as BaseCommand
|
|
4
|
+
from canvas_sdk.commands.constants import CodeSystems, Coding
|
|
2
5
|
|
|
3
6
|
|
|
4
7
|
class InstructCommand(BaseCommand):
|
|
@@ -8,5 +11,18 @@ class InstructCommand(BaseCommand):
|
|
|
8
11
|
key = "instruct"
|
|
9
12
|
commit_required_fields = ("instruction",)
|
|
10
13
|
|
|
11
|
-
|
|
14
|
+
coding: Coding | None = None
|
|
12
15
|
comment: str | None = None
|
|
16
|
+
|
|
17
|
+
def _get_error_details(self, method: str) -> list[InitErrorDetails]:
|
|
18
|
+
errors = super()._get_error_details(method)
|
|
19
|
+
|
|
20
|
+
if (
|
|
21
|
+
self.coding
|
|
22
|
+
and self.coding["system"] != CodeSystems.SNOMED
|
|
23
|
+
and self.coding["system"] != CodeSystems.UNSTRUCTURED
|
|
24
|
+
):
|
|
25
|
+
message = f"The 'coding.system' field must be '{CodeSystems.SNOMED}' or '{CodeSystems.UNSTRUCTURED}'."
|
|
26
|
+
errors.append(self._create_error_detail("value", message, self.coding))
|
|
27
|
+
|
|
28
|
+
return errors
|
|
@@ -34,11 +34,16 @@ class LabOrderCommand(BaseCommand):
|
|
|
34
34
|
|
|
35
35
|
lab_partner_obj = None
|
|
36
36
|
if self.lab_partner:
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
.
|
|
40
|
-
|
|
41
|
-
|
|
37
|
+
query = {}
|
|
38
|
+
try:
|
|
39
|
+
UUID(str(self.lab_partner))
|
|
40
|
+
except ValueError:
|
|
41
|
+
query["name"] = self.lab_partner
|
|
42
|
+
else:
|
|
43
|
+
query["id"] = self.lab_partner
|
|
44
|
+
|
|
45
|
+
lab_partner_obj = LabPartner.objects.filter(**query).values("id", "dbid").first()
|
|
46
|
+
|
|
42
47
|
if not lab_partner_obj:
|
|
43
48
|
errors.append(
|
|
44
49
|
self._create_error_detail(
|
|
@@ -61,7 +66,7 @@ class LabOrderCommand(BaseCommand):
|
|
|
61
66
|
|
|
62
67
|
for code in self.tests_order_codes:
|
|
63
68
|
try:
|
|
64
|
-
uuid_tests.append(UUID(code))
|
|
69
|
+
uuid_tests.append(UUID(str(code)))
|
|
65
70
|
except ValueError:
|
|
66
71
|
order_code_tests.append(code)
|
|
67
72
|
|
|
@@ -28,7 +28,7 @@ class PrescribeCommand(_BaseCommand):
|
|
|
28
28
|
|
|
29
29
|
fdb_code: str | None = Field(default=None, json_schema_extra={"commands_api_name": "prescribe"})
|
|
30
30
|
icd10_codes: conlist(str, max_length=2) = Field( # type: ignore[valid-type]
|
|
31
|
-
[], json_schema_extra={"commands_api_name": "indications"}
|
|
31
|
+
default=[], json_schema_extra={"commands_api_name": "indications"}
|
|
32
32
|
)
|
|
33
33
|
sig: str = ""
|
|
34
34
|
days_supply: int | None = None
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
from functools import cached_property
|
|
2
|
+
from typing import Any
|
|
3
|
+
|
|
4
|
+
from pydantic import Field
|
|
5
|
+
|
|
6
|
+
from canvas_sdk.commands.base import _BaseCommand
|
|
7
|
+
from canvas_sdk.commands.commands.questionnaire.question import (
|
|
8
|
+
BaseQuestion,
|
|
9
|
+
CheckboxQuestion,
|
|
10
|
+
IntegerQuestion,
|
|
11
|
+
RadioQuestion,
|
|
12
|
+
ResponseOption,
|
|
13
|
+
TextQuestion,
|
|
14
|
+
)
|
|
15
|
+
from canvas_sdk.v1.data import Questionnaire
|
|
16
|
+
|
|
17
|
+
QUESTION_CLASSES: dict[str, type[BaseQuestion]] = {
|
|
18
|
+
ResponseOption.TYPE_TEXT: TextQuestion,
|
|
19
|
+
ResponseOption.TYPE_INTEGER: IntegerQuestion,
|
|
20
|
+
ResponseOption.TYPE_RADIO: RadioQuestion,
|
|
21
|
+
ResponseOption.TYPE_CHECKBOX: CheckboxQuestion,
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class QuestionnaireCommand(_BaseCommand):
|
|
26
|
+
"""A class for managing a Questionnaire command within a specific note."""
|
|
27
|
+
|
|
28
|
+
class Meta:
|
|
29
|
+
key = "questionnaire"
|
|
30
|
+
commit_required_fields = ("questionnaire_id",)
|
|
31
|
+
|
|
32
|
+
questionnaire_id: str | None = Field(
|
|
33
|
+
default=None, json_schema_extra={"commands_api_name": "questionnaire"}
|
|
34
|
+
)
|
|
35
|
+
result: str | None = None
|
|
36
|
+
|
|
37
|
+
@cached_property
|
|
38
|
+
def _questionnaire(self) -> Questionnaire | None:
|
|
39
|
+
if not self.questionnaire_id:
|
|
40
|
+
return None
|
|
41
|
+
return Questionnaire.objects.get(id=self.questionnaire_id)
|
|
42
|
+
|
|
43
|
+
@cached_property
|
|
44
|
+
def questions(self) -> list[BaseQuestion]:
|
|
45
|
+
"""
|
|
46
|
+
Returns a list of question objects.
|
|
47
|
+
|
|
48
|
+
For each question in the questionnaire, creates an instance of the
|
|
49
|
+
appropriate question subclass based on the question.response_option_set.type.
|
|
50
|
+
"""
|
|
51
|
+
question_objs: list[BaseQuestion] = []
|
|
52
|
+
if not self._questionnaire:
|
|
53
|
+
return question_objs
|
|
54
|
+
|
|
55
|
+
for question in self._questionnaire.questions.all():
|
|
56
|
+
qdata: dict[str, Any] = {
|
|
57
|
+
"name": f"question-{question.pk}",
|
|
58
|
+
"label": question.name,
|
|
59
|
+
"coding": {
|
|
60
|
+
"system": question.code_system,
|
|
61
|
+
"code": question.code,
|
|
62
|
+
},
|
|
63
|
+
"options": [
|
|
64
|
+
ResponseOption(
|
|
65
|
+
dbid=option.pk, name=option.name, code=option.code, value=option.value
|
|
66
|
+
)
|
|
67
|
+
for option in question.response_option_set.options.all()
|
|
68
|
+
]
|
|
69
|
+
if question.response_option_set
|
|
70
|
+
else [],
|
|
71
|
+
}
|
|
72
|
+
q_type = question.response_option_set.type if question.response_option_set else None
|
|
73
|
+
q_obj: BaseQuestion
|
|
74
|
+
if q_type in QUESTION_CLASSES:
|
|
75
|
+
question_objs.append(QUESTION_CLASSES[q_type](**qdata))
|
|
76
|
+
else:
|
|
77
|
+
raise ValueError(f"Unsupported question type: {q_type}")
|
|
78
|
+
if q_type == ResponseOption.TYPE_TEXT:
|
|
79
|
+
q_obj = TextQuestion(**qdata)
|
|
80
|
+
elif q_type == ResponseOption.TYPE_INTEGER:
|
|
81
|
+
q_obj = IntegerQuestion(**qdata)
|
|
82
|
+
elif q_type == ResponseOption.TYPE_RADIO:
|
|
83
|
+
q_obj = RadioQuestion(**qdata)
|
|
84
|
+
elif q_type == ResponseOption.TYPE_CHECKBOX:
|
|
85
|
+
q_obj = CheckboxQuestion(**qdata)
|
|
86
|
+
else:
|
|
87
|
+
# This should never happen, but just in case
|
|
88
|
+
raise ValueError(f"Unsupported question type: {q_type}")
|
|
89
|
+
question_objs.append(q_obj)
|
|
90
|
+
return question_objs
|
|
91
|
+
|
|
92
|
+
@property
|
|
93
|
+
def values(self) -> dict:
|
|
94
|
+
"""Return the values for the command.
|
|
95
|
+
|
|
96
|
+
For questionnaire-related commands, this includes the responses to the questions.
|
|
97
|
+
"""
|
|
98
|
+
values = super().values
|
|
99
|
+
|
|
100
|
+
values["questions"] = {q.name: q.response for q in self.questions if q.response is not None}
|
|
101
|
+
|
|
102
|
+
return values
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import dataclasses
|
|
2
|
+
from abc import ABC, abstractmethod
|
|
3
|
+
from typing import Any
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
@dataclasses.dataclass
|
|
7
|
+
class ResponseOption:
|
|
8
|
+
"""A response option for a question."""
|
|
9
|
+
|
|
10
|
+
TYPE_TEXT = "TXT"
|
|
11
|
+
TYPE_INTEGER = "INT"
|
|
12
|
+
TYPE_RADIO = "SING"
|
|
13
|
+
TYPE_CHECKBOX = "MULT"
|
|
14
|
+
|
|
15
|
+
def __init__(self, dbid: int, name: str, code: str, value: str) -> None:
|
|
16
|
+
self.dbid: int = dbid
|
|
17
|
+
self.name: str = name
|
|
18
|
+
self.code: str = code
|
|
19
|
+
self.value: str = value
|
|
20
|
+
|
|
21
|
+
def __eq__(self, other: Any) -> bool:
|
|
22
|
+
if isinstance(other, ResponseOption):
|
|
23
|
+
return (
|
|
24
|
+
self.dbid == other.dbid
|
|
25
|
+
and self.name == other.name
|
|
26
|
+
and self.code == other.code
|
|
27
|
+
and self.value == other.value
|
|
28
|
+
)
|
|
29
|
+
return False
|
|
30
|
+
|
|
31
|
+
def __repr__(self) -> str:
|
|
32
|
+
return f"ResponseOption({self.dbid=!r}, {self.name=!r}, {self.code=!r}, {self.value=!r})"
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class BaseQuestion(ABC):
|
|
36
|
+
"""Base class for questions."""
|
|
37
|
+
|
|
38
|
+
type: str
|
|
39
|
+
|
|
40
|
+
def __init__(
|
|
41
|
+
self, name: str, label: str, coding: dict[str, str], options: list[ResponseOption]
|
|
42
|
+
) -> None:
|
|
43
|
+
self.name: str = name
|
|
44
|
+
self.label: str = label
|
|
45
|
+
self.coding: dict[str, str] = coding
|
|
46
|
+
self.options: list[ResponseOption] = options
|
|
47
|
+
self.response: Any | None = None
|
|
48
|
+
|
|
49
|
+
def __repr__(self) -> str:
|
|
50
|
+
return f"Question({self.name=!r}, {self.label=!r}, {self.type=!r}, {self.options=!r}, {self.response=!r})"
|
|
51
|
+
|
|
52
|
+
@abstractmethod
|
|
53
|
+
def add_response(self, *args: Any, **kwargs: Any) -> None:
|
|
54
|
+
"""Record a response for the question.
|
|
55
|
+
|
|
56
|
+
Subclasses will override this to perform type-specific validation.
|
|
57
|
+
"""
|
|
58
|
+
raise NotImplementedError("Subclasses must implement this method.")
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
class TextQuestion(BaseQuestion):
|
|
62
|
+
"""A question that expects a text response."""
|
|
63
|
+
|
|
64
|
+
type = ResponseOption.TYPE_TEXT
|
|
65
|
+
|
|
66
|
+
def add_response(self, /, text: str) -> None:
|
|
67
|
+
"""For a text question, the response must be a string."""
|
|
68
|
+
if not isinstance(text, str):
|
|
69
|
+
raise ValueError(
|
|
70
|
+
f"Response for a text question must be a string. Question: {self.label}"
|
|
71
|
+
)
|
|
72
|
+
self.response = text
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
class IntegerQuestion(BaseQuestion):
|
|
76
|
+
"""A question that expects an integer response."""
|
|
77
|
+
|
|
78
|
+
type = ResponseOption.TYPE_INTEGER
|
|
79
|
+
|
|
80
|
+
def add_response(self, /, integer: int) -> None:
|
|
81
|
+
"""For an integer question, the response must be convertible to int."""
|
|
82
|
+
try:
|
|
83
|
+
self.response = int(integer)
|
|
84
|
+
except (ValueError, TypeError) as e:
|
|
85
|
+
raise ValueError(
|
|
86
|
+
f"Response for IntegerQuestion must be convertible to an integer. Question: {self.label}"
|
|
87
|
+
) from e
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
class RadioQuestion(BaseQuestion):
|
|
91
|
+
"""A question that expects a single-choice response."""
|
|
92
|
+
|
|
93
|
+
type = ResponseOption.TYPE_RADIO
|
|
94
|
+
|
|
95
|
+
def add_response(self, /, option: ResponseOption) -> None:
|
|
96
|
+
"""Record a radio response.
|
|
97
|
+
|
|
98
|
+
Expects a single keyword argument 'option' of type ResponseOption.
|
|
99
|
+
Validates that the option's value is among the allowed options.
|
|
100
|
+
"""
|
|
101
|
+
if option not in self.options:
|
|
102
|
+
raise ValueError(
|
|
103
|
+
f"Invalid response option for radio question '{self.label}'. Allowed options: {self.options}"
|
|
104
|
+
)
|
|
105
|
+
|
|
106
|
+
self.response = option.dbid
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
class CheckboxQuestion(BaseQuestion):
|
|
110
|
+
"""A question that expects a multiple-choice response."""
|
|
111
|
+
|
|
112
|
+
type = ResponseOption.TYPE_CHECKBOX
|
|
113
|
+
|
|
114
|
+
def add_response(
|
|
115
|
+
self, /, option: ResponseOption, selected: bool = True, comment: str = ""
|
|
116
|
+
) -> None:
|
|
117
|
+
"""Record a checkbox response.
|
|
118
|
+
|
|
119
|
+
Validates that:
|
|
120
|
+
- 'option' is a ResponseOption.
|
|
121
|
+
- 'selected' is a bool (defaults to True if not provided).
|
|
122
|
+
- 'comment' is a string (defaults to empty string if not provided).
|
|
123
|
+
The response is stored as a list of dictionaries.
|
|
124
|
+
"""
|
|
125
|
+
if option not in self.options:
|
|
126
|
+
raise ValueError(
|
|
127
|
+
f"Invalid response option for checkbox question '{self.label}'. Allowed values: {self.options}"
|
|
128
|
+
)
|
|
129
|
+
|
|
130
|
+
if not self.response:
|
|
131
|
+
self.response = []
|
|
132
|
+
self.response.append(
|
|
133
|
+
{"text": option.name, "value": option.dbid, "comment": comment, "selected": selected}
|
|
134
|
+
)
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
from enum import Enum
|
|
2
|
+
|
|
3
|
+
from canvas_sdk.commands.base import _BaseCommand as BaseCommand
|
|
4
|
+
from canvas_sdk.commands.constants import ServiceProvider
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class ReferCommand(BaseCommand):
|
|
8
|
+
"""A class for managing a Refer command within a specific note."""
|
|
9
|
+
|
|
10
|
+
class Meta:
|
|
11
|
+
key = "refer"
|
|
12
|
+
commit_required_fields = (
|
|
13
|
+
"service_provider",
|
|
14
|
+
"diagnosis_codes",
|
|
15
|
+
"clinical_question",
|
|
16
|
+
"notes_to_specialist",
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
class ClinicalQuestion(Enum):
|
|
20
|
+
"""Clinical question choices."""
|
|
21
|
+
|
|
22
|
+
COGNITIVE_ASSISTANCE = "Cognitive Assistance (Advice/Guidance)"
|
|
23
|
+
ASSISTANCE_WITH_ONGOING_MANAGEMENT = "Assistance with Ongoing Management"
|
|
24
|
+
SPECIALIZED_INTERVENTION = "Specialized intervention"
|
|
25
|
+
DIAGNOSTIC_UNCERTAINTY = "Diagnostic Uncertainty"
|
|
26
|
+
|
|
27
|
+
class Priority(Enum):
|
|
28
|
+
"""Priority choices."""
|
|
29
|
+
|
|
30
|
+
ROUTINE = "Routine"
|
|
31
|
+
URGENT = "Urgent"
|
|
32
|
+
|
|
33
|
+
service_provider: ServiceProvider | None = None
|
|
34
|
+
diagnosis_codes: list[str] = []
|
|
35
|
+
clinical_question: ClinicalQuestion | None = None
|
|
36
|
+
priority: Priority | None = None
|
|
37
|
+
notes_to_specialist: str | None = None
|
|
38
|
+
include_visit_note: bool = False
|
|
39
|
+
comment: str | None = None
|
|
40
|
+
linked_items_urns: list[str] | None = None
|
|
41
|
+
|
|
42
|
+
@property
|
|
43
|
+
def values(self) -> dict:
|
|
44
|
+
"""The Refer command's field values."""
|
|
45
|
+
values = super().values
|
|
46
|
+
|
|
47
|
+
if self.is_dirty("service_provider"):
|
|
48
|
+
values["service_provider"] = self.service_provider.__dict__
|
|
49
|
+
|
|
50
|
+
return values
|
|
@@ -1,4 +1,10 @@
|
|
|
1
|
+
from typing import Literal
|
|
2
|
+
|
|
3
|
+
from django.db.models.expressions import Subquery
|
|
4
|
+
from pydantic_core import InitErrorDetails
|
|
5
|
+
|
|
1
6
|
from canvas_sdk.commands.commands.prescribe import PrescribeCommand
|
|
7
|
+
from canvas_sdk.v1.data import Medication, Note
|
|
2
8
|
|
|
3
9
|
|
|
4
10
|
class RefillCommand(PrescribeCommand):
|
|
@@ -15,3 +21,25 @@ class RefillCommand(PrescribeCommand):
|
|
|
15
21
|
"substitutions",
|
|
16
22
|
"prescriber_id",
|
|
17
23
|
)
|
|
24
|
+
|
|
25
|
+
def _get_error_details(
|
|
26
|
+
self, method: Literal["originate", "edit", "delete", "commit", "enter_in_error"]
|
|
27
|
+
) -> list[InitErrorDetails]:
|
|
28
|
+
errors = super()._get_error_details(method)
|
|
29
|
+
|
|
30
|
+
if self.fdb_code:
|
|
31
|
+
subquery = Subquery(Note.objects.filter(id=self.note_uuid).values("patient_id")[:1])
|
|
32
|
+
if (
|
|
33
|
+
not Medication.objects.active()
|
|
34
|
+
.filter(codings__code=self.fdb_code, patient=subquery)
|
|
35
|
+
.exists()
|
|
36
|
+
):
|
|
37
|
+
errors.append(
|
|
38
|
+
self._create_error_detail(
|
|
39
|
+
"value",
|
|
40
|
+
f"Medication with fdb_code {self.fdb_code} does not exist.",
|
|
41
|
+
self.fdb_code,
|
|
42
|
+
)
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
return errors
|