messagefoundry 0.1.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 (142) hide show
  1. messagefoundry/__init__.py +108 -0
  2. messagefoundry/__main__.py +1155 -0
  3. messagefoundry/api/__init__.py +27 -0
  4. messagefoundry/api/app.py +1581 -0
  5. messagefoundry/api/approvals.py +184 -0
  6. messagefoundry/api/auth_models.py +211 -0
  7. messagefoundry/api/auth_routes.py +655 -0
  8. messagefoundry/api/field_authz.py +96 -0
  9. messagefoundry/api/models.py +374 -0
  10. messagefoundry/api/security.py +247 -0
  11. messagefoundry/api/tls.py +47 -0
  12. messagefoundry/auth/__init__.py +39 -0
  13. messagefoundry/auth/data/common_passwords.NOTICE +13 -0
  14. messagefoundry/auth/data/common_passwords.txt +10000 -0
  15. messagefoundry/auth/identity.py +71 -0
  16. messagefoundry/auth/ldap.py +264 -0
  17. messagefoundry/auth/notifications.py +68 -0
  18. messagefoundry/auth/passwords.py +53 -0
  19. messagefoundry/auth/permissions.py +120 -0
  20. messagefoundry/auth/policy.py +153 -0
  21. messagefoundry/auth/ratelimit.py +55 -0
  22. messagefoundry/auth/service.py +1323 -0
  23. messagefoundry/auth/tokens.py +26 -0
  24. messagefoundry/auth/totp.py +174 -0
  25. messagefoundry/checks.py +174 -0
  26. messagefoundry/config/__init__.py +30 -0
  27. messagefoundry/config/active_environment.py +80 -0
  28. messagefoundry/config/ai_policy.py +140 -0
  29. messagefoundry/config/code_sets.py +260 -0
  30. messagefoundry/config/connections_edit.py +200 -0
  31. messagefoundry/config/connections_file.py +287 -0
  32. messagefoundry/config/db_lookup.py +117 -0
  33. messagefoundry/config/environments.py +116 -0
  34. messagefoundry/config/ingest_time.py +83 -0
  35. messagefoundry/config/models.py +240 -0
  36. messagefoundry/config/reference.py +158 -0
  37. messagefoundry/config/response.py +83 -0
  38. messagefoundry/config/run_context.py +153 -0
  39. messagefoundry/config/settings.py +1311 -0
  40. messagefoundry/config/state.py +99 -0
  41. messagefoundry/config/tls_policy.py +110 -0
  42. messagefoundry/config/wiring.py +1918 -0
  43. messagefoundry/console/__init__.py +20 -0
  44. messagefoundry/console/__main__.py +274 -0
  45. messagefoundry/console/_async.py +107 -0
  46. messagefoundry/console/change_password.py +111 -0
  47. messagefoundry/console/client.py +552 -0
  48. messagefoundry/console/connections.py +324 -0
  49. messagefoundry/console/login.py +107 -0
  50. messagefoundry/console/mfa.py +205 -0
  51. messagefoundry/console/reauth.py +94 -0
  52. messagefoundry/console/search.py +57 -0
  53. messagefoundry/console/service_control.py +137 -0
  54. messagefoundry/console/sessions.py +122 -0
  55. messagefoundry/console/shell.py +410 -0
  56. messagefoundry/console/status.py +377 -0
  57. messagefoundry/console/users_page.py +282 -0
  58. messagefoundry/console/widgets.py +553 -0
  59. messagefoundry/generators/README.md +27 -0
  60. messagefoundry/generators/__init__.py +15 -0
  61. messagefoundry/generators/_core.py +589 -0
  62. messagefoundry/generators/_hl7data.py +428 -0
  63. messagefoundry/generators/adt.py +286 -0
  64. messagefoundry/generators/all_types.py +24 -0
  65. messagefoundry/generators/bar.py +28 -0
  66. messagefoundry/generators/dft.py +20 -0
  67. messagefoundry/generators/mdm.py +39 -0
  68. messagefoundry/generators/mfn.py +46 -0
  69. messagefoundry/generators/oml.py +32 -0
  70. messagefoundry/generators/orl.py +30 -0
  71. messagefoundry/generators/orm.py +23 -0
  72. messagefoundry/generators/oru.py +21 -0
  73. messagefoundry/generators/ras.py +20 -0
  74. messagefoundry/generators/rde.py +54 -0
  75. messagefoundry/generators/siu.py +64 -0
  76. messagefoundry/generators/vxu.py +20 -0
  77. messagefoundry/hl7schema.py +75 -0
  78. messagefoundry/last_resort.py +55 -0
  79. messagefoundry/logging_setup.py +332 -0
  80. messagefoundry/parsing/__init__.py +64 -0
  81. messagefoundry/parsing/consistency.py +166 -0
  82. messagefoundry/parsing/groups.py +228 -0
  83. messagefoundry/parsing/message.py +453 -0
  84. messagefoundry/parsing/peek.py +237 -0
  85. messagefoundry/parsing/split.py +120 -0
  86. messagefoundry/parsing/summary.py +46 -0
  87. messagefoundry/parsing/tree.py +128 -0
  88. messagefoundry/parsing/validate.py +95 -0
  89. messagefoundry/parsing/x12/__init__.py +46 -0
  90. messagefoundry/parsing/x12/delimiters.py +140 -0
  91. messagefoundry/parsing/x12/errors.py +30 -0
  92. messagefoundry/parsing/x12/interchange.py +232 -0
  93. messagefoundry/parsing/x12/message.py +200 -0
  94. messagefoundry/parsing/x12/peek.py +207 -0
  95. messagefoundry/pipeline/__init__.py +21 -0
  96. messagefoundry/pipeline/alert_sinks.py +486 -0
  97. messagefoundry/pipeline/alerts.py +100 -0
  98. messagefoundry/pipeline/cert_expiry.py +219 -0
  99. messagefoundry/pipeline/cluster.py +955 -0
  100. messagefoundry/pipeline/cluster_sqlserver.py +444 -0
  101. messagefoundry/pipeline/config_convergence.py +137 -0
  102. messagefoundry/pipeline/dryrun.py +450 -0
  103. messagefoundry/pipeline/engine.py +756 -0
  104. messagefoundry/pipeline/leader_tasks.py +158 -0
  105. messagefoundry/pipeline/reference_sync.py +369 -0
  106. messagefoundry/pipeline/retention.py +289 -0
  107. messagefoundry/pipeline/security_notify.py +168 -0
  108. messagefoundry/pipeline/state_convergence.py +143 -0
  109. messagefoundry/pipeline/wiring_runner.py +1722 -0
  110. messagefoundry/py.typed +0 -0
  111. messagefoundry/redaction.py +71 -0
  112. messagefoundry/scaffold.py +321 -0
  113. messagefoundry/secrets_dpapi.py +129 -0
  114. messagefoundry/store/__init__.py +46 -0
  115. messagefoundry/store/audit_tee.py +67 -0
  116. messagefoundry/store/base.py +758 -0
  117. messagefoundry/store/crypto.py +166 -0
  118. messagefoundry/store/keyprovider.py +192 -0
  119. messagefoundry/store/postgres.py +3447 -0
  120. messagefoundry/store/sqlserver.py +3014 -0
  121. messagefoundry/store/store.py +3790 -0
  122. messagefoundry/timezone.py +207 -0
  123. messagefoundry/transports/__init__.py +50 -0
  124. messagefoundry/transports/base.py +269 -0
  125. messagefoundry/transports/database.py +693 -0
  126. messagefoundry/transports/file.py +551 -0
  127. messagefoundry/transports/framing.py +164 -0
  128. messagefoundry/transports/loopback.py +53 -0
  129. messagefoundry/transports/mllp.py +644 -0
  130. messagefoundry/transports/remotefile.py +664 -0
  131. messagefoundry/transports/rest.py +281 -0
  132. messagefoundry/transports/signing.py +321 -0
  133. messagefoundry/transports/soap.py +507 -0
  134. messagefoundry/transports/tcp.py +307 -0
  135. messagefoundry/transports/timer.py +146 -0
  136. messagefoundry/transports/x12.py +323 -0
  137. messagefoundry-0.1.0.dist-info/METADATA +212 -0
  138. messagefoundry-0.1.0.dist-info/RECORD +142 -0
  139. messagefoundry-0.1.0.dist-info/WHEEL +4 -0
  140. messagefoundry-0.1.0.dist-info/entry_points.txt +2 -0
  141. messagefoundry-0.1.0.dist-info/licenses/LICENSE +662 -0
  142. messagefoundry-0.1.0.dist-info/licenses/NOTICE +27 -0
