medicafe 0.250728.8__py3-none-any.whl → 0.250805.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 medicafe might be problematic. Click here for more details.
- MediBot/MediBot.bat +233 -19
- MediBot/MediBot.py +138 -46
- MediBot/MediBot_Crosswalk_Library.py +127 -623
- MediBot/MediBot_Crosswalk_Utils.py +618 -0
- MediBot/MediBot_Preprocessor.py +72 -17
- MediBot/MediBot_Preprocessor_lib.py +470 -76
- MediBot/MediBot_UI.py +32 -17
- MediBot/MediBot_dataformat_library.py +68 -20
- MediBot/MediBot_docx_decoder.py +120 -19
- MediBot/MediBot_smart_import.py +180 -0
- MediBot/__init__.py +89 -0
- MediBot/get_medicafe_version.py +25 -0
- MediBot/update_json.py +35 -6
- MediBot/update_medicafe.py +19 -1
- MediCafe/MediLink_ConfigLoader.py +160 -0
- MediCafe/__init__.py +171 -0
- MediCafe/__main__.py +222 -0
- MediCafe/api_core.py +1098 -0
- MediCafe/api_core_backup.py +427 -0
- MediCafe/api_factory.py +306 -0
- MediCafe/api_utils.py +356 -0
- MediCafe/core_utils.py +450 -0
- MediCafe/graphql_utils.py +445 -0
- MediCafe/logging_config.py +123 -0
- MediCafe/logging_demo.py +61 -0
- MediCafe/migration_helpers.py +463 -0
- MediCafe/smart_import.py +436 -0
- MediLink/MediLink.py +66 -26
- MediLink/MediLink_837p_cob_library.py +28 -28
- MediLink/MediLink_837p_encoder.py +33 -34
- MediLink/MediLink_837p_encoder_library.py +243 -151
- MediLink/MediLink_837p_utilities.py +129 -5
- MediLink/MediLink_API_Generator.py +83 -60
- MediLink/MediLink_API_v3.py +1 -1
- MediLink/MediLink_ClaimStatus.py +177 -31
- MediLink/MediLink_DataMgmt.py +405 -72
- MediLink/MediLink_Decoder.py +20 -1
- MediLink/MediLink_Deductible.py +155 -28
- MediLink/MediLink_Display_Utils.py +72 -0
- MediLink/MediLink_Down.py +127 -5
- MediLink/MediLink_Gmail.py +712 -653
- MediLink/MediLink_PatientProcessor.py +257 -0
- MediLink/MediLink_UI.py +85 -61
- MediLink/MediLink_Up.py +28 -4
- MediLink/MediLink_insurance_utils.py +227 -264
- MediLink/MediLink_main.py +248 -0
- MediLink/MediLink_smart_import.py +264 -0
- MediLink/__init__.py +93 -0
- MediLink/insurance_type_integration_test.py +66 -76
- MediLink/test.py +1 -1
- MediLink/test_timing.py +59 -0
- {medicafe-0.250728.8.dist-info → medicafe-0.250805.0.dist-info}/METADATA +1 -1
- medicafe-0.250805.0.dist-info/RECORD +81 -0
- medicafe-0.250805.0.dist-info/entry_points.txt +2 -0
- {medicafe-0.250728.8.dist-info → medicafe-0.250805.0.dist-info}/top_level.txt +1 -0
- medicafe-0.250728.8.dist-info/RECORD +0 -59
- {medicafe-0.250728.8.dist-info → medicafe-0.250805.0.dist-info}/LICENSE +0 -0
- {medicafe-0.250728.8.dist-info → medicafe-0.250805.0.dist-info}/WHEEL +0 -0
MediCafe/smart_import.py
ADDED
|
@@ -0,0 +1,436 @@
|
|
|
1
|
+
"""
|
|
2
|
+
MediCafe Smart Import System
|
|
3
|
+
|
|
4
|
+
This module provides intelligent import management for the entire MediCafe ecosystem,
|
|
5
|
+
allowing MediBot and MediLink modules to request components without worrying about
|
|
6
|
+
circular imports or complex dependency management.
|
|
7
|
+
|
|
8
|
+
Usage Examples:
|
|
9
|
+
# Simple component requests
|
|
10
|
+
from MediCafe.smart_import import get_components
|
|
11
|
+
api_core, logging_config = get_components('api_core', 'logging_config')
|
|
12
|
+
|
|
13
|
+
# Get everything for a specific module type
|
|
14
|
+
from MediCafe.smart_import import setup_for_medibot
|
|
15
|
+
components = setup_for_medibot('preprocessor')
|
|
16
|
+
|
|
17
|
+
# Use components
|
|
18
|
+
api_core = components['api_core']
|
|
19
|
+
logging = components['logging_config']
|
|
20
|
+
|
|
21
|
+
# Get API suite for any module
|
|
22
|
+
from MediCafe.smart_import import get_api_access
|
|
23
|
+
api_suite = get_api_access()
|
|
24
|
+
"""
|
|
25
|
+
|
|
26
|
+
import sys
|
|
27
|
+
import importlib
|
|
28
|
+
import inspect
|
|
29
|
+
# from typing import Any, Dict, List, Optional, Union, Tuple, Set # Removed for Python 3.4.4 compatibility
|
|
30
|
+
# from functools import lru_cache # Removed as not used
|
|
31
|
+
import threading
|
|
32
|
+
# from pathlib import Path # Replaced with os.path for Python 3.4.4 compatibility
|
|
33
|
+
import os
|
|
34
|
+
import warnings
|
|
35
|
+
|
|
36
|
+
# Define typing aliases for Python 3.4.4 compatibility
|
|
37
|
+
try:
|
|
38
|
+
from typing import Any, Dict, List, Optional, Union, Tuple, Set
|
|
39
|
+
except ImportError:
|
|
40
|
+
# Python 3.4.4 compatibility - define as object
|
|
41
|
+
Any = object
|
|
42
|
+
Dict = dict
|
|
43
|
+
List = list
|
|
44
|
+
Optional = object
|
|
45
|
+
Union = object
|
|
46
|
+
Tuple = tuple
|
|
47
|
+
Set = set
|
|
48
|
+
|
|
49
|
+
class ComponentRegistry:
|
|
50
|
+
"""Registry for managing all available components and their dependencies."""
|
|
51
|
+
|
|
52
|
+
def __init__(self):
|
|
53
|
+
self._components = {}
|
|
54
|
+
self._modules = {}
|
|
55
|
+
self._dependencies = {}
|
|
56
|
+
self._loading_stack = []
|
|
57
|
+
self._lock = threading.RLock()
|
|
58
|
+
self._module_configs = {}
|
|
59
|
+
self._failed_loads = set()
|
|
60
|
+
|
|
61
|
+
def register_component(self, name, component, dependencies=None):
|
|
62
|
+
"""Register a component with optional dependencies."""
|
|
63
|
+
with self._lock:
|
|
64
|
+
self._components[name] = component
|
|
65
|
+
self._dependencies[name] = dependencies or []
|
|
66
|
+
|
|
67
|
+
def register_module_config(self, module_name, config):
|
|
68
|
+
"""Register configuration for a specific module's needs."""
|
|
69
|
+
self._module_configs[module_name] = config
|
|
70
|
+
|
|
71
|
+
def get_component(self, name, silent_fail=False):
|
|
72
|
+
"""Get a component, loading it if necessary."""
|
|
73
|
+
with self._lock:
|
|
74
|
+
# Return cached component if available
|
|
75
|
+
if name in self._components:
|
|
76
|
+
return self._components[name]
|
|
77
|
+
|
|
78
|
+
# Skip if previously failed and silent_fail is True
|
|
79
|
+
if silent_fail and name in self._failed_loads:
|
|
80
|
+
return None
|
|
81
|
+
|
|
82
|
+
# Check for circular imports
|
|
83
|
+
if name in self._loading_stack:
|
|
84
|
+
error_msg = "Circular import detected: {} -> {}".format(' -> '.join(self._loading_stack), name)
|
|
85
|
+
if silent_fail:
|
|
86
|
+
warnings.warn(error_msg)
|
|
87
|
+
return None
|
|
88
|
+
raise ImportError(error_msg)
|
|
89
|
+
|
|
90
|
+
self._loading_stack.append(name)
|
|
91
|
+
try:
|
|
92
|
+
component = self._load_component(name)
|
|
93
|
+
self._components[name] = component
|
|
94
|
+
return component
|
|
95
|
+
except ImportError as e:
|
|
96
|
+
self._failed_loads.add(name)
|
|
97
|
+
if silent_fail:
|
|
98
|
+
return None
|
|
99
|
+
raise e
|
|
100
|
+
finally:
|
|
101
|
+
if name in self._loading_stack:
|
|
102
|
+
self._loading_stack.remove(name)
|
|
103
|
+
|
|
104
|
+
def _load_component(self, name: str) -> Any:
|
|
105
|
+
"""Load a component dynamically."""
|
|
106
|
+
# Component loading mappings
|
|
107
|
+
component_mappings = {
|
|
108
|
+
# MediCafe core components
|
|
109
|
+
'api_core': 'MediCafe.api_core',
|
|
110
|
+
'api_factory': 'MediCafe.api_factory',
|
|
111
|
+
'api_utils': 'MediCafe.api_utils',
|
|
112
|
+
'core_utils': 'MediCafe.core_utils',
|
|
113
|
+
'graphql_utils': 'MediCafe.graphql_utils',
|
|
114
|
+
'logging_config': 'MediCafe.logging_config',
|
|
115
|
+
'medicafe_config_loader': 'MediCafe.MediLink_ConfigLoader',
|
|
116
|
+
|
|
117
|
+
# MediBot components
|
|
118
|
+
'medibot_main': 'MediBot.MediBot',
|
|
119
|
+
'medibot_preprocessor': 'MediBot.MediBot_Preprocessor',
|
|
120
|
+
'medibot_preprocessor_lib': 'MediBot.MediBot_Preprocessor_lib',
|
|
121
|
+
'medibot_crosswalk_library': 'MediBot.MediBot_Crosswalk_Library',
|
|
122
|
+
'medibot_crosswalk_utils': 'MediBot.MediBot_Crosswalk_Utils',
|
|
123
|
+
'medibot_dataformat_library': 'MediBot.MediBot_dataformat_library',
|
|
124
|
+
'medibot_docx_decoder': 'MediBot.MediBot_docx_decoder',
|
|
125
|
+
'medibot_ui': 'MediBot.MediBot_UI',
|
|
126
|
+
'medibot_charges': 'MediBot.MediBot_Charges',
|
|
127
|
+
'medibot_post': 'MediBot.MediBot_Post',
|
|
128
|
+
'get_medicafe_version': 'MediBot.get_medicafe_version',
|
|
129
|
+
'update_medicafe': 'MediBot.update_medicafe',
|
|
130
|
+
'update_json': 'MediBot.update_json',
|
|
131
|
+
|
|
132
|
+
# MediLink components
|
|
133
|
+
'medilink_main': 'MediLink.MediLink_main',
|
|
134
|
+
'medilink_azure': 'MediLink.MediLink_Azure',
|
|
135
|
+
'medilink_claim_status': 'MediLink.MediLink_ClaimStatus',
|
|
136
|
+
'medilink_datamgmt': 'MediLink.MediLink_DataMgmt',
|
|
137
|
+
'medilink_decoder': 'MediLink.MediLink_Decoder',
|
|
138
|
+
'medilink_deductible': 'MediLink.MediLink_Deductible',
|
|
139
|
+
'medilink_deductible_validator': 'MediLink.MediLink_Deductible_Validator',
|
|
140
|
+
'medilink_display_utils': 'MediLink.MediLink_Display_Utils',
|
|
141
|
+
'medilink_down': 'MediLink.MediLink_Down',
|
|
142
|
+
'medilink_gmail': 'MediLink.MediLink_Gmail',
|
|
143
|
+
'medilink_mailer': 'MediLink.MediLink_Mailer',
|
|
144
|
+
'medilink_parser': 'MediLink.MediLink_Parser',
|
|
145
|
+
'medilink_patient_processor': 'MediLink.MediLink_PatientProcessor',
|
|
146
|
+
'medilink_scan': 'MediLink.MediLink_Scan',
|
|
147
|
+
'medilink_scheduler': 'MediLink.MediLink_Scheduler',
|
|
148
|
+
'medilink_ui': 'MediLink.MediLink_UI',
|
|
149
|
+
'medilink_up': 'MediLink.MediLink_Up',
|
|
150
|
+
'medilink_insurance_utils': 'MediLink.MediLink_insurance_utils',
|
|
151
|
+
'medilink_837p_cob_library': 'MediLink.MediLink_837p_cob_library',
|
|
152
|
+
'medilink_837p_encoder': 'MediLink.MediLink_837p_encoder',
|
|
153
|
+
'medilink_837p_encoder_library': 'MediLink.MediLink_837p_encoder_library',
|
|
154
|
+
'medilink_837p_utilities': 'MediLink.MediLink_837p_utilities',
|
|
155
|
+
'medilink_api_generator': 'MediLink.MediLink_API_Generator',
|
|
156
|
+
'soumit_api': 'MediLink.Soumit_api',
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
if name not in component_mappings:
|
|
160
|
+
raise ImportError("Unknown component: {}. Available components: {}".format(name, list(component_mappings.keys())))
|
|
161
|
+
|
|
162
|
+
module_path = component_mappings[name]
|
|
163
|
+
try:
|
|
164
|
+
module = importlib.import_module(module_path)
|
|
165
|
+
return module
|
|
166
|
+
except ImportError as e:
|
|
167
|
+
raise ImportError("Failed to load component '{}' from '{}': {}".format(name, module_path, e))
|
|
168
|
+
|
|
169
|
+
# Global registry instance
|
|
170
|
+
_registry = ComponentRegistry()
|
|
171
|
+
|
|
172
|
+
class ComponentProvider:
|
|
173
|
+
"""Main interface for requesting components."""
|
|
174
|
+
|
|
175
|
+
def __init__(self, registry: ComponentRegistry):
|
|
176
|
+
self.registry = registry
|
|
177
|
+
self._setup_module_configs()
|
|
178
|
+
|
|
179
|
+
def _setup_module_configs(self):
|
|
180
|
+
"""Setup predefined configurations for known module types."""
|
|
181
|
+
configs = {
|
|
182
|
+
# MediBot configurations
|
|
183
|
+
'medibot_preprocessor': {
|
|
184
|
+
'core_dependencies': ['api_core', 'logging_config', 'core_utils'],
|
|
185
|
+
'optional_dependencies': ['api_factory', 'api_utils'],
|
|
186
|
+
'shared_resources': ['medibot_dataformat_library', 'medibot_crosswalk_utils']
|
|
187
|
+
},
|
|
188
|
+
'medibot_ui': {
|
|
189
|
+
'core_dependencies': ['medibot_main', 'logging_config'],
|
|
190
|
+
'optional_dependencies': ['core_utils', 'api_core'],
|
|
191
|
+
'shared_resources': ['medibot_preprocessor', 'medibot_crosswalk_library']
|
|
192
|
+
},
|
|
193
|
+
'medibot_crosswalk': {
|
|
194
|
+
'core_dependencies': ['logging_config', 'core_utils'],
|
|
195
|
+
'optional_dependencies': ['api_core'],
|
|
196
|
+
'shared_resources': ['medibot_crosswalk_library', 'medibot_crosswalk_utils', 'medibot_dataformat_library']
|
|
197
|
+
},
|
|
198
|
+
'medibot_document_processing': {
|
|
199
|
+
'core_dependencies': ['logging_config', 'core_utils'],
|
|
200
|
+
'optional_dependencies': ['api_core'],
|
|
201
|
+
'shared_resources': ['medibot_docx_decoder', 'medibot_preprocessor_lib']
|
|
202
|
+
},
|
|
203
|
+
|
|
204
|
+
# MediLink configurations
|
|
205
|
+
'medilink_main': {
|
|
206
|
+
'core_dependencies': ['api_core', 'logging_config', 'core_utils'],
|
|
207
|
+
'optional_dependencies': ['api_factory', 'graphql_utils'],
|
|
208
|
+
'shared_resources': ['medilink_datamgmt', 'medilink_parser']
|
|
209
|
+
},
|
|
210
|
+
'medilink_claim_processing': {
|
|
211
|
+
'core_dependencies': ['api_core', 'logging_config', 'medilink_datamgmt'],
|
|
212
|
+
'optional_dependencies': ['graphql_utils', 'api_utils'],
|
|
213
|
+
'shared_resources': ['medilink_837p_encoder', 'medilink_837p_utilities', 'medilink_claim_status']
|
|
214
|
+
},
|
|
215
|
+
'medilink_deductible_processing': {
|
|
216
|
+
'core_dependencies': ['api_core', 'logging_config', 'medilink_datamgmt'],
|
|
217
|
+
'optional_dependencies': ['graphql_utils'],
|
|
218
|
+
'shared_resources': ['medilink_deductible', 'medilink_deductible_validator', 'medilink_insurance_utils']
|
|
219
|
+
},
|
|
220
|
+
'medilink_communication': {
|
|
221
|
+
'core_dependencies': ['logging_config', 'core_utils'],
|
|
222
|
+
'optional_dependencies': ['api_core'],
|
|
223
|
+
'shared_resources': ['medilink_gmail', 'medilink_mailer', 'medilink_display_utils']
|
|
224
|
+
},
|
|
225
|
+
'medilink_data_management': {
|
|
226
|
+
'core_dependencies': ['api_core', 'logging_config'],
|
|
227
|
+
'optional_dependencies': ['graphql_utils'],
|
|
228
|
+
'shared_resources': ['medilink_datamgmt', 'medilink_up', 'medilink_down', 'medilink_parser']
|
|
229
|
+
},
|
|
230
|
+
|
|
231
|
+
# General configurations
|
|
232
|
+
'general_api_access': {
|
|
233
|
+
'core_dependencies': ['api_core', 'api_factory'],
|
|
234
|
+
'optional_dependencies': ['api_utils', 'graphql_utils'],
|
|
235
|
+
'shared_resources': ['logging_config', 'core_utils']
|
|
236
|
+
},
|
|
237
|
+
'logging_only': {
|
|
238
|
+
'core_dependencies': ['logging_config'],
|
|
239
|
+
'optional_dependencies': [],
|
|
240
|
+
'shared_resources': []
|
|
241
|
+
},
|
|
242
|
+
'utilities_only': {
|
|
243
|
+
'core_dependencies': ['core_utils'],
|
|
244
|
+
'optional_dependencies': ['api_utils'],
|
|
245
|
+
'shared_resources': ['logging_config']
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
for module_name, config in configs.items():
|
|
250
|
+
self.registry.register_module_config(module_name, config)
|
|
251
|
+
|
|
252
|
+
def __call__(self, *component_names, **kwargs):
|
|
253
|
+
"""Get one or more components by name."""
|
|
254
|
+
silent_fail = kwargs.get('silent_fail', False)
|
|
255
|
+
if len(component_names) == 1:
|
|
256
|
+
return self.registry.get_component(component_names[0], silent_fail=silent_fail)
|
|
257
|
+
|
|
258
|
+
results = []
|
|
259
|
+
for name in component_names:
|
|
260
|
+
component = self.registry.get_component(name, silent_fail=silent_fail)
|
|
261
|
+
results.append(component)
|
|
262
|
+
return tuple(results)
|
|
263
|
+
|
|
264
|
+
def for_module(self, module_type: str, silent_fail: bool = False) -> Dict[str, Any]:
|
|
265
|
+
"""Get all components needed for a specific module type."""
|
|
266
|
+
if module_type not in self.registry._module_configs:
|
|
267
|
+
available_types = list(self.registry._module_configs.keys())
|
|
268
|
+
raise ValueError("Unknown module type: {}. Available types: {}".format(module_type, available_types))
|
|
269
|
+
|
|
270
|
+
config = self.registry._module_configs[module_type]
|
|
271
|
+
components = {}
|
|
272
|
+
|
|
273
|
+
# Load core dependencies (these must succeed unless silent_fail is True)
|
|
274
|
+
for dep in config.get('core_dependencies', []):
|
|
275
|
+
component = self.registry.get_component(dep, silent_fail=silent_fail)
|
|
276
|
+
if component is not None:
|
|
277
|
+
components[dep] = component
|
|
278
|
+
|
|
279
|
+
# Load optional dependencies (always fail silently)
|
|
280
|
+
for dep in config.get('optional_dependencies', []):
|
|
281
|
+
try:
|
|
282
|
+
component = self.registry.get_component(dep, silent_fail=True)
|
|
283
|
+
if component is not None:
|
|
284
|
+
components[dep] = component
|
|
285
|
+
except ImportError:
|
|
286
|
+
pass
|
|
287
|
+
|
|
288
|
+
# Load shared resources (always fail silently)
|
|
289
|
+
for dep in config.get('shared_resources', []):
|
|
290
|
+
try:
|
|
291
|
+
component = self.registry.get_component(dep, silent_fail=True)
|
|
292
|
+
if component is not None:
|
|
293
|
+
components[dep] = component
|
|
294
|
+
except ImportError:
|
|
295
|
+
pass
|
|
296
|
+
|
|
297
|
+
return components
|
|
298
|
+
|
|
299
|
+
def get_api_suite(self) -> Dict[str, Any]:
|
|
300
|
+
"""Get the complete API access suite."""
|
|
301
|
+
return self.for_module('general_api_access')
|
|
302
|
+
|
|
303
|
+
def get_medibot_suite(self, module_type: str = 'medibot_preprocessor') -> Dict[str, Any]:
|
|
304
|
+
"""Get components specifically for MediBot operations."""
|
|
305
|
+
return self.for_module(module_type)
|
|
306
|
+
|
|
307
|
+
def get_medilink_suite(self, module_type: str = 'medilink_main') -> Dict[str, Any]:
|
|
308
|
+
"""Get components specifically for MediLink operations."""
|
|
309
|
+
return self.for_module(module_type)
|
|
310
|
+
|
|
311
|
+
def list_available_components(self) -> List[str]:
|
|
312
|
+
"""List all available component names."""
|
|
313
|
+
# Get component mappings from registry's _load_component method
|
|
314
|
+
component_mappings = {
|
|
315
|
+
'api_core', 'api_factory', 'api_utils', 'core_utils', 'graphql_utils', 'logging_config',
|
|
316
|
+
'medicafe_config_loader', 'medibot_main', 'medibot_preprocessor', 'medibot_preprocessor_lib',
|
|
317
|
+
'medibot_crosswalk_library', 'medibot_crosswalk_utils', 'medibot_dataformat_library',
|
|
318
|
+
'medibot_docx_decoder', 'medibot_ui', 'medibot_charges', 'medibot_post',
|
|
319
|
+
'get_medicafe_version', 'update_medicafe', 'update_json', 'medilink_main',
|
|
320
|
+
'medilink_azure', 'medilink_claim_status', 'medilink_datamgmt', 'medilink_decoder',
|
|
321
|
+
'medilink_deductible', 'medilink_deductible_validator', 'medilink_display_utils',
|
|
322
|
+
'medilink_down', 'medilink_gmail', 'medilink_mailer', 'medilink_parser',
|
|
323
|
+
'medilink_patient_processor', 'medilink_scan', 'medilink_scheduler', 'medilink_ui',
|
|
324
|
+
'medilink_up', 'medilink_insurance_utils', 'medilink_837p_cob_library',
|
|
325
|
+
'medilink_837p_encoder', 'medilink_837p_encoder_library', 'medilink_837p_utilities',
|
|
326
|
+
'medilink_api_generator', 'soumit_api'
|
|
327
|
+
}
|
|
328
|
+
return sorted(list(component_mappings))
|
|
329
|
+
|
|
330
|
+
def list_available_module_types(self) -> List[str]:
|
|
331
|
+
"""List all available module type configurations."""
|
|
332
|
+
return sorted(list(self.registry._module_configs.keys()))
|
|
333
|
+
|
|
334
|
+
# Global component provider
|
|
335
|
+
get_components = ComponentProvider(_registry)
|
|
336
|
+
|
|
337
|
+
# Convenience functions for common use cases
|
|
338
|
+
def get_api_access():
|
|
339
|
+
"""Get standard API access components."""
|
|
340
|
+
return get_components.get_api_suite()
|
|
341
|
+
|
|
342
|
+
def get_logging():
|
|
343
|
+
"""Get logging configuration."""
|
|
344
|
+
return get_components('logging_config')
|
|
345
|
+
|
|
346
|
+
def get_core_utils():
|
|
347
|
+
"""Get core utilities."""
|
|
348
|
+
return get_components('core_utils')
|
|
349
|
+
|
|
350
|
+
def setup_for_medibot(module_type: str = 'medibot_preprocessor'):
|
|
351
|
+
"""Setup everything needed for MediBot operations."""
|
|
352
|
+
return get_components.get_medibot_suite(module_type)
|
|
353
|
+
|
|
354
|
+
def setup_for_medilink(module_type: str = 'medilink_main'):
|
|
355
|
+
"""Setup everything needed for MediLink operations."""
|
|
356
|
+
return get_components.get_medilink_suite(module_type)
|
|
357
|
+
|
|
358
|
+
# Helper functions for discovery
|
|
359
|
+
def list_components():
|
|
360
|
+
"""List all available component names."""
|
|
361
|
+
return get_components.list_available_components()
|
|
362
|
+
|
|
363
|
+
def list_module_types():
|
|
364
|
+
"""List all available module type configurations."""
|
|
365
|
+
return get_components.list_available_module_types()
|
|
366
|
+
|
|
367
|
+
def describe_module_type(module_type: str):
|
|
368
|
+
"""Describe what components a module type provides."""
|
|
369
|
+
if module_type in _registry._module_configs:
|
|
370
|
+
config = _registry._module_configs[module_type]
|
|
371
|
+
print("Module Type: {}".format(module_type))
|
|
372
|
+
print("Core Dependencies: {}".format(config.get('core_dependencies', [])))
|
|
373
|
+
print("Optional Dependencies: {}".format(config.get('optional_dependencies', [])))
|
|
374
|
+
print("Shared Resources: {}".format(config.get('shared_resources', [])))
|
|
375
|
+
else:
|
|
376
|
+
print("Unknown module type: {}".format(module_type))
|
|
377
|
+
print("Available types: {}".format(list_module_types()))
|
|
378
|
+
|
|
379
|
+
# Module initialization and validation
|
|
380
|
+
def validate_setup():
|
|
381
|
+
"""Validate that the import system is working correctly."""
|
|
382
|
+
try:
|
|
383
|
+
# Test core components
|
|
384
|
+
logging_config = get_components('logging_config')
|
|
385
|
+
core_utils = get_components('core_utils')
|
|
386
|
+
|
|
387
|
+
print("[+] MediCafe Smart Import System initialized successfully")
|
|
388
|
+
print("[+] Available components: {}".format(len(list_components())))
|
|
389
|
+
print("[+] Available module types: {}".format(len(list_module_types())))
|
|
390
|
+
return True
|
|
391
|
+
except Exception as e:
|
|
392
|
+
print("[-] MediCafe Smart Import System validation failed: {}".format(e))
|
|
393
|
+
return False
|
|
394
|
+
|
|
395
|
+
# Advanced usage examples and documentation
|
|
396
|
+
def show_usage_examples():
|
|
397
|
+
"""Show usage examples for the smart import system."""
|
|
398
|
+
examples = """
|
|
399
|
+
MediCafe Smart Import System - Usage Examples
|
|
400
|
+
|
|
401
|
+
1. Basic component import:
|
|
402
|
+
from MediCafe.smart_import import get_components
|
|
403
|
+
api_core, logging_config = get_components('api_core', 'logging_config')
|
|
404
|
+
|
|
405
|
+
2. Setup for MediBot:
|
|
406
|
+
from MediCafe.smart_import import setup_for_medibot
|
|
407
|
+
components = setup_for_medibot('medibot_preprocessor')
|
|
408
|
+
api_core = components['api_core']
|
|
409
|
+
|
|
410
|
+
3. Setup for MediLink:
|
|
411
|
+
from MediCafe.smart_import import setup_for_medilink
|
|
412
|
+
components = setup_for_medilink('medilink_claim_processing')
|
|
413
|
+
datamgmt = components['medilink_datamgmt']
|
|
414
|
+
|
|
415
|
+
4. Get API access suite:
|
|
416
|
+
from MediCafe.smart_import import get_api_access
|
|
417
|
+
api_suite = get_api_access()
|
|
418
|
+
api_core = api_suite['api_core']
|
|
419
|
+
api_factory = api_suite['api_factory']
|
|
420
|
+
|
|
421
|
+
5. Discovery functions:
|
|
422
|
+
from MediCafe.smart_import import list_components, list_module_types
|
|
423
|
+
print("Available components:", list_components())
|
|
424
|
+
print("Available module types:", list_module_types())
|
|
425
|
+
"""
|
|
426
|
+
print(examples)
|
|
427
|
+
|
|
428
|
+
# Auto-validation on import (silent)
|
|
429
|
+
if __name__ != '__main__':
|
|
430
|
+
try:
|
|
431
|
+
# Silent validation - don't print success messages on import
|
|
432
|
+
logging_config = get_components('logging_config', silent_fail=True)
|
|
433
|
+
if logging_config:
|
|
434
|
+
pass # Successfully validated
|
|
435
|
+
except:
|
|
436
|
+
pass # Silent fail on import
|
MediLink/MediLink.py
CHANGED
|
@@ -33,17 +33,25 @@ def collect_detailed_patient_data(selected_files, config, crosswalk):
|
|
|
33
33
|
"""
|
|
34
34
|
Collects detailed patient data from the selected files.
|
|
35
35
|
|
|
36
|
+
DATA FLOW CLARIFICATION:
|
|
37
|
+
This function processes fixed-width files through extract_and_suggest_endpoint(),
|
|
38
|
+
which creates data structures with 'patient_id' field (sourced from 'CHART' field).
|
|
39
|
+
This is DIFFERENT from MediBot's parse_z_dat() flow which uses 'PATID' field.
|
|
40
|
+
|
|
36
41
|
:param selected_files: List of selected file paths.
|
|
37
42
|
:param config: Configuration settings loaded from a JSON file.
|
|
38
43
|
:param crosswalk: Crosswalk data for mapping purposes.
|
|
39
|
-
:return: A list of detailed patient data.
|
|
44
|
+
:return: A list of detailed patient data with 'patient_id' field populated.
|
|
40
45
|
"""
|
|
41
46
|
detailed_patient_data = []
|
|
42
47
|
for file_path in selected_files:
|
|
48
|
+
# IMPORTANT: extract_and_suggest_endpoint creates data with 'patient_id' field
|
|
49
|
+
# sourced from the 'CHART' field in fixed-width files
|
|
43
50
|
detailed_data = extract_and_suggest_endpoint(file_path, config, crosswalk)
|
|
44
51
|
detailed_patient_data.extend(detailed_data) # Accumulate detailed data for processing
|
|
45
52
|
|
|
46
53
|
# Enrich the detailed patient data with insurance type
|
|
54
|
+
# NOTE: This receives data from extract_and_suggest_endpoint with 'patient_id' field
|
|
47
55
|
detailed_patient_data = enrich_with_insurance_type(detailed_patient_data, insurance_options)
|
|
48
56
|
|
|
49
57
|
# Display summaries and provide an option for bulk edit
|
|
@@ -56,8 +64,16 @@ def enrich_with_insurance_type(detailed_patient_data, patient_insurance_type_map
|
|
|
56
64
|
Enriches the detailed patient data with insurance type based on patient ID.
|
|
57
65
|
Enhanced with optional API integration and comprehensive logging.
|
|
58
66
|
|
|
67
|
+
DATA FLOW CLARIFICATION:
|
|
68
|
+
This function receives data from collect_detailed_patient_data() -> extract_and_suggest_endpoint().
|
|
69
|
+
The patient ID field is 'patient_id' (NOT 'PATID').
|
|
70
|
+
|
|
71
|
+
IMPORTANT: Do not confuse with MediBot's parse_z_dat() flow which uses 'PATID'.
|
|
72
|
+
MediLink flow: fixed-width files -> extract_and_suggest_endpoint() -> 'patient_id' field (from 'CHART')
|
|
73
|
+
MediBot flow: Z.dat files -> parse_z_dat() -> 'PATID' field
|
|
74
|
+
|
|
59
75
|
Parameters:
|
|
60
|
-
- detailed_patient_data: List of dictionaries containing detailed patient data.
|
|
76
|
+
- detailed_patient_data: List of dictionaries containing detailed patient data with 'patient_id' field.
|
|
61
77
|
- patient_insurance_mapping: Dictionary mapping patient IDs to their insurance types.
|
|
62
78
|
|
|
63
79
|
Returns:
|
|
@@ -70,48 +86,60 @@ def enrich_with_insurance_type(detailed_patient_data, patient_insurance_type_map
|
|
|
70
86
|
UHC and which ones are not yet supported so they know which ones they need to edit. It is possible that we may want to isolate the
|
|
71
87
|
patient data that is already pulled from UHC so that the user can see which ones are already using the enriched data.
|
|
72
88
|
"""
|
|
73
|
-
#
|
|
89
|
+
# Enhanced mode check with graceful degradation
|
|
90
|
+
enhanced_mode = False
|
|
91
|
+
|
|
74
92
|
try:
|
|
75
93
|
from MediLink_insurance_utils import (
|
|
76
94
|
get_feature_flag,
|
|
77
|
-
enrich_patient_data_with_metadata,
|
|
78
|
-
generate_insurance_assignment_summary,
|
|
79
95
|
validate_insurance_type_from_config
|
|
80
96
|
)
|
|
81
97
|
enhanced_mode = get_feature_flag('enhanced_insurance_enrichment', default=False)
|
|
82
|
-
|
|
83
|
-
|
|
98
|
+
MediLink_ConfigLoader.log("Insurance enhancement utilities loaded successfully", level="DEBUG")
|
|
99
|
+
except ImportError as e:
|
|
100
|
+
MediLink_ConfigLoader.log("Insurance utils not available: {}. Using legacy mode.".format(str(e)), level="INFO")
|
|
101
|
+
enhanced_mode = False
|
|
102
|
+
except Exception as e:
|
|
103
|
+
MediLink_ConfigLoader.log("Error initializing insurance enhancements: {}. Using legacy mode.".format(str(e)), level="ERROR")
|
|
84
104
|
enhanced_mode = False
|
|
85
105
|
|
|
86
106
|
if patient_insurance_type_mapping is None:
|
|
87
|
-
MediLink_ConfigLoader.log("No Patient:Insurance-Type mapping available.", level="
|
|
107
|
+
MediLink_ConfigLoader.log("No Patient:Insurance-Type mapping available.", level="INFO")
|
|
88
108
|
patient_insurance_type_mapping = {}
|
|
89
109
|
|
|
90
|
-
# Enhanced mode with
|
|
110
|
+
# Enhanced mode with validation
|
|
91
111
|
if enhanced_mode:
|
|
92
112
|
MediLink_ConfigLoader.log("Using enhanced insurance type enrichment", level="INFO")
|
|
93
113
|
|
|
94
114
|
for data in detailed_patient_data:
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
generate_insurance_assignment_summary(detailed_patient_data)
|
|
115
|
+
# FIELD NAME CLARIFICATION: Use 'patient_id' field created by extract_and_suggest_endpoint()
|
|
116
|
+
# This field contains the value from the 'CHART' field in the original fixed-width file
|
|
117
|
+
patient_id = data.get('patient_id')
|
|
118
|
+
if patient_id:
|
|
119
|
+
raw_insurance_type = patient_insurance_type_mapping.get(patient_id, '12') # Default to '12' (PPO/SBR09)
|
|
120
|
+
validated_insurance_type = validate_insurance_type_from_config(raw_insurance_type, patient_id)
|
|
121
|
+
data['insurance_type'] = validated_insurance_type
|
|
122
|
+
data['insurance_type_source'] = 'MANUAL' if patient_id in patient_insurance_type_mapping else 'DEFAULT'
|
|
123
|
+
else:
|
|
124
|
+
# Handle case where patient_id is missing or empty
|
|
125
|
+
MediLink_ConfigLoader.log("No patient_id found in data record", level="WARNING")
|
|
126
|
+
data['insurance_type'] = '12' # SBR09 default PPO
|
|
127
|
+
data['insurance_type_source'] = 'DEFAULT_FALLBACK'
|
|
109
128
|
|
|
110
129
|
else:
|
|
111
130
|
# Legacy mode (preserve existing behavior exactly)
|
|
131
|
+
MediLink_ConfigLoader.log("Using legacy insurance type enrichment", level="INFO")
|
|
112
132
|
for data in detailed_patient_data:
|
|
113
|
-
|
|
114
|
-
|
|
133
|
+
# FIELD NAME CLARIFICATION: Use 'patient_id' field created by extract_and_suggest_endpoint()
|
|
134
|
+
# This field contains the value from the 'CHART' field in the original fixed-width file
|
|
135
|
+
patient_id = data.get('patient_id')
|
|
136
|
+
if patient_id:
|
|
137
|
+
insurance_type = patient_insurance_type_mapping.get(patient_id, '12') # Default to '12' (PPO/SBR09)
|
|
138
|
+
else:
|
|
139
|
+
# Handle case where patient_id is missing or empty
|
|
140
|
+
MediLink_ConfigLoader.log("No patient_id found in data record", level="WARNING")
|
|
141
|
+
insurance_type = '12' # Default when no patient ID available
|
|
142
|
+
|
|
115
143
|
data['insurance_type'] = insurance_type
|
|
116
144
|
|
|
117
145
|
return detailed_patient_data
|
|
@@ -123,6 +151,16 @@ def extract_and_suggest_endpoint(file_path, config, crosswalk):
|
|
|
123
151
|
an endpoint based on insurance provider information found in the crosswalk and prepares
|
|
124
152
|
detailed patient data for processing.
|
|
125
153
|
|
|
154
|
+
DATA FLOW CLARIFICATION:
|
|
155
|
+
This function is the PRIMARY data source for MediLink patient processing.
|
|
156
|
+
It creates the 'patient_id' field by extracting the 'CHART' field from fixed-width files.
|
|
157
|
+
|
|
158
|
+
IMPORTANT: This is DIFFERENT from MediBot's parse_z_dat() which extracts 'PATID'.
|
|
159
|
+
|
|
160
|
+
Field mapping for MediLink flow:
|
|
161
|
+
- Fixed-width file 'CHART' field -> detailed_data['patient_id']
|
|
162
|
+
- This 'patient_id' is then used by enrich_with_insurance_type()
|
|
163
|
+
|
|
126
164
|
Parameters:
|
|
127
165
|
- file_path: Path to the fixed-width file.
|
|
128
166
|
- crosswalk: Crosswalk dictionary loaded from a JSON file.
|
|
@@ -177,7 +215,9 @@ def extract_and_suggest_endpoint(file_path, config, crosswalk):
|
|
|
177
215
|
detailed_data = parsed_data.copy() # Copy parsed_data to avoid modifying the original dictionary
|
|
178
216
|
detailed_data.update({
|
|
179
217
|
'file_path': file_path,
|
|
180
|
-
|
|
218
|
+
# CRITICAL FIELD MAPPING: 'CHART' field from fixed-width file becomes 'patient_id'
|
|
219
|
+
# This is the field that enrich_with_insurance_type() will use
|
|
220
|
+
'patient_id': parsed_data.get('CHART'), # ← This is the key field mapping for MediLink flow
|
|
181
221
|
'surgery_date': parsed_data.get('DATE'),
|
|
182
222
|
'patient_name': ' '.join([parsed_data.get(key, '') for key in ['FIRST', 'MIDDLE', 'LAST']]),
|
|
183
223
|
'amount': parsed_data.get('AMOUNT'),
|