medicafe 0.250812.4__py3-none-any.whl → 0.250812.6__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.
- MediBot/MediBot.bat +44 -11
- MediBot/MediBot.py +52 -6
- MediBot/MediBot_Crosswalk_Library.py +2 -0
- MediBot/MediBot_Crosswalk_Utils.py +6 -4
- MediBot/MediBot_Preprocessor_lib.py +5 -0
- MediBot/update_medicafe.py +36 -13
- MediCafe/api_core.py +3 -0
- MediCafe/graphql_utils.py +63 -4
- MediCafe/submission_index.py +288 -0
- MediLink/InsuranceTypeService.py +57 -0
- MediLink/MediLink_837p_cob_library.py +8 -1
- MediLink/MediLink_837p_encoder.py +6 -0
- MediLink/MediLink_837p_encoder_library.py +38 -0
- MediLink/MediLink_DataMgmt.py +7 -2
- MediLink/MediLink_Display_Utils.py +28 -6
- MediLink/MediLink_PatientProcessor.py +69 -8
- MediLink/MediLink_UI.py +2 -0
- MediLink/MediLink_Up.py +101 -12
- MediLink/MediLink_main.py +106 -6
- medicafe-0.250812.6.dist-info/METADATA +95 -0
- {medicafe-0.250812.4.dist-info → medicafe-0.250812.6.dist-info}/RECORD +25 -23
- medicafe-0.250812.4.dist-info/METADATA +0 -138
- {medicafe-0.250812.4.dist-info → medicafe-0.250812.6.dist-info}/LICENSE +0 -0
- {medicafe-0.250812.4.dist-info → medicafe-0.250812.6.dist-info}/WHEEL +0 -0
- {medicafe-0.250812.4.dist-info → medicafe-0.250812.6.dist-info}/entry_points.txt +0 -0
- {medicafe-0.250812.4.dist-info → medicafe-0.250812.6.dist-info}/top_level.txt +0 -0
MediBot/MediBot.bat
CHANGED
@@ -2,11 +2,31 @@
|
|
2
2
|
@echo off
|
3
3
|
setlocal enabledelayedexpansion
|
4
4
|
|
5
|
-
::
|
5
|
+
:: Clear screen before launcher header
|
6
|
+
cls
|
7
|
+
|
8
|
+
:: Launcher header
|
6
9
|
echo ========================================
|
7
10
|
echo MediCafe Launcher
|
8
11
|
echo ========================================
|
9
12
|
echo.
|
13
|
+
|
14
|
+
:: Hidden debug access: 1-second Enter-to-open gate; otherwise start normal mode
|
15
|
+
echo Press Enter within 1 second to open Debug Options... (otherwise starting Normal Mode)
|
16
|
+
rem Prefer timeout for key-break; fall back to ping if unavailable
|
17
|
+
where timeout >nul 2>&1
|
18
|
+
if errorlevel 1 (
|
19
|
+
rem Fallback: simple 1-second delay (no key detection on XP fallback)
|
20
|
+
ping -n 2 127.0.0.1 >nul
|
21
|
+
goto start_normal_mode
|
22
|
+
) else (
|
23
|
+
timeout /t 1 >nul 2>nul
|
24
|
+
if errorlevel 1 goto show_debug_menu
|
25
|
+
goto start_normal_mode
|
26
|
+
)
|
27
|
+
|
28
|
+
:show_debug_menu
|
29
|
+
echo.
|
10
30
|
echo Choose your mode:
|
11
31
|
echo 1. Normal Mode - Production
|
12
32
|
echo 2. Debug Mode - Full diagnostics (Interactive)
|
@@ -127,6 +147,8 @@ set "claims_status_script=..\MediLink\MediLink_ClaimStatus.py"
|
|
127
147
|
set "deductible_script=..\MediLink\MediLink_Deductible.py"
|
128
148
|
set "package_version="
|
129
149
|
set PYTHONWARNINGS=ignore
|
150
|
+
set "PRES_WARN_UPDATE_SCRIPT=0"
|
151
|
+
set "PRES_WARN_NO_INTERNET=0"
|
130
152
|
|
131
153
|
:: Check if Python is installed
|
132
154
|
python --version >nul 2>&1
|
@@ -186,6 +208,7 @@ if defined package_version (
|
|
186
208
|
ping -n 1 google.com >nul 2>&1
|
187
209
|
if errorlevel 1 (
|
188
210
|
set "internet_available=0"
|
211
|
+
set "PRES_WARN_NO_INTERNET=1"
|
189
212
|
) else (
|
190
213
|
set "internet_available=1"
|
191
214
|
echo Internet connection detected.
|
@@ -322,6 +345,7 @@ if exist "%upgrade_medicafe_local%" (
|
|
322
345
|
ping -n 2 127.0.0.1 >nul
|
323
346
|
) else (
|
324
347
|
echo update_medicafe.py not detected in any known location.
|
348
|
+
set "PRES_WARN_UPDATE_SCRIPT=1"
|
325
349
|
echo.
|
326
350
|
echo Checked locations:
|
327
351
|
echo - Site-packages: C:\Python34\Lib\site-packages\MediBot\update_medicafe.py
|
@@ -351,6 +375,16 @@ echo .//* Welcome to MediCafe *\\.
|
|
351
375
|
echo --------------------------------------------------------------
|
352
376
|
echo.
|
353
377
|
|
378
|
+
:: Preserve important warnings/errors from boot sequence
|
379
|
+
if "%PRES_WARN_UPDATE_SCRIPT%"=="1" (
|
380
|
+
echo [WARNING] Update helper script not detected during startup. Update features may be limited.
|
381
|
+
echo.
|
382
|
+
)
|
383
|
+
if "%PRES_WARN_NO_INTERNET%"=="1" (
|
384
|
+
echo [WARNING] No internet connectivity detected during startup.
|
385
|
+
echo.
|
386
|
+
)
|
387
|
+
|
354
388
|
if "!internet_available!"=="0" (
|
355
389
|
echo NOTE: No internet detected. Options 1-5 require internet.
|
356
390
|
echo.
|
@@ -371,8 +405,6 @@ echo 6. Run MediBot
|
|
371
405
|
echo.
|
372
406
|
echo 7. Troubleshooting
|
373
407
|
echo.
|
374
|
-
echo 9. Toggle Performance Logging (session)
|
375
|
-
echo.
|
376
408
|
echo 8. Exit
|
377
409
|
echo.
|
378
410
|
set /p choice=Enter your choice:
|
@@ -386,7 +418,6 @@ if "!choice!"=="4" goto united_claims_status
|
|
386
418
|
if "!choice!"=="3" goto medilink_flow
|
387
419
|
if "!choice!"=="2" goto download_emails
|
388
420
|
if "!choice!"=="1" goto check_updates
|
389
|
-
if "!choice!"=="9" goto toggle_perf_logging
|
390
421
|
if "!choice!"=="0" goto end_script
|
391
422
|
|
392
423
|
echo Invalid choice. Please try again.
|
@@ -538,7 +569,7 @@ if not exist "%_UPD_RUNNER%" (
|
|
538
569
|
echo.
|
539
570
|
echo Launching updater and closing this window...
|
540
571
|
start "MediCafe Update" "%_UPD_RUNNER%"
|
541
|
-
exit
|
572
|
+
exit 0
|
542
573
|
|
543
574
|
:: Download Carol's Emails
|
544
575
|
:download_emails
|
@@ -602,7 +633,7 @@ if /I "%MEDICAFE_PERFORMANCE_LOGGING%"=="1" (
|
|
602
633
|
echo.
|
603
634
|
echo Note: This affects current session only. To persist, set in config.json.
|
604
635
|
pause
|
605
|
-
goto
|
636
|
+
goto troubleshooting_menu
|
606
637
|
|
607
638
|
:: United Claims Status
|
608
639
|
:united_claims_status
|
@@ -681,14 +712,16 @@ echo Troubleshooting Options:
|
|
681
712
|
echo.
|
682
713
|
echo 1. Open Latest Log File
|
683
714
|
echo 2. Clear Python Cache
|
684
|
-
echo 3.
|
685
|
-
echo 4.
|
715
|
+
echo 3. Toggle Performance Logging ^(session^)
|
716
|
+
echo 4. Forced MediCafe version rollback
|
717
|
+
echo 5. Back to Main Menu
|
686
718
|
echo.
|
687
719
|
set /p tchoice=Enter your choice:
|
688
720
|
if "%tchoice%"=="1" goto open_latest_log
|
689
721
|
if "%tchoice%"=="2" goto clear_cache_menu
|
690
|
-
if "%tchoice%"=="3" goto
|
691
|
-
if "%tchoice%"=="4" goto
|
722
|
+
if "%tchoice%"=="3" goto toggle_perf_logging
|
723
|
+
if "%tchoice%"=="4" goto forced_version_rollback
|
724
|
+
if "%tchoice%"=="5" goto main_menu
|
692
725
|
echo Invalid choice. Please try again.
|
693
726
|
pause
|
694
727
|
goto troubleshooting_menu
|
@@ -709,7 +742,7 @@ goto troubleshooting_menu
|
|
709
742
|
:: End Script
|
710
743
|
:end_script
|
711
744
|
echo Exiting MediBot
|
712
|
-
exit
|
745
|
+
exit 0
|
713
746
|
|
714
747
|
:: Full Debug Mode moved to external script full_debug_suite.bat
|
715
748
|
|
MediBot/MediBot.py
CHANGED
@@ -73,6 +73,45 @@ except ImportError as e:
|
|
73
73
|
# Make API client optional - don't log warning for now
|
74
74
|
pass
|
75
75
|
|
76
|
+
# Buffer for startup warnings/errors so we can re-display them after clearing the console
|
77
|
+
STARTUP_NOTICES = []
|
78
|
+
|
79
|
+
def record_startup_warning(message):
|
80
|
+
"""Record a startup warning, log it, and print it immediately.
|
81
|
+
Stored warnings will be reprinted after the screen is cleared.
|
82
|
+
"""
|
83
|
+
try:
|
84
|
+
STARTUP_NOTICES.append(('WARNING', message))
|
85
|
+
except Exception:
|
86
|
+
pass
|
87
|
+
try:
|
88
|
+
if MediLink_ConfigLoader:
|
89
|
+
MediLink_ConfigLoader.log(message, level="WARNING")
|
90
|
+
except Exception:
|
91
|
+
pass
|
92
|
+
try:
|
93
|
+
print(message)
|
94
|
+
except Exception:
|
95
|
+
pass
|
96
|
+
|
97
|
+
def record_startup_error(message):
|
98
|
+
"""Record a startup error, log it, and print it immediately.
|
99
|
+
Stored errors will be reprinted after the screen is cleared.
|
100
|
+
"""
|
101
|
+
try:
|
102
|
+
STARTUP_NOTICES.append(('ERROR', message))
|
103
|
+
except Exception:
|
104
|
+
pass
|
105
|
+
try:
|
106
|
+
if MediLink_ConfigLoader:
|
107
|
+
MediLink_ConfigLoader.log(message, level="ERROR")
|
108
|
+
except Exception:
|
109
|
+
pass
|
110
|
+
try:
|
111
|
+
print(message)
|
112
|
+
except Exception:
|
113
|
+
pass
|
114
|
+
|
76
115
|
def identify_field(header, field_mapping):
|
77
116
|
for medisoft_field, patterns in field_mapping.items():
|
78
117
|
for pattern in patterns:
|
@@ -448,12 +487,10 @@ class ExecutionState:
|
|
448
487
|
MediLink_ConfigLoader.log("Crosswalk update completed successfully.", level="INFO")
|
449
488
|
print("Crosswalk update completed successfully.")
|
450
489
|
else:
|
451
|
-
|
452
|
-
print("Crosswalk update failed.")
|
490
|
+
record_startup_error("Crosswalk update failed.")
|
453
491
|
|
454
492
|
except Exception as e:
|
455
|
-
|
456
|
-
print("MediBot: Failed to load or update configuration: {}".format(e))
|
493
|
+
record_startup_error("MediBot: Failed to load or update configuration: {}".format(e))
|
457
494
|
raise # Re-throwing the exception or using a more sophisticated error handling mechanism might be needed
|
458
495
|
# Handle the exception somehow (e.g., retry, halt, log)??
|
459
496
|
|
@@ -544,9 +581,18 @@ if __name__ == "__main__":
|
|
544
581
|
MediLink_ConfigLoader.log("Load Complete event triggered. Clearing console. Displaying Menu...", level="INFO")
|
545
582
|
# Windows XP console buffer fix: Use cls with echo to reset buffer state
|
546
583
|
# Add a debug switch to optionally skip clearing the console for debugging purposes
|
547
|
-
CLEAR_CONSOLE_ON_LOAD =
|
584
|
+
CLEAR_CONSOLE_ON_LOAD = True # Clear screen before menu for cleaner UI
|
548
585
|
if CLEAR_CONSOLE_ON_LOAD:
|
549
586
|
_ = os.system('cls && echo.')
|
587
|
+
# Re-display critical startup notices so the user still sees them
|
588
|
+
if STARTUP_NOTICES:
|
589
|
+
print("Important notices from startup:")
|
590
|
+
for lvl, msg in STARTUP_NOTICES:
|
591
|
+
try:
|
592
|
+
print("[{}] {}".format(lvl, msg))
|
593
|
+
except Exception:
|
594
|
+
print(msg)
|
595
|
+
print("-" * 60)
|
550
596
|
|
551
597
|
proceed, selected_patient_ids, selected_indices, fixed_values = user_interaction(csv_data, interaction_mode, error_message, reverse_mapping)
|
552
598
|
|
@@ -556,7 +602,7 @@ if __name__ == "__main__":
|
|
556
602
|
|
557
603
|
# Check if MAPAT_MED_PATH is missing or invalid
|
558
604
|
if (not _ac()) or (not _ac().get_mapat_med_path()) or (not os.path.exists(_ac().get_mapat_med_path())):
|
559
|
-
|
605
|
+
record_startup_warning("Warning: MAPAT.MED PATH is missing or invalid. Please check the path configuration.")
|
560
606
|
|
561
607
|
# Perform the existing patients check
|
562
608
|
existing_patients, patients_to_process = MediBot_Preprocessor.check_existing_patients(selected_patient_ids, _ac().get_mapat_med_path() if _ac() else '')
|
@@ -376,6 +376,8 @@ def crosswalk_update(client, config, crosswalk): # Upstream of this is only Medi
|
|
376
376
|
'medisoft_medicare_id': [] # PERFORMANCE FIX: Use list instead of set to avoid conversions
|
377
377
|
}
|
378
378
|
MediLink_ConfigLoader.log("Initialized payer ID {} in crosswalk with endpoint '{}'.".format(payer_id, selected_endpoint), config, level="DEBUG")
|
379
|
+
# TODO (MEDICARE ENDPOINTS): If payer_id is Medicare (e.g., in config['MediLink_Config']['cob_settings']['medicare_payer_ids']),
|
380
|
+
# set endpoint to 'MEDICARE_PRIMARY' and optionally store 'crossover_endpoint' for later automation.
|
379
381
|
|
380
382
|
# Add the insurance ID to the payer ID entry (PERFORMANCE FIX: Use list operations)
|
381
383
|
insurance_id_str = str(insurance_id) # Ensure ID is string
|
@@ -370,10 +370,12 @@ def save_crosswalk(client, config, crosswalk, skip_api_operations=False, api_cac
|
|
370
370
|
crosswalk['payer_id'][payer_id]['endpoint'] = select_endpoint(config) # Use the helper function to set the endpoint
|
371
371
|
MediLink_ConfigLoader.log("Initialized 'endpoint' for payer ID {}.".format(payer_id), config, level="DEBUG")
|
372
372
|
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
|
373
|
+
# Initialize medisoft_id and medisoft_medicare_id as empty lists if they do not exist
|
374
|
+
crosswalk['payer_id'][payer_id].setdefault('medisoft_id', [])
|
375
|
+
crosswalk['payer_id'][payer_id].setdefault('medisoft_medicare_id', []) # does this work in 3.4.4?
|
376
|
+
MediLink_ConfigLoader.log("Ensured 'medisoft_id' and 'medisoft_medicare_id' for payer ID {} are initialized.".format(payer_id), config, level="DEBUG")
|
377
|
+
# TODO (CROSSWALK VALIDATION): Enforce distinctness between 'medisoft_id' and 'medisoft_medicare_id' and support optional
|
378
|
+
# 'crossover_endpoint' per payer. Use config['MediLink_Config']['cob_settings']['medicare_payer_ids'] to detect Medicare payers.
|
377
379
|
|
378
380
|
# Convert sets to sorted lists for JSON serialization
|
379
381
|
for payer_id, details in crosswalk.get('payer_id', {}).items():
|
@@ -816,6 +816,11 @@ def update_insurance_ids(csv_data, config, crosswalk):
|
|
816
816
|
|
817
817
|
# Assign the resolved insurance ID to the row
|
818
818
|
row['Ins1 Insurance ID'] = insurance_id
|
819
|
+
# TODO (SECONDARY QUEUE): When building a secondary-claims queue after Medicare crossover,
|
820
|
+
# set claim_type='secondary' and attach prior payer fields here from the Medicare primary outcome:
|
821
|
+
# - row['prior_payer_name'] = 'MEDICARE'
|
822
|
+
# - row['prior_payer_id'] = best Medicare ID from config/crosswalk
|
823
|
+
# - optionally row['primary_paid_amount'], row['cas_adjustments'] extracted from 835
|
819
824
|
processed_count += 1
|
820
825
|
# LOGGING STRATEGY: Remove success logging - DEBUG is typically silent anyway
|
821
826
|
# if processed_count <= 10 or processed_count % 100 == 0: # Log first 10 and every 100th
|
MediBot/update_medicafe.py
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
#update_medicafe.py
|
2
|
-
import subprocess, sys, time, platform, os, shutil
|
2
|
+
import subprocess, sys, time, platform, os, shutil, random
|
3
3
|
|
4
4
|
# Safe import for pkg_resources with fallback
|
5
5
|
try:
|
@@ -162,6 +162,8 @@ def get_latest_version(package, retries=3, delay=1):
|
|
162
162
|
time.sleep(delay)
|
163
163
|
return None
|
164
164
|
|
165
|
+
|
166
|
+
|
165
167
|
def check_internet_connection():
|
166
168
|
try:
|
167
169
|
requests.get("http://www.google.com", timeout=5)
|
@@ -288,7 +290,7 @@ def compare_versions(version1, version2):
|
|
288
290
|
v2_parts = list(map(int, version2.split(".")))
|
289
291
|
return (v1_parts > v2_parts) - (v1_parts < v2_parts)
|
290
292
|
|
291
|
-
def upgrade_package(package, retries=
|
293
|
+
def upgrade_package(package, retries=4, delay=2, target_version=None): # Updated retries to 4
|
292
294
|
"""
|
293
295
|
Attempts to upgrade the package multiple times with delays in between.
|
294
296
|
"""
|
@@ -296,23 +298,33 @@ def upgrade_package(package, retries=3, delay=2): # Updated retries to 3
|
|
296
298
|
print_status("No internet connection detected. Please check your internet connection and try again.", "ERROR")
|
297
299
|
print_final_result(False, "No internet connection available")
|
298
300
|
|
301
|
+
# Light verbosity: show pinned target once
|
302
|
+
if target_version:
|
303
|
+
print("Pinned target version: {}".format(target_version))
|
304
|
+
|
299
305
|
for attempt in range(1, retries + 1):
|
300
|
-
print("Attempt {} to upgrade {}...".format(attempt, package))
|
306
|
+
print("Attempt {}/{} to upgrade {}...".format(attempt, retries, package))
|
301
307
|
|
302
308
|
# Use a more compatible approach for Python 3.4
|
303
309
|
# Try with --no-deps first to avoid dependency resolution issues
|
310
|
+
pkg_spec = package
|
311
|
+
if target_version:
|
312
|
+
pkg_spec = "{}=={}".format(package, target_version)
|
313
|
+
|
304
314
|
cmd = [
|
305
315
|
sys.executable, '-m', 'pip', 'install', '--upgrade',
|
306
|
-
'--no-deps', '--no-cache-dir', '--disable-pip-version-check', '-q',
|
316
|
+
'--no-deps', '--no-cache-dir', '--disable-pip-version-check', '-q', pkg_spec
|
307
317
|
]
|
308
318
|
|
319
|
+
print("Using pip upgrade with --no-deps and --no-cache-dir")
|
309
320
|
process = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
310
321
|
stdout, stderr = process.communicate()
|
311
322
|
|
312
323
|
if process.returncode == 0:
|
313
324
|
print(stdout.decode().strip())
|
314
325
|
new_version = get_installed_version(package) # Get new version after upgrade
|
315
|
-
|
326
|
+
expected_version = target_version or get_latest_version(package)
|
327
|
+
if expected_version and compare_versions(new_version, expected_version) >= 0: # Compare versions
|
316
328
|
if attempt == 1:
|
317
329
|
print_status("Upgrade succeeded!", "SUCCESS")
|
318
330
|
else:
|
@@ -320,20 +332,27 @@ def upgrade_package(package, retries=3, delay=2): # Updated retries to 3
|
|
320
332
|
time.sleep(delay)
|
321
333
|
return True
|
322
334
|
else:
|
323
|
-
print_status("Upgrade
|
335
|
+
print_status("Upgrade incomplete. Current version: {} Expected at least: {}".format(new_version, expected_version), "WARNING")
|
324
336
|
if attempt < retries:
|
325
337
|
print("Retrying in {} seconds...".format(delay))
|
326
|
-
|
338
|
+
try:
|
339
|
+
time.sleep(delay + (random.random() * 0.5))
|
340
|
+
except Exception:
|
341
|
+
time.sleep(delay)
|
327
342
|
else:
|
328
343
|
print(stderr.decode().strip())
|
329
344
|
print_status("Attempt {}: Upgrade failed with --no-deps.".format(attempt), "WARNING")
|
330
345
|
|
331
346
|
# If --no-deps failed, try with --force-reinstall to bypass dependency issues
|
332
347
|
if attempt < retries:
|
333
|
-
print("
|
348
|
+
print("Fallback this attempt: retrying with --force-reinstall...")
|
349
|
+
pkg_spec = package
|
350
|
+
if target_version:
|
351
|
+
pkg_spec = "{}=={}".format(package, target_version)
|
352
|
+
|
334
353
|
cmd = [
|
335
354
|
sys.executable, '-m', 'pip', 'install', '--upgrade',
|
336
|
-
'--force-reinstall', '--no-cache-dir', '--disable-pip-version-check', '-q',
|
355
|
+
'--force-reinstall', '--no-cache-dir', '--disable-pip-version-check', '-q', pkg_spec
|
337
356
|
]
|
338
357
|
|
339
358
|
process = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
@@ -342,19 +361,23 @@ def upgrade_package(package, retries=3, delay=2): # Updated retries to 3
|
|
342
361
|
if process.returncode == 0:
|
343
362
|
print(stdout.decode().strip())
|
344
363
|
new_version = get_installed_version(package)
|
345
|
-
|
364
|
+
expected_version = target_version or get_latest_version(package)
|
365
|
+
if expected_version and compare_versions(new_version, expected_version) >= 0:
|
346
366
|
print_status("Attempt {}: Upgrade succeeded with --force-reinstall!".format(attempt), "SUCCESS")
|
347
367
|
time.sleep(delay)
|
348
368
|
return True
|
349
369
|
else:
|
350
|
-
print_status("Upgrade
|
370
|
+
print_status("Upgrade incomplete. Current version: {} Expected at least: {}".format(new_version, expected_version), "WARNING")
|
351
371
|
else:
|
352
372
|
print(stderr.decode().strip())
|
353
373
|
print_status("Attempt {}: Upgrade failed with --force-reinstall.".format(attempt), "WARNING")
|
354
374
|
|
355
375
|
if attempt < retries:
|
356
376
|
print("Retrying in {} seconds...".format(delay))
|
357
|
-
|
377
|
+
try:
|
378
|
+
time.sleep(delay + (random.random() * 0.5))
|
379
|
+
except Exception:
|
380
|
+
time.sleep(delay)
|
358
381
|
|
359
382
|
print_status("All upgrade attempts failed.", "ERROR")
|
360
383
|
return False
|
@@ -566,7 +589,7 @@ def main():
|
|
566
589
|
print("Current version: {}".format(current_version))
|
567
590
|
print("Target version: {}".format(latest_version))
|
568
591
|
|
569
|
-
if upgrade_package(package):
|
592
|
+
if upgrade_package(package, target_version=latest_version):
|
570
593
|
# STEP 8: Verify upgrade
|
571
594
|
debug_step(8, "Upgrade Verification")
|
572
595
|
new_version = get_installed_version(package)
|
MediCafe/api_core.py
CHANGED
@@ -79,6 +79,9 @@ class ConfigLoader:
|
|
79
79
|
print("Attempting to load Swagger file: {}".format(swagger_path))
|
80
80
|
with open(swagger_path, 'r') as swagger_file:
|
81
81
|
if swagger_path.endswith('.yaml') or swagger_path.endswith('.yml'):
|
82
|
+
if yaml is None:
|
83
|
+
print("YAML parsing not available (PyYAML not installed). Please install PyYAML or provide a JSON Swagger file.")
|
84
|
+
return None
|
82
85
|
print("Parsing YAML file: {}".format(swagger_path))
|
83
86
|
swagger_data = yaml.safe_load(swagger_file)
|
84
87
|
elif swagger_path.endswith('.json'):
|
MediCafe/graphql_utils.py
CHANGED
@@ -109,7 +109,7 @@ class GraphQLQueryBuilder:
|
|
109
109
|
This is for testing purposes to verify the endpoint is working.
|
110
110
|
"""
|
111
111
|
return {
|
112
|
-
"query": "query Query($input: EligibilityInput!) { checkEligibility(input: $input) { eligibility { eligibilityInfo { trnId member { memberId firstName lastName middleName suffix dateOfBirth gender relationship relationshipCode relationshipTypeCode individualRelationshipCode dependentSequenceNumber } contact { addresses { type street1 street2 city state country zip zip4 } } insuranceInfo { policyNumber eligibilityStartDate eligibilityEndDate planStartDate planEndDate policyStatus planTypeDescription planVariation reportingCode stateOfIssueCode productType productId productCode payerId lineOfBusiness lineOfBusinessCode coverageTypes { typeCode description } } associatedIds { alternateId medicaidRecipientId exchangeMemberId alternateSubscriberId hicNumber mbiNumber subscriberMemberFacingIdentifier survivingSpouseId subscriberId memberReplacementId legacyMemberId customerAccountIdentifier } planLevels { level family { networkStatus planAmount planAmountFrequency remainingAmount } individual { networkStatus planAmount planAmountFrequency remainingAmount } } delegatedInfo { entity payerId contact { phone fax email } addresses { type street1 street2 city state country zip zip4 } } additionalInfo { isReferralRequired } } primaryCarePhysician { isPcpFound lastName firstName middleName phoneNumber address { type street1 street2 city state country zip zip4 } networkStatusCode affiliateHospitalName providerGroupName } coordinationOfBenefit { coordinationOfBenefitDetails { payer { name phoneNumber address { type street1 street2 city state country zip zip4 } } cobPrimacy { indicator description message } } uhgPrimacyStatus { policyEffectiveDate policyTerminationDate primacy { indicator description message } } } idCardImages { side content contentType } providerNetwork { status tier } extendedAttributes { fundingCode fundingType hsa cdhp governmentProgramCode cmsPackageBenefitPlanCode cmsSegmentId cmsContractId marketType obligorId marketSite benefitPlanId virtualVisit planVariation groupNumber legacyPanelNumber coverageLevel sharedArrangement productServiceCode designatedVirtualClinicNetwork medicaidVariableCode healthInsuranceExchangeId memberDiv legalEntityCode } otherBeneficiaries { memberId firstName lastName middleName suffix dateOfBirth gender relationship relationshipCode relationshipTypeCode individualRelationshipCode dependentSequenceNumber } serviceLevels { family { networkStatus services { isVendorOnly service serviceCode serviceDate text status coPayAmount coPayFrequency coInsurancePercent planAmount remainingAmount metYearToDateAmount isReferralObtainedCopay isReferralObtainedCoInsurance referralCopayAmount referralCoInsurancePercent benefitsAllowedFrequencies benefitsRemainingFrequencies message { note { isSingleMessageDetail isViewDetail messages text subMessages { service status copay msg startDate endDate minCopay minCopayMsg maxCopay maxCopayMsg isPrimaryIndicator } limitationInfo { lmtPeriod lmtType lmtOccurPerPeriod lmtDollarPerPeriod message } isMultipleCopaysFound isMultipleCoinsuranceFound } coPay { isSingleMessageDetail isViewDetail messages text subMessages { service status copay msg startDate endDate minCopay minCopayMsg maxCopay maxCopayMsg isPrimaryIndicator } limitationInfo { lmtPeriod lmtType lmtOccurPerPeriod lmtDollarPerPeriod message } isMultipleCopaysFound isMultipleCoinsuranceFound } coInsurance { isSingleMessageDetail isViewDetail messages text subMessages { service status copay msg startDate endDate minCopay minCopayMsg maxCopay maxCopayMsg isPrimaryIndicator } limitationInfo { lmtPeriod lmtType lmtOccurPerPeriod lmtDollarPerPeriod message } isMultipleCopaysFound isMultipleCoinsuranceFound } deductible { isSingleMessageDetail isViewDetail messages text subMessages { service status copay msg startDate endDate minCopay minCopayMsg maxCopay maxCopayMsg isPrimaryIndicator } limitationInfo { lmtPeriod lmtType lmtOccurPerPeriod lmtDollarPerPeriod message } isMultipleCopaysFound isMultipleCoinsuranceFound } benefitsAllowed { isSingleMessageDetail isViewDetail messages text subMessages { service status copay msg startDate endDate minCopay minCopayMsg maxCopay maxCopayMsg isPrimaryIndicator } limitationInfo { lmtPeriod lmtType lmtOccurPerPeriod lmtDollarPerPeriod message } isMultipleCopaysFound isMultipleCoinsuranceFound } benefitsRemaining { isSingleMessageDetail isViewDetail messages text subMessages { service status copay msg startDate endDate minCopay minCopayMsg maxCopay maxCopayMsg isPrimaryIndicator } limitationInfo { lmtPeriod lmtType lmtOccurPerPeriod lmtDollarPerPeriod message } isMultipleCopaysFound isMultipleCoinsuranceFound } coPayList coInsuranceList } } }
|
112
|
+
"query": "query Query($input: EligibilityInput!) { checkEligibility(input: $input) { eligibility { eligibilityInfo { trnId member { memberId firstName lastName middleName suffix dateOfBirth gender relationship relationshipCode relationshipTypeCode individualRelationshipCode dependentSequenceNumber } contact { addresses { type street1 street2 city state country zip zip4 } } insuranceInfo { policyNumber eligibilityStartDate eligibilityEndDate planStartDate planEndDate policyStatus planTypeDescription planVariation reportingCode stateOfIssueCode productType productId productCode payerId lineOfBusiness lineOfBusinessCode coverageTypes { typeCode description } } associatedIds { alternateId medicaidRecipientId exchangeMemberId alternateSubscriberId hicNumber mbiNumber subscriberMemberFacingIdentifier survivingSpouseId subscriberId memberReplacementId legacyMemberId customerAccountIdentifier } planLevels { level family { networkStatus planAmount planAmountFrequency remainingAmount } individual { networkStatus planAmount planAmountFrequency remainingAmount } } delegatedInfo { entity payerId contact { phone fax email } addresses { type street1 street2 city state country zip zip4 } } additionalInfo { isReferralRequired } } primaryCarePhysician { isPcpFound lastName firstName middleName phoneNumber address { type street1 street2 city state country zip zip4 } networkStatusCode affiliateHospitalName providerGroupName } coordinationOfBenefit { coordinationOfBenefitDetails { payer { name phoneNumber address { type street1 street2 city state country zip zip4 } } cobPrimacy { indicator description message } } uhgPrimacyStatus { policyEffectiveDate policyTerminationDate primacy { indicator description message } } } idCardImages { side content contentType } providerNetwork { status tier } extendedAttributes { fundingCode fundingType hsa cdhp governmentProgramCode cmsPackageBenefitPlanCode cmsSegmentId cmsContractId marketType obligorId marketSite benefitPlanId virtualVisit planVariation groupNumber legacyPanelNumber coverageLevel sharedArrangement productServiceCode designatedVirtualClinicNetwork medicaidVariableCode healthInsuranceExchangeId memberDiv legalEntityCode } otherBeneficiaries { memberId firstName lastName middleName suffix dateOfBirth gender relationship relationshipCode relationshipTypeCode individualRelationshipCode dependentSequenceNumber } serviceLevels { family { networkStatus services { isVendorOnly service serviceCode serviceDate text status coPayAmount coPayFrequency coInsurancePercent planAmount remainingAmount metYearToDateAmount isReferralObtainedCopay isReferralObtainedCoInsurance referralCopayAmount referralCoInsurancePercent benefitsAllowedFrequencies benefitsRemainingFrequencies message { note { isSingleMessageDetail isViewDetail messages text subMessages { service status copay msg startDate endDate minCopay minCopayMsg maxCopay maxCopayMsg isPrimaryIndicator } limitationInfo { lmtPeriod lmtType lmtOccurPerPeriod lmtDollarPerPeriod message } isMultipleCopaysFound isMultipleCoinsuranceFound } coPay { isSingleMessageDetail isViewDetail messages text subMessages { service status copay msg startDate endDate minCopay minCopayMsg maxCopay maxCopayMsg isPrimaryIndicator } limitationInfo { lmtPeriod lmtType lmtOccurPerPeriod lmtDollarPerPeriod message } isMultipleCopaysFound isMultipleCoinsuranceFound } coInsurance { isSingleMessageDetail isViewDetail messages text subMessages { service status copay msg startDate endDate minCopay minCopayMsg maxCopay maxCopayMsg isPrimaryIndicator } limitationInfo { lmtPeriod lmtType lmtOccurPerPeriod lmtDollarPerPeriod message } isMultipleCopaysFound isMultipleCoinsuranceFound } deductible { isSingleMessageDetail isViewDetail messages text subMessages { service status copay msg startDate endDate minCopay minCopayMsg maxCopay maxCopayMsg isPrimaryIndicator } limitationInfo { lmtPeriod lmtType lmtOccurPerPeriod lmtDollarPerPeriod message } isMultipleCopaysFound isMultipleCoinsuranceFound } benefitsAllowed { isSingleMessageDetail isViewDetail messages text subMessages { service status copay msg startDate endDate minCopay minCopayMsg maxCopay maxCopayMsg isPrimaryIndicator } limitationInfo { lmtPeriod lmtType lmtOccurPerPeriod lmtDollarPerPeriod message } isMultipleCopaysFound isMultipleCoinsuranceFound } benefitsRemaining { isSingleMessageDetail isViewDetail messages text subMessages { service status copay msg startDate endDate minCopay minCopayMsg maxCopay maxCopayMsg isPrimaryIndicator } limitationInfo { lmtPeriod lmtType lmtOccurPerPeriod lmtDollarPerPeriod message } isMultipleCopaysFound isMultipleCoinsuranceFound } coPayList coInsuranceList } } } } } } }",
|
113
113
|
"variables": {
|
114
114
|
"input": {
|
115
115
|
"memberId": "0001234567",
|
@@ -141,7 +141,7 @@ class GraphQLQueryBuilder:
|
|
141
141
|
Returns the exact GraphQL query format that works with the Super Connector API.
|
142
142
|
This matches the exact format from the successful cURL request.
|
143
143
|
"""
|
144
|
-
return """query Query($input: EligibilityInput!) {\r\n \r\n checkEligibility(input: $input) {\r\n eligibility {\r\n eligibilityInfo {\r\n trnId\r\n member {\r\n memberId\r\n firstName\r\n lastName\r\n middleName\r\n suffix\r\n dateOfBirth\r\n gender\r\n relationship\r\n relationshipCode\r\n relationshipTypeCode\r\n individualRelationshipCode\r\n dependentSequenceNumber\r\n }\r\n contact {\r\n addresses {\r\n type\r\n street1\r\n street2\r\n city\r\n state\r\n country\r\n zip\r\n zip4\r\n }\r\n }\r\n insuranceInfo {\r\n policyNumber\r\n eligibilityStartDate\r\n eligibilityEndDate\r\n planStartDate\r\n planEndDate\r\n policyStatus\r\n planTypeDescription\r\n planVariation\r\n reportingCode\r\n stateOfIssueCode\r\n productType\r\n productId\r\n productCode\r\n payerId\r\n lineOfBusiness\r\n lineOfBusinessCode\r\n coverageTypes {\r\n typeCode\r\n description\r\n }\r\n }\r\n associatedIds {\r\n alternateId\r\n medicaidRecipientId\r\n exchangeMemberId\r\n alternateSubscriberId\r\n hicNumber\r\n mbiNumber\r\n subscriberMemberFacingIdentifier\r\n survivingSpouseId\r\n subscriberId\r\n memberReplacementId\r\n legacyMemberId\r\n customerAccountIdentifier\r\n }\r\n planLevels {\r\n level\r\n family {\r\n networkStatus\r\n planAmount\r\n planAmountFrequency\r\n remainingAmount\r\n }\r\n individual {\r\n networkStatus\r\n planAmount\r\n planAmountFrequency\r\n remainingAmount\r\n }\r\n }\r\n delegatedInfo {\r\n entity\r\n payerId\r\n contact {\r\n phone\r\n fax\r\n email\r\n }\r\n addresses {\r\n type\r\n street1\r\n street2\r\n city\r\n state\r\n country\r\n zip\r\n zip4\r\n }\r\n }\r\n additionalInfo {\r\n isReferralRequired\r\n }\r\n }\r\n primaryCarePhysician {\r\n isPcpFound\r\n lastName\r\n firstName\r\n middleName\r\n phoneNumber\r\n address {\r\n type\r\n street1\r\n street2\r\n city\r\n state\r\n country\r\n zip\r\n zip4\r\n }\r\n networkStatusCode\r\n affiliateHospitalName\r\n providerGroupName\r\n }\r\n coordinationOfBenefit {\r\n coordinationOfBenefitDetails {\r\n payer {\r\n name\r\n phoneNumber\r\n address {\r\n type\r\n street1\r\n street2\r\n city\r\n state\r\n country\r\n zip\r\n zip4\r\n }\r\n }\r\n cobPrimacy {\r\n indicator\r\n description\r\n message\r\n }\r\n }\r\n uhgPrimacyStatus {\r\n policyEffectiveDate\r\n policyTerminationDate\r\n primacy {\r\n indicator\r\n description\r\n message\r\n }\r\n }\r\n }\r\n providerNetwork {\r\n status\r\n tier\r\n }\r\n extendedAttributes {\r\n fundingCode\r\n fundingType\r\n hsa\r\n cdhp\r\n governmentProgramCode\r\n cmsPackageBenefitPlanCode\r\n cmsSegmentId\r\n cmsContractId\r\n marketType\r\n obligorId\r\n marketSite\r\n benefitPlanId\r\n virtualVisit\r\n planVariation\r\n groupNumber\r\n legacyPanelNumber\r\n coverageLevel\r\n sharedArrangement\r\n productServiceCode\r\n designatedVirtualClinicNetwork\r\n medicaidVariableCode\r\n healthInsuranceExchangeId\r\n memberDiv\r\n legalEntityCode\r\n }\r\n otherBeneficiaries {\r\n memberId\r\n firstName\r\n lastName\r\n middleName\r\n suffix\r\n dateOfBirth\r\n gender\r\n relationship\r\n relationshipCode\r\n relationshipTypeCode\r\n individualRelationshipCode\r\n dependentSequenceNumber\r\n }\r\n serviceLevels {\r\n family {\r\n networkStatus\r\n services {\r\n isVendorOnly\r\n service\r\n serviceCode\r\n serviceDate\r\n text\r\n status\r\n coPayAmount\r\n coPayFrequency\r\n coInsurancePercent\r\n planAmount\r\n remainingAmount\r\n metYearToDateAmount\r\n isReferralObtainedCopay\r\n isReferralObtainedCoInsurance\r\n referralCopayAmount\r\n referralCoInsurancePercent\r\n benefitsAllowedFrequencies\r\n benefitsRemainingFrequencies\r\n message {\r\n note {\r\n isSingleMessageDetail\r\n isViewDetail\r\n messages\r\n text\r\n subMessages {\r\n service\r\n status\r\n copay\r\n msg\r\n startDate\r\n endDate\r\n minCopay\r\n minCopayMsg\r\n maxCopay\r\n maxCopayMsg\r\n isPrimaryIndicator\r\n }\r\n limitationInfo {\r\n lmtPeriod\r\n lmtType\r\n lmtOccurPerPeriod\r\n lmtDollarPerPeriod\r\n message\r\n }\r\n isMultipleCopaysFound\r\n isMultipleCoinsuranceFound\r\n }\r\n coPay {\r\n isSingleMessageDetail\r\n isViewDetail\r\n messages\r\n text\r\n subMessages {\r\n service\r\n status\r\n copay\r\n msg\r\n startDate\r\n endDate\r\n minCopay\r\n minCopayMsg\r\n maxCopay\r\n maxCopayMsg\r\n isPrimaryIndicator\r\n }\r\n limitationInfo {\r\n lmtPeriod\r\n lmtType\r\n lmtOccurPerPeriod\r\n lmtDollarPerPeriod\r\n message\r\n }\r\n isMultipleCopaysFound\r\n isMultipleCoinsuranceFound\r\n }\r\n coInsurance {\r\n isSingleMessageDetail\r\n isViewDetail\r\n messages\r\n text\r\n subMessages {\r\n service\r\n status\r\n copay\r\n msg\r\n startDate\r\n endDate\r\n minCopay\r\n minCopayMsg\r\n maxCopay\r\n maxCopayMsg\r\n isPrimaryIndicator\r\n }\r\n limitationInfo {\r\n lmtPeriod\r\n lmtType\r\n lmtOccurPerPeriod\r\n lmtDollarPerPeriod\r\n message\r\n }\r\n isMultipleCopaysFound\r\n isMultipleCoinsuranceFound\r\n }\r\n deductible {\r\n isSingleMessageDetail\r\n isViewDetail\r\n messages\r\n text\r\n subMessages {\r\n service\r\n status\r\n copay\r\n msg\r\n startDate\r\n endDate\r\n minCopay\r\n minCopayMsg\r\n maxCopay\r\n maxCopayMsg\r\n isPrimaryIndicator\r\n }\r\n limitationInfo {\r\n lmtPeriod\r\n lmtType\r\n lmtOccurPerPeriod\r\n lmtDollarPerPeriod\r\n message\r\n }\r\n isMultipleCopaysFound\r\n isMultipleCoinsuranceFound\r\n }\r\n benefitsAllowed {\r\n isSingleMessageDetail\r\n isViewDetail\r\n messages\r\n text\r\n subMessages {\r\n service\r\n status\r\n copay\r\n msg\r\n startDate\r\n endDate\r\n minCopay\r\n minCopayMsg\r\n maxCopay\r\n maxCopayMsg\r\n isPrimaryIndicator\r\n }\r\n limitationInfo {\r\n lmtPeriod\r\n lmtType\r\n lmtOccurPerPeriod\r\n lmtDollarPerPeriod\r\n message\r\n }\r\n isMultipleCopaysFound\r\n isMultipleCoinsuranceFound\r\n }\r\n benefitsRemaining {\r\n isSingleMessageDetail\r\n isViewDetail\r\n messages\r\n text\r\n subMessages {\r\n service\r\n status\r\n copay\r\n msg\r\n startDate\r\n endDate\r\n minCopay\r\n minCopayMsg\r\n maxCopay\r\n maxCopayMsg\r\n isPrimaryIndicator\r\n }\r\n limitationInfo {\r\n lmtPeriod\r\n lmtType\r\n lmtOccurPerPeriod\r\n lmtDollarPerPeriod\r\n message\r\n }\r\n isMultipleCopaysFound\r\n isMultipleCoinsuranceFound\r\n }\r\n coPayList\r\n coInsuranceList\r\n }\r\n }\r\n }\r\n individual {\r\n networkStatus\r\n services {\r\n isVendorOnly\r\n service\r\n serviceCode\r\n serviceDate\r\n text\r\n status\r\n coPayAmount\r\n coPayFrequency\r\n coInsurancePercent\r\n planAmount\r\n remainingAmount\r\n metYearToDateAmount\r\n isReferralObtainedCopay\r\n isReferralObtainedCoInsurance\r\n referralCopayAmount\r\n referralCoInsurancePercent\r\n benefitsAllowedFrequencies\r\n benefitsRemainingFrequencies\r\n message {\r\n note {\r\n isSingleMessageDetail\r\n isViewDetail\r\n messages\r\n text\r\n subMessages {\r\n service\r\n status\r\n copay\r\n msg\r\n startDate\r\n endDate\r\n minCopay\r\n minCopayMsg\r\n maxCopay\r\n maxCopayMsg\r\n isPrimaryIndicator\r\n }\r\n limitationInfo {\r\n lmtPeriod\r\n lmtType\r\n lmtOccurPerPeriod\r\n lmtDollarPerPeriod\r\n message\r\n }\r\n isMultipleCopaysFound\r\n isMultipleCoinsuranceFound\r\n }\r\n coPay {\r\n isSingleMessageDetail\r\n isViewDetail\r\n messages\r\n text\r\n subMessages {\r\n service\r\n status\r\n copay\r\n msg\r\n startDate\r\n endDate\r\n minCopay\r\n minCopayMsg\r\n maxCopay\r\n maxCopayMsg\r\n isPrimaryIndicator\r\n }\r\n limitationInfo {\r\n lmtPeriod\r\n lmtType\r\n lmtOccurPerPeriod\r\n lmtDollarPerPeriod\r\n message\r\n }\r\n isMultipleCopaysFound\r\n isMultipleCoinsuranceFound\r\n }\r\n coInsurance {\r\n isSingleMessageDetail\r\n isViewDetail\r\n messages\r\n text\r\n subMessages {\r\n service\r\n status\r\n copay\r\n msg\r\n startDate\r\n endDate\r\n minCopay\r\n minCopayMsg\r\n maxCopay\r\n maxCopayMsg\r\n isPrimaryIndicator\r\n }\r\n limitationInfo {\r\n lmtPeriod\r\n lmtType\r\n lmtOccurPerPeriod\r\n lmtDollarPerPeriod\r\n message\r\n }\r\n isMultipleCopaysFound\r\n isMultipleCoinsuranceFound\r\n }\r\n deductible {\r\n isSingleMessageDetail\r\n isViewDetail\r\n messages\r\n text\r\n subMessages {\r\n service\r\n status\r\n copay\r\n msg\r\n startDate\r\n endDate\r\n minCopay\r\n minCopayMsg\r\n maxCopay\r\n maxCopayMsg\r\n isPrimaryIndicator\r\n }\r\n limitationInfo {\r\n lmtPeriod\r\n lmtType\r\n lmtOccurPerPeriod\r\n lmtDollarPerPeriod\r\n message\r\n }\r\n isMultipleCopaysFound\r\n isMultipleCoinsuranceFound\r\n }\r\n benefitsAllowed {\r\n isSingleMessageDetail\r\n isViewDetail\r\n messages\r\n text\r\n subMessages {\r\n service\r\n status\r\n copay\r\n msg\r\n startDate\r\n endDate\r\n minCopay\r\n minCopayMsg\r\n maxCopay\r\n maxCopayMsg\r\n isPrimaryIndicator\r\n }\r\n limitationInfo {\r\n lmtPeriod\r\n lmtType\r\n lmtOccurPerPeriod\r\n lmtDollarPerPeriod\r\n message\r\n }\r\n isMultipleCopaysFound\r\n isMultipleCoinsuranceFound\r\n }\r\n benefitsRemaining {\r\n isSingleMessageDetail\r\n isViewDetail\r\n messages\r\n text\r\n subMessages {\r\n service\r\n status\r\n copay\r\n msg\r\n startDate\r\n endDate\r\n minCopay\r\n minCopayMsg\r\n maxCopay\r\n maxCopayMsg\r\n isPrimaryIndicator\r\n }\r\n limitationInfo {\r\n lmtPeriod\r\n lmtType\r\n lmtOccurPerPeriod\r\n lmtDollarPerPeriod\r\n message\r\n }\r\n isMultipleCopaysFound\r\n isMultipleCoinsuranceFound\r\n }\r\n coPayList\r\n coInsuranceList\r\n }\r\n }\r\n }\r\n }\r\n }\r\n }\r\n}"""
|
144
|
+
return """query Query($input: EligibilityInput!) {\r\n \r\n checkEligibility(input: $input) {\r\n eligibility {\r\n eligibilityInfo {\r\n trnId\r\n member {\r\n memberId\r\n firstName\r\n lastName\r\n middleName\r\n suffix\r\n dateOfBirth\r\n gender\r\n relationship\r\n relationshipCode\r\n relationshipTypeCode\r\n individualRelationshipCode\r\n dependentSequenceNumber\r\n }\r\n contact {\r\n addresses {\r\n type\r\n street1\r\n street2\r\n city\r\n state\r\n country\r\n zip\r\n zip4\r\n }\r\n }\r\n insuranceInfo {\r\n policyNumber\r\n eligibilityStartDate\r\n eligibilityEndDate\r\n planStartDate\r\n planEndDate\r\n policyStatus\r\n planTypeDescription\r\n planVariation\r\n reportingCode\r\n stateOfIssueCode\r\n productType\r\n productId\r\n productCode\r\n payerId\r\n lineOfBusiness\r\n lineOfBusinessCode\r\n coverageTypes {\r\n typeCode\r\n description\r\n }\r\n }\r\n associatedIds {\r\n alternateId\r\n medicaidRecipientId\r\n exchangeMemberId\r\n alternateSubscriberId\r\n hicNumber\r\n mbiNumber\r\n subscriberMemberFacingIdentifier\r\n survivingSpouseId\r\n subscriberId\r\n memberReplacementId\r\n legacyMemberId\r\n customerAccountIdentifier\r\n }\r\n planLevels {\r\n level\r\n family {\r\n networkStatus\r\n planAmount\r\n planAmountFrequency\r\n remainingAmount\r\n }\r\n individual {\r\n networkStatus\r\n planAmount\r\n planAmountFrequency\r\n remainingAmount\r\n }\r\n }\r\n delegatedInfo {\r\n entity\r\n payerId\r\n contact {\r\n phone\r\n fax\r\n email\r\n }\r\n addresses {\r\n type\r\n street1\r\n street2\r\n city\r\n state\r\n country\r\n zip\r\n zip4\r\n }\r\n }\r\n additionalInfo {\r\n isReferralRequired\r\n }\r\n }\r\n primaryCarePhysician {\r\n isPcpFound\r\n lastName\r\n firstName\r\n middleName\r\n phoneNumber\r\n address {\r\n type\r\n street1\r\n street2\r\n city\r\n state\r\n country\r\n zip\r\n zip4\r\n }\r\n networkStatusCode\r\n affiliateHospitalName\r\n providerGroupName\r\n }\r\n coordinationOfBenefit {\r\n coordinationOfBenefitDetails {\r\n payer {\r\n name\r\n phoneNumber\r\n address {\r\n type\r\n street1\r\n street2\r\n city\r\n state\r\n country\r\n zip\r\n zip4\r\n }\r\n }\r\n cobPrimacy {\r\n indicator\r\n description\r\n message\r\n }\r\n }\r\n uhgPrimacyStatus {\r\n policyEffectiveDate\r\n policyTerminationDate\r\n primacy {\r\n indicator\r\n description\r\n message\r\n }\r\n }\r\n }\r\n providerNetwork {\r\n status\r\n tier\r\n }\r\n extendedAttributes {\r\n fundingCode\r\n fundingType\r\n hsa\r\n cdhp\r\n governmentProgramCode\r\n cmsPackageBenefitPlanCode\r\n cmsSegmentId\r\n cmsContractId\r\n marketType\r\n obligorId\r\n marketSite\r\n benefitPlanId\r\n virtualVisit\r\n planVariation\r\n groupNumber\r\n legacyPanelNumber\r\n coverageLevel\r\n sharedArrangement\r\n productServiceCode\r\n designatedVirtualClinicNetwork\r\n medicaidVariableCode\r\n healthInsuranceExchangeId\r\n memberDiv\r\n legalEntityCode\r\n }\r\n otherBeneficiaries {\r\n memberId\r\n firstName\r\n lastName\r\n middleName\r\n suffix\r\n dateOfBirth\r\n gender\r\n relationship\r\n relationshipCode\r\n relationshipTypeCode\r\n individualRelationshipCode\r\n dependentSequenceNumber\r\n }\r\n serviceLevels {\r\n family {\r\n networkStatus\r\n services {\r\n isVendorOnly\r\n service\r\n serviceCode\r\n serviceDate\r\n text\r\n status\r\n coPayAmount\r\n coPayFrequency\r\n coInsurancePercent\r\n planAmount\r\n remainingAmount\r\n metYearToDateAmount\r\n isReferralObtainedCopay\r\n isReferralObtainedCoInsurance\r\n referralCopayAmount\r\n referralCoInsurancePercent\r\n benefitsAllowedFrequencies\r\n benefitsRemainingFrequencies\r\n message {\r\n note {\r\n isSingleMessageDetail\r\n isViewDetail\r\n messages\r\n text\r\n subMessages {\r\n service\r\n status\r\n copay\r\n msg\r\n startDate\r\n endDate\r\n minCopay\r\n minCopayMsg\r\n maxCopay\r\n maxCopayMsg\r\n isPrimaryIndicator\r\n }\r\n limitationInfo {\r\n lmtPeriod\r\n lmtType\r\n lmtOccurPerPeriod\r\n lmtDollarPerPeriod\r\n message\r\n }\r\n isMultipleCopaysFound\r\n isMultipleCoinsuranceFound\r\n }\r\n coPay {\r\n isSingleMessageDetail\r\n isViewDetail\r\n messages\r\n text\r\n subMessages {\r\n service\r\n status\r\n copay\r\n msg\r\n startDate\r\n endDate\r\n minCopay\r\n minCopayMsg\r\n maxCopay\r\n maxCopayMsg\r\n isPrimaryIndicator\r\n }\r\n limitationInfo {\r\n lmtPeriod\r\n lmtType\r\n lmtOccurPerPeriod\r\n lmtDollarPerPeriod\r\n message\r\n }\r\n isMultipleCopaysFound\r\n isMultipleCoinsuranceFound\r\n }\r\n coInsurance {\r\n isSingleMessageDetail\r\n isViewDetail\r\n messages\r\n text\r\n subMessages {\r\n service\r\n status\r\n copay\r\n msg\r\n startDate\r\n endDate\r\n minCopay\r\n minCopayMsg\r\n maxCopay\r\n maxCopayMsg\r\n isPrimaryIndicator\r\n }\r\n limitationInfo {\r\n lmtPeriod\r\n lmtType\r\n lmtOccurPerPeriod\r\n lmtDollarPerPeriod\r\n message\r\n }\r\n isMultipleCopaysFound\r\n isMultipleCoinsuranceFound\r\n }\r\n deductible {\r\n isSingleMessageDetail\r\n isViewDetail\r\n messages\r\n text\r\n subMessages {\r\n service\r\n status\r\n copay\r\n msg\r\n startDate\r\n endDate\r\n minCopay\r\n minCopayMsg\r\n maxCopay\r\n maxCopayMsg\r\n isPrimaryIndicator\r\n }\r\n limitationInfo {\r\n lmtPeriod\r\n lmtType\r\n lmtOccurPerPeriod\r\n lmtDollarPerPeriod\r\n message\r\n }\r\n isMultipleCopaysFound\r\n isMultipleCoinsuranceFound\r\n }\r\n benefitsAllowed {\r\n isSingleMessageDetail\r\n isViewDetail\r\n messages\r\n text\r\n subMessages {\r\n service\r\n status\r\n copay\r\n msg\r\n startDate\r\n endDate\r\n minCopay\r\n minCopayMsg\r\n maxCopay\r\n maxCopayMsg\r\n isPrimaryIndicator\r\n }\r\n limitationInfo {\r\n lmtPeriod\r\n lmtType\r\n lmtOccurPerPeriod\r\n lmtDollarPerPeriod\r\n message\r\n }\r\n isMultipleCopaysFound\r\n isMultipleCoinsuranceFound\r\n }\r\n benefitsRemaining {\r\n isSingleMessageDetail\r\n isViewDetail\r\n messages\r\n text\r\n subMessages {\r\n service\r\n status\r\n copay\r\n msg\r\n startDate\r\n endDate\r\n minCopay\r\n minCopayMsg\r\n maxCopay\r\n maxCopayMsg\r\n isPrimaryIndicator\r\n }\r\n limitationInfo {\r\n lmtPeriod\r\n lmtType\r\n lmtOccurPerPeriod\r\n lmtDollarPerPeriod\r\n message\r\n }\r\n isMultipleCopaysFound\r\n isMultipleCoinsuranceFound\r\n }\r\n coPayList\r\n coInsuranceList\r\n }\r\n }\r\n }\r\n }\r\n }\r\n }\r\n}"""
|
145
145
|
|
146
146
|
@staticmethod
|
147
147
|
def build_working_eligibility_request(variables):
|
@@ -424,6 +424,7 @@ class GraphQLResponseTransformer:
|
|
424
424
|
}
|
425
425
|
|
426
426
|
# Convenience functions for easy access
|
427
|
+
|
427
428
|
def get_eligibility_query():
|
428
429
|
"""Get the eligibility GraphQL query (working format)"""
|
429
430
|
return GraphQLQueryBuilder.get_eligibility_query()
|
@@ -433,7 +434,7 @@ def build_eligibility_variables(**kwargs):
|
|
433
434
|
return GraphQLQueryBuilder.build_eligibility_variables(**kwargs)
|
434
435
|
|
435
436
|
def build_eligibility_request(variables):
|
436
|
-
"""Build complete
|
437
|
+
"""Build complete GraphQL request body with working format"""
|
437
438
|
return GraphQLQueryBuilder.build_eligibility_request(variables)
|
438
439
|
|
439
440
|
def transform_eligibility_response(graphql_response):
|
@@ -442,4 +443,62 @@ def transform_eligibility_response(graphql_response):
|
|
442
443
|
|
443
444
|
def get_sample_eligibility_request():
|
444
445
|
"""Get the sample GraphQL request from swagger documentation"""
|
445
|
-
return GraphQLQueryBuilder.get_sample_eligibility_request()
|
446
|
+
return GraphQLQueryBuilder.get_sample_eligibility_request()
|
447
|
+
|
448
|
+
# -----------------------------------------------------------------------------
|
449
|
+
# Phase 2 scaffolding: centralized direct SBR09 extraction (placeholder)
|
450
|
+
# -----------------------------------------------------------------------------
|
451
|
+
|
452
|
+
# Placeholder path for future API-provided SBR09 value.
|
453
|
+
# Accepts either a top-level key (e.g., 'sbr09Code') or a dotted path
|
454
|
+
# (e.g., 'eligibilityInfo.insuranceInfo.sbr09'). Update when contract is finalized.
|
455
|
+
FUTURE_SBR09_FIELD_PATH = '<INSERT_SBR09_FIELD_PATH>'
|
456
|
+
|
457
|
+
|
458
|
+
def _get_nested_value(data, dotted_path):
|
459
|
+
"""Safely get nested value from dict given a dotted path."""
|
460
|
+
try:
|
461
|
+
current = data
|
462
|
+
for part in dotted_path.split('.'):
|
463
|
+
if not isinstance(current, dict) or part not in current:
|
464
|
+
return None
|
465
|
+
current = current[part]
|
466
|
+
return current
|
467
|
+
except Exception:
|
468
|
+
return None
|
469
|
+
|
470
|
+
|
471
|
+
def _is_valid_sbr09(code):
|
472
|
+
if not isinstance(code, str):
|
473
|
+
return False
|
474
|
+
c = code.strip().upper()
|
475
|
+
return 1 <= len(c) <= 3 and c.isalnum()
|
476
|
+
|
477
|
+
|
478
|
+
def _normalize_sbr09(code):
|
479
|
+
return str(code).strip().upper()
|
480
|
+
|
481
|
+
|
482
|
+
def extract_sbr09_direct(response_dict):
|
483
|
+
"""
|
484
|
+
Extract SBR09 directly from a transformed GraphQL response or raw GraphQL if the
|
485
|
+
provider API supplies it. Returns None until FUTURE_SBR09_FIELD_PATH is set and value is present.
|
486
|
+
|
487
|
+
- No mapping is performed. Only format checks are applied.
|
488
|
+
- Accepts either top-level key or dotted path.
|
489
|
+
"""
|
490
|
+
if not FUTURE_SBR09_FIELD_PATH or FUTURE_SBR09_FIELD_PATH.startswith('<'):
|
491
|
+
return None
|
492
|
+
|
493
|
+
# Try top-level lookup
|
494
|
+
raw_value = response_dict.get(FUTURE_SBR09_FIELD_PATH)
|
495
|
+
|
496
|
+
# If not found, try dotted path
|
497
|
+
if raw_value is None and '.' in FUTURE_SBR09_FIELD_PATH:
|
498
|
+
raw_value = _get_nested_value(response_dict, FUTURE_SBR09_FIELD_PATH)
|
499
|
+
|
500
|
+
if raw_value is None:
|
501
|
+
return None
|
502
|
+
|
503
|
+
candidate = _normalize_sbr09(raw_value)
|
504
|
+
return candidate if _is_valid_sbr09(candidate) else None
|