@@ -0,0 +1,428 @@
1
+ # SPDX-License-Identifier: AGPL-3.0-or-later
2
+ # Copyright (C) 2026 MessageFoundry Organization and contributors
3
+ """HL7 v2.5.1 datatype encoders + synthetic data pools for the ADT generator.
4
+
5
+ This module is deliberately small and dependency-free: it knows how to render a handful
6
+ of HL7 *datatypes* (CX, XPN, XAD, XCN, PL, CWE, TS) as delimited strings, and it carries
7
+ pools of **fabricated** demographic/clinical values to draw from. Everything here is
8
+ synthetic test data — **no real PHI** (see CLAUDE.md §9).
9
+
10
+ The encoders take a *component* separator of ``^`` and never emit the field separator
11
+ ``|``; segment assembly (joining fields with ``|``) is the caller's job in ``adt.py``.
12
+ Table-coded values use codes that are valid for their HL7 table so the corpus is genuinely
13
+ conformant, not merely accepted by the validator.
14
+ """
15
+
16
+ from __future__ import annotations
17
+
18
+ from datetime import datetime
19
+
20
+ __all__ = [
21
+ "ts",
22
+ "date8",
23
+ "cx",
24
+ "xpn",
25
+ "xad",
26
+ "xcn",
27
+ "pl",
28
+ "cwe",
29
+ "ei",
30
+ "ORDER_CONTROLS",
31
+ "ORDER_STATUSES",
32
+ "TRANSACTION_TYPES",
33
+ "SERVICES",
34
+ "PROCEDURES",
35
+ "APPT_REASONS",
36
+ "SPECIMEN_TYPES",
37
+ "DOCUMENT_TYPES",
38
+ "DOC_STATUSES",
39
+ "VACCINES",
40
+ "ROUTES",
41
+ "INSURANCE_PLANS",
42
+ "INSURANCE_COMPANIES",
43
+ "MEDICATIONS",
44
+ "FAMILY_NAMES",
45
+ "GIVEN_NAMES",
46
+ "MIDDLE_INITIALS",
47
+ "STREETS",
48
+ "CITIES",
49
+ "SEXES",
50
+ "PATIENT_CLASSES",
51
+ "ADMIT_TYPES",
52
+ "HOSPITAL_SERVICES",
53
+ "POINTS_OF_CARE",
54
+ "ROOMS",
55
+ "BEDS",
56
+ "FACILITIES",
57
+ "SENDING_APPS",
58
+ "RECEIVING_APPS",
59
+ "CLINICIANS",
60
+ "RELATIONSHIPS",
61
+ "ALLERGENS",
62
+ "ALLERGY_SEVERITIES",
63
+ "DIAGNOSES",
64
+ "DIAGNOSIS_TYPES",
65
+ "OBSERVATIONS",
66
+ "BED_STATUSES",
67
+ "EVENT_REASONS",
68
+ ]
69
+
70
+
71
+ # --- datatype encoders -------------------------------------------------------
72
+
73
+
74
+ def ts(when: datetime) -> str:
75
+ """TS / DTM timestamp: ``YYYYMMDDHHMMSS``."""
76
+ return when.strftime("%Y%m%d%H%M%S")
77
+
78
+
79
+ def date8(when: datetime) -> str:
80
+ """DT date: ``YYYYMMDD`` (e.g. a birth date)."""
81
+ return when.strftime("%Y%m%d")
82
+
83
+
84
+ def cx(id_number: str, *, authority: str = "HOSP", id_type: str = "MR") -> str:
85
+ """CX identifier: ``ID^^^AssigningAuthority^IdentifierTypeCode`` (PID-3, MRG-1, …)."""
86
+ return f"{id_number}^^^{authority}^{id_type}"
87
+
88
+
89
+ def xpn(family: str, given: str, middle: str = "") -> str:
90
+ """XPN person name: ``Family^Given^Middle`` (PID-5, NK1-2)."""
91
+ return f"{family}^{given}^{middle}" if middle else f"{family}^{given}"
92
+
93
+
94
+ def xad(street: str, city: str, state: str, zip_code: str, country: str = "USA") -> str:
95
+ """XAD address: ``Street^^City^State^Zip^Country`` (PID-11)."""
96
+ return f"{street}^^{city}^{state}^{zip_code}^{country}"
97
+
98
+
99
+ def xcn(id_number: str, family: str, given: str) -> str:
100
+ """XCN provider: ``ID^Family^Given`` (PV1-7/8/17, attending/referring/admitting)."""
101
+ return f"{id_number}^{family}^{given}"
102
+
103
+
104
+ def pl(point_of_care: str, room: str, bed: str, facility: str = "MAIN") -> str:
105
+ """PL location: ``PointOfCare^Room^Bed^Facility`` (PV1-3, NPU-1)."""
106
+ return f"{point_of_care}^{room}^{bed}^{facility}"
107
+
108
+
109
+ def cwe(code: str, text: str, system: str) -> str:
110
+ """CWE coded element: ``Code^Text^CodingSystem`` (diagnoses, allergens, reasons)."""
111
+ return f"{code}^{text}^{system}"
112
+
113
+
114
+ def ei(entity_id: str, namespace: str = "HOSP") -> str:
115
+ """EI entity identifier: ``EntityID^NamespaceID`` (ORC/OBR placer & filler numbers)."""
116
+ return f"{entity_id}^{namespace}"
117
+
118
+
119
+ # --- synthetic pools (fabricated; no real PHI) -------------------------------
120
+
121
+ FAMILY_NAMES: tuple[str, ...] = (
122
+ "SMITH",
123
+ "JOHNSON",
124
+ "WILLIAMS",
125
+ "BROWN",
126
+ "JONES",
127
+ "GARCIA",
128
+ "MILLER",
129
+ "DAVIS",
130
+ "RODRIGUEZ",
131
+ "MARTINEZ",
132
+ "HERNANDEZ",
133
+ "LOPEZ",
134
+ "GONZALEZ",
135
+ "WILSON",
136
+ "ANDERSON",
137
+ "THOMAS",
138
+ "TAYLOR",
139
+ "MOORE",
140
+ "JACKSON",
141
+ "MARTIN",
142
+ "LEE",
143
+ "PEREZ",
144
+ "THOMPSON",
145
+ "WHITE",
146
+ "HARRIS",
147
+ "SANCHEZ",
148
+ "CLARK",
149
+ "RAMIREZ",
150
+ "LEWIS",
151
+ "ROBINSON",
152
+ "WALKER",
153
+ "NGUYEN",
154
+ "PATEL",
155
+ "KIM",
156
+ "OKAFOR",
157
+ "ROSSI",
158
+ )
159
+
160
+ GIVEN_NAMES: tuple[str, ...] = (
161
+ "JAMES",
162
+ "MARY",
163
+ "JOHN",
164
+ "PATRICIA",
165
+ "ROBERT",
166
+ "JENNIFER",
167
+ "MICHAEL",
168
+ "LINDA",
169
+ "WILLIAM",
170
+ "ELIZABETH",
171
+ "DAVID",
172
+ "BARBARA",
173
+ "RICHARD",
174
+ "SUSAN",
175
+ "JOSEPH",
176
+ "JESSICA",
177
+ "THOMAS",
178
+ "SARAH",
179
+ "CHARLES",
180
+ "KAREN",
181
+ "MARIA",
182
+ "DANIEL",
183
+ "NANCY",
184
+ "ANTHONY",
185
+ "LISA",
186
+ "MARK",
187
+ "BETTY",
188
+ "CARLOS",
189
+ "AISHA",
190
+ "WEI",
191
+ "PRIYA",
192
+ "OMAR",
193
+ "FATIMA",
194
+ "HIROSHI",
195
+ "INGRID",
196
+ "DMITRI",
197
+ )
198
+
199
+ MIDDLE_INITIALS: tuple[str, ...] = ("A", "B", "C", "D", "E", "J", "L", "M", "Q", "R", "T", "")
200
+
201
+ # street, city, state, zip
202
+ STREETS: tuple[str, ...] = (
203
+ "123 MAIN ST",
204
+ "456 OAK AVE",
205
+ "789 PINE RD",
206
+ "1010 MAPLE DR",
207
+ "222 CEDAR LN",
208
+ "55 BIRCH CT",
209
+ "9000 ELM BLVD",
210
+ "31 SPRUCE WAY",
211
+ "78 WILLOW TER",
212
+ "640 ASH PL",
213
+ "1200 LAKESHORE DR",
214
+ "88 SUNSET BLVD",
215
+ "417 RIVERSIDE DR",
216
+ "26 HILLCREST AVE",
217
+ )
218
+
219
+ # city, state, zip — kept consistent as a unit
220
+ CITIES: tuple[tuple[str, str, str], ...] = (
221
+ ("METROPOLIS", "IL", "60601"),
222
+ ("SPRINGFIELD", "IL", "62701"),
223
+ ("RIVERTON", "OH", "45011"),
224
+ ("FAIRVIEW", "TX", "75069"),
225
+ ("LAKEVILLE", "MN", "55044"),
226
+ ("GREENVILLE", "SC", "29601"),
227
+ ("CLAYTON", "MO", "63105"),
228
+ ("AURORA", "CO", "80010"),
229
+ ("BRISTOL", "CT", "06010"),
230
+ ("SALEM", "OR", "97301"),
231
+ )
232
+
233
+ SEXES: tuple[str, ...] = ("F", "M", "O", "U") # HL7 table 0001
234
+ PATIENT_CLASSES: tuple[str, ...] = ("I", "O", "E", "P", "R", "B") # table 0004
235
+ ADMIT_TYPES: tuple[str, ...] = ("A", "E", "L", "R", "N", "U", "C") # table 0007
236
+ HOSPITAL_SERVICES: tuple[str, ...] = ("MED", "SUR", "CAR", "PUL", "URO", "OBS", "PED", "ONC")
237
+ POINTS_OF_CARE: tuple[str, ...] = ("WARD", "ICU", "ER", "2W", "3E", "OR", "MATERNITY")
238
+ ROOMS: tuple[str, ...] = ("101", "102", "210", "305", "412", "A11", "B22", "C30")
239
+ BEDS: tuple[str, ...] = ("A", "B", "1", "2", "W")
240
+ FACILITIES: tuple[str, ...] = ("MAIN", "NORTH", "SOUTH", "WESTCAMPUS")
241
+ SENDING_APPS: tuple[tuple[str, str], ...] = (
242
+ ("ADT", "MAINHOSP"),
243
+ ("REGISTRATION", "NORTHCLINIC"),
244
+ ("EHR", "SOUTHHOSP"),
245
+ ("HIS", "WESTMED"),
246
+ )
247
+ RECEIVING_APPS: tuple[tuple[str, str], ...] = (
248
+ ("MESSAGEFOUNDRY", "INTEGRATION"),
249
+ ("LAB", "MAINHOSP"),
250
+ ("PHARMACY", "MAINHOSP"),
251
+ )
252
+
253
+ # id, family, given
254
+ CLINICIANS: tuple[tuple[str, str, str], ...] = (
255
+ ("1001", "SMITH", "JOHN"),
256
+ ("1002", "PATEL", "ANJALI"),
257
+ ("1003", "NGUYEN", "TRAN"),
258
+ ("1004", "OKAFOR", "CHIDI"),
259
+ ("1005", "ROSSI", "GIULIA"),
260
+ ("1006", "KIM", "SOOJIN"),
261
+ ("1007", "GARCIA", "MIGUEL"),
262
+ ("1008", "WALKER", "DENISE"),
263
+ )
264
+
265
+ # code, text (HL7 table 0063 relationship)
266
+ RELATIONSHIPS: tuple[tuple[str, str], ...] = (
267
+ ("SPO", "Spouse"),
268
+ ("CHD", "Child"),
269
+ ("PAR", "Parent"),
270
+ ("SIB", "Sibling"),
271
+ ("FND", "Friend"),
272
+ ("GRD", "Guardian"),
273
+ ("EME", "Employer"),
274
+ )
275
+
276
+ # code, text (allergen mnemonic — AL1-3 / IAM-3)
277
+ ALLERGENS: tuple[tuple[str, str], ...] = (
278
+ ("PCN", "Penicillin"),
279
+ ("SULFA", "Sulfa drugs"),
280
+ ("ASA", "Aspirin"),
281
+ ("LATEX", "Latex"),
282
+ ("PEANUT", "Peanuts"),
283
+ ("CODEINE", "Codeine"),
284
+ ("SHELLFISH", "Shellfish"),
285
+ ("IODINE", "Iodine"),
286
+ )
287
+
288
+ # code, text (HL7 table 0128 allergy severity)
289
+ ALLERGY_SEVERITIES: tuple[tuple[str, str], ...] = (
290
+ ("SV", "Severe"),
291
+ ("MO", "Moderate"),
292
+ ("MI", "Mild"),
293
+ )
294
+
295
+ # code, text (ICD-10-CM diagnoses — DG1-3)
296
+ DIAGNOSES: tuple[tuple[str, str], ...] = (
297
+ ("I10", "Essential hypertension"),
298
+ ("E11.9", "Type 2 diabetes mellitus"),
299
+ ("J45.909", "Unspecified asthma"),
300
+ ("N39.0", "Urinary tract infection"),
301
+ ("M54.5", "Low back pain"),
302
+ ("R07.9", "Chest pain unspecified"),
303
+ ("K21.9", "Gastro-esophageal reflux disease"),
304
+ ("F41.1", "Generalized anxiety disorder"),
305
+ ("S52.501A", "Fracture of right radius"),
306
+ ("A09", "Infectious gastroenteritis"),
307
+ )
308
+
309
+ DIAGNOSIS_TYPES: tuple[str, ...] = ("A", "W", "F") # admitting / working / final (table 0052)
310
+
311
+ # code, text, value-type, value, units (OBX vitals)
312
+ OBSERVATIONS: tuple[tuple[str, str, str, str, str], ...] = (
313
+ ("8302-2", "Body height", "NM", "170", "cm"),
314
+ ("29463-7", "Body weight", "NM", "72", "kg"),
315
+ ("8480-6", "Systolic blood pressure", "NM", "128", "mm[Hg]"),
316
+ ("8462-4", "Diastolic blood pressure", "NM", "82", "mm[Hg]"),
317
+ ("8867-4", "Heart rate", "NM", "76", "/min"),
318
+ ("8310-5", "Body temperature", "NM", "37.0", "Cel"),
319
+ )
320
+
321
+ # code, text (HL7 table 0116 bed status — NPU-2)
322
+ BED_STATUSES: tuple[tuple[str, str], ...] = (
323
+ ("C", "Closed"),
324
+ ("H", "Housekeeping"),
325
+ ("O", "Occupied"),
326
+ ("U", "Unoccupied"),
327
+ ("K", "Contaminated"),
328
+ ("I", "Isolated"),
329
+ )
330
+
331
+ # code, text (event reason — EVN-4, free use of a local table)
332
+ EVENT_REASONS: tuple[tuple[str, str], ...] = (
333
+ ("01", "Patient request"),
334
+ ("02", "Physician order"),
335
+ ("03", "Census management"),
336
+ ("", "Routine"),
337
+ )
338
+
339
+ # --- orders / results / financials / scheduling ------------------------------
340
+
341
+ ORDER_CONTROLS: tuple[str, ...] = ("NW", "OK", "SC", "CA", "XO", "CM") # table 0119
342
+ ORDER_STATUSES: tuple[str, ...] = ("A", "CM", "IP", "SC", "CA") # table 0038
343
+ TRANSACTION_TYPES: tuple[str, ...] = ("CG", "CD", "RA") # table 0017 (charge/credit/adjust)
344
+
345
+ # code, text (orderable services / observation identifiers — OBR-4 / AIS-3, LOINC-ish)
346
+ SERVICES: tuple[tuple[str, str], ...] = (
347
+ ("24331-1", "Lipid panel"),
348
+ ("57021-8", "CBC with differential"),
349
+ ("2345-7", "Glucose"),
350
+ ("2951-2", "Sodium"),
351
+ ("718-7", "Hemoglobin"),
352
+ ("24362-6", "Renal panel"),
353
+ ("30341-2", "Erythrocyte sedimentation rate"),
354
+ )
355
+
356
+ # code, text (procedure / charge codes — FT1-7, CPT-ish)
357
+ PROCEDURES: tuple[tuple[str, str], ...] = (
358
+ ("99213", "Office visit, established"),
359
+ ("36415", "Venipuncture"),
360
+ ("80053", "Comprehensive metabolic panel"),
361
+ ("71046", "Chest X-ray, 2 views"),
362
+ ("93000", "Electrocardiogram"),
363
+ ("85025", "Complete blood count"),
364
+ )
365
+
366
+ # code, text (appointment reason — SCH-6, local table)
367
+ APPT_REASONS: tuple[tuple[str, str], ...] = (
368
+ ("ROUTINE", "Routine"),
369
+ ("FOLLOWUP", "Follow-up"),
370
+ ("URGENT", "Urgent"),
371
+ ("CONSULT", "Consultation"),
372
+ )
373
+
374
+ # code, text (specimen type — SPM-4, HL7 table 0487)
375
+ SPECIMEN_TYPES: tuple[tuple[str, str], ...] = (
376
+ ("BLD", "Whole blood"),
377
+ ("SER", "Serum"),
378
+ ("UR", "Urine"),
379
+ ("PLAS", "Plasma"),
380
+ ("CSF", "Cerebrospinal fluid"),
381
+ )
382
+
383
+ DOCUMENT_TYPES: tuple[str, ...] = ("DS", "CN", "HP", "OP", "PN", "CD") # table 0270
384
+ DOC_STATUSES: tuple[str, ...] = ("AU", "DO", "IP", "LA") # table 0271 completion status
385
+
386
+ # code, text (vaccine — RXA-5, CVX codes)
387
+ VACCINES: tuple[tuple[str, str], ...] = (
388
+ ("08", "Hepatitis B"),
389
+ ("20", "DTaP"),
390
+ ("03", "MMR"),
391
+ ("21", "Varicella"),
392
+ ("88", "Influenza"),
393
+ ("207", "COVID-19 mRNA"),
394
+ )
395
+
396
+ # code, text (route of administration — RXR-1, HL7 table 0162)
397
+ ROUTES: tuple[tuple[str, str], ...] = (
398
+ ("IM", "Intramuscular"),
399
+ ("SC", "Subcutaneous"),
400
+ ("PO", "Oral"),
401
+ ("IV", "Intravenous"),
402
+ ("IN", "Intranasal"),
403
+ )
404
+
405
+ # code, text (insurance plan — IN1-2, local table)
406
+ INSURANCE_PLANS: tuple[tuple[str, str], ...] = (
407
+ ("PPO", "Preferred Provider Organization"),
408
+ ("HMO", "Health Maintenance Organization"),
409
+ ("MCR", "Medicare"),
410
+ ("MCD", "Medicaid"),
411
+ )
412
+
413
+ # id, name (insurance company — IN1-3 / IN1-4)
414
+ INSURANCE_COMPANIES: tuple[tuple[str, str], ...] = (
415
+ ("INS001", "BlueCross"),
416
+ ("INS002", "Aetna"),
417
+ ("INS003", "UnitedHealth"),
418
+ ("INS004", "Cigna"),
419
+ )
420
+
421
+ # code, text (medication — RXE-2 give code, RxNorm-ish)
422
+ MEDICATIONS: tuple[tuple[str, str], ...] = (
423
+ ("197361", "Amoxicillin 500 mg oral capsule"),
424
+ ("310965", "Ibuprofen 200 mg oral tablet"),
425
+ ("314076", "Lisinopril 10 mg oral tablet"),
426
+ ("198211", "Metformin 500 mg oral tablet"),
427
+ ("313782", "Atorvastatin 20 mg oral tablet"),
428
+ )