medicafe 0.251017.1__py3-none-any.whl → 0.251026.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 +867 -835
- MediBot/MediBot.py +77 -11
- MediBot/MediBot_Preprocessor_lib.py +1895 -1821
- MediBot/__init__.py +1 -1
- MediCafe/MediLink_ConfigLoader.py +8 -1
- MediCafe/__init__.py +1 -1
- MediCafe/api_core.py +27 -43
- MediCafe/error_reporter.py +90 -113
- MediCafe/graphql_utils.py +40 -21
- MediLink/MediLink_Deductible.py +45 -23
- MediLink/MediLink_Gmail.py +1 -0
- MediLink/MediLink_Up.py +31 -25
- MediLink/MediLink_main.py +65 -58
- MediLink/MediLink_smart_import.py +3 -2
- MediLink/__init__.py +1 -1
- {medicafe-0.251017.1.dist-info → medicafe-0.251026.0.dist-info}/METADATA +1 -1
- {medicafe-0.251017.1.dist-info → medicafe-0.251026.0.dist-info}/RECORD +21 -21
- {medicafe-0.251017.1.dist-info → medicafe-0.251026.0.dist-info}/LICENSE +0 -0
- {medicafe-0.251017.1.dist-info → medicafe-0.251026.0.dist-info}/WHEEL +0 -0
- {medicafe-0.251017.1.dist-info → medicafe-0.251026.0.dist-info}/entry_points.txt +0 -0
- {medicafe-0.251017.1.dist-info → medicafe-0.251026.0.dist-info}/top_level.txt +0 -0
MediLink/MediLink_Deductible.py
CHANGED
|
@@ -549,6 +549,7 @@ def get_eligibility_info(client, payer_id, provider_last_name, date_of_birth, me
|
|
|
549
549
|
# Enable verbose diagnostics in debug mode without config changes
|
|
550
550
|
diagnostics_verbose = True
|
|
551
551
|
sc_preflight_failed = False
|
|
552
|
+
# NOTE: No config flag mutation needed; OPTUMAI call now never auto-falls back
|
|
552
553
|
|
|
553
554
|
# Get legacy response
|
|
554
555
|
MediLink_ConfigLoader.log("Getting legacy get_eligibility_v3 API response", level="INFO")
|
|
@@ -569,8 +570,8 @@ def get_eligibility_info(client, payer_id, provider_last_name, date_of_birth, me
|
|
|
569
570
|
else:
|
|
570
571
|
MediLink_ConfigLoader.log("API client does not support token authentication for Legacy API.", level="WARNING")
|
|
571
572
|
|
|
572
|
-
# Get
|
|
573
|
-
MediLink_ConfigLoader.log("Getting
|
|
573
|
+
# Get OPTUMAI eligibility response for comparison (formerly Super Connector)
|
|
574
|
+
MediLink_ConfigLoader.log("Getting OPTUMAI eligibility API response", level="INFO")
|
|
574
575
|
super_connector_eligibility = None
|
|
575
576
|
try:
|
|
576
577
|
if not sc_preflight_failed:
|
|
@@ -580,32 +581,32 @@ def get_eligibility_info(client, payer_id, provider_last_name, date_of_birth, me
|
|
|
580
581
|
else:
|
|
581
582
|
super_connector_eligibility = None
|
|
582
583
|
except Exception as e:
|
|
583
|
-
MediLink_ConfigLoader.log("
|
|
584
|
+
MediLink_ConfigLoader.log("OPTUMAI eligibility API failed: {}".format(e), level="ERROR")
|
|
584
585
|
# Best-effort triage classification for clearer downstream messaging
|
|
585
586
|
try:
|
|
586
587
|
# Use centralized classifier when available
|
|
587
588
|
from MediCafe.deductible_utils import classify_api_failure
|
|
588
|
-
code, message = classify_api_failure(e, '
|
|
589
|
+
code, message = classify_api_failure(e, 'OPTUMAI eligibility API')
|
|
589
590
|
# Sticky preflight failure for subsequent patients in this run
|
|
590
591
|
if code in ['TIMEOUT', 'CONN_ERR', 'AUTH_FAIL', 'MISCONFIG']:
|
|
591
592
|
sc_preflight_failed = True
|
|
592
593
|
except Exception:
|
|
593
594
|
try:
|
|
594
|
-
failure_reason = "
|
|
595
|
+
failure_reason = "OPTUMAI eligibility API connection failed"
|
|
595
596
|
detail = str(e)
|
|
596
597
|
if requests and hasattr(requests, 'exceptions') and isinstance(e, requests.exceptions.Timeout):
|
|
597
|
-
failure_reason = "
|
|
598
|
+
failure_reason = "OPTUMAI eligibility API timeout"
|
|
598
599
|
elif requests and hasattr(requests, 'exceptions') and isinstance(e, requests.exceptions.ConnectionError):
|
|
599
|
-
failure_reason = "
|
|
600
|
+
failure_reason = "OPTUMAI eligibility API connection error"
|
|
600
601
|
elif "Invalid payer_id" in detail:
|
|
601
|
-
failure_reason = "
|
|
602
|
+
failure_reason = "OPTUMAI eligibility API rejected payer_id"
|
|
602
603
|
elif ("No access token" in detail) or ("token" in detail.lower()):
|
|
603
|
-
failure_reason = "
|
|
604
|
+
failure_reason = "OPTUMAI eligibility API authentication failed"
|
|
604
605
|
elif ("Eligibility endpoint not configured" in detail) or ("endpoint" in detail.lower() and "configured" in detail.lower()):
|
|
605
|
-
failure_reason = "
|
|
606
|
+
failure_reason = "OPTUMAI eligibility API endpoint misconfigured"
|
|
606
607
|
message = "{}: {}".format(failure_reason, detail)
|
|
607
608
|
except Exception:
|
|
608
|
-
message = "
|
|
609
|
+
message = "OPTUMAI eligibility API failed: {}".format(str(e))
|
|
609
610
|
sc_failure_info = {"message": message}
|
|
610
611
|
try:
|
|
611
612
|
error_messages_for_row.append(message)
|
|
@@ -629,22 +630,22 @@ def get_eligibility_info(client, payer_id, provider_last_name, date_of_birth, me
|
|
|
629
630
|
)
|
|
630
631
|
print("\nValidation report generated (legacy only): {}".format(validation_file_path))
|
|
631
632
|
elif super_connector_eligibility:
|
|
632
|
-
# Only
|
|
633
|
+
# Only OPTUMAI eligibility API returned data
|
|
633
634
|
validation_report = MediLink_Deductible_Validator.run_validation_comparison(
|
|
634
635
|
None, super_connector_eligibility, validation_file_path
|
|
635
636
|
)
|
|
636
|
-
print("\nValidation report generated (
|
|
637
|
+
print("\nValidation report generated (OPTUMAI only): {}".format(validation_file_path))
|
|
637
638
|
else:
|
|
638
639
|
# Neither API returned data
|
|
639
640
|
print("\nNo validation report generated - both APIs failed")
|
|
640
641
|
validation_file_path = None
|
|
641
642
|
|
|
642
|
-
# Log any
|
|
643
|
+
# Log any OPTUMAI eligibility API errors if we have that data
|
|
643
644
|
if super_connector_eligibility and "rawGraphQLResponse" in super_connector_eligibility:
|
|
644
645
|
raw_response = super_connector_eligibility.get('rawGraphQLResponse', {})
|
|
645
646
|
errors = raw_response.get('errors', [])
|
|
646
647
|
if errors:
|
|
647
|
-
error_msg = "
|
|
648
|
+
error_msg = "OPTUMAI eligibility API returned {} error(s):".format(len(errors))
|
|
648
649
|
if error_msg not in printed_messages:
|
|
649
650
|
print(error_msg)
|
|
650
651
|
printed_messages.add(error_msg)
|
|
@@ -676,21 +677,42 @@ def get_eligibility_info(client, payer_id, provider_last_name, date_of_birth, me
|
|
|
676
677
|
error_messages_for_row.append("Extensions include {} detail record(s)".format(len(details)))
|
|
677
678
|
except Exception:
|
|
678
679
|
pass
|
|
680
|
+
|
|
681
|
+
# Provide concise terminal hints for 401/403 outcomes (XP-safe)
|
|
682
|
+
def _emit_hint(status_code):
|
|
683
|
+
try:
|
|
684
|
+
if status_code == '401':
|
|
685
|
+
h = "Hint: Authentication failed. Verify API credentials/token and endpoint configuration."
|
|
686
|
+
if h not in printed_messages:
|
|
687
|
+
print(h)
|
|
688
|
+
printed_messages.add(h)
|
|
689
|
+
elif status_code == '403':
|
|
690
|
+
h = "Hint: Access denied. Verify provider TIN/NPI and account permissions/roles."
|
|
691
|
+
if h not in printed_messages:
|
|
692
|
+
print(h)
|
|
693
|
+
printed_messages.add(h)
|
|
694
|
+
except Exception:
|
|
695
|
+
pass
|
|
696
|
+
|
|
697
|
+
try:
|
|
698
|
+
_emit_hint(super_connector_eligibility.get('statuscode'))
|
|
699
|
+
except Exception:
|
|
700
|
+
pass
|
|
679
701
|
|
|
680
702
|
# Check status code
|
|
681
703
|
if super_connector_eligibility:
|
|
682
704
|
status_code = super_connector_eligibility.get('statuscode')
|
|
683
705
|
from MediCafe.deductible_utils import is_ok_200
|
|
684
706
|
if status_code is not None and not is_ok_200(status_code):
|
|
685
|
-
print("
|
|
707
|
+
print("OPTUMAI eligibility API status code: {} (non-200 indicates errors)".format(status_code))
|
|
686
708
|
# Record status code for the row diagnostics
|
|
687
|
-
error_messages_for_row.append("Status code {} from
|
|
709
|
+
error_messages_for_row.append("Status code {} from OPTUMAI eligibility".format(status_code))
|
|
688
710
|
# If Super Connector failed entirely, append a triage note to the validation report (if created)
|
|
689
711
|
try:
|
|
690
712
|
if sc_failure_info and validation_file_path and os.path.exists(validation_file_path):
|
|
691
713
|
with open(validation_file_path, 'a') as vf:
|
|
692
714
|
vf.write("\n" + "-" * 80 + "\n")
|
|
693
|
-
vf.write("
|
|
715
|
+
vf.write("OPTUMAI ELIGIBILITY CONNECTION FAILURE NOTE\n")
|
|
694
716
|
vf.write("-" * 80 + "\n")
|
|
695
717
|
vf.write(sc_failure_info['message'] + "\n")
|
|
696
718
|
vf.write("Recommendation: Verify network connectivity, credentials, payer ID validity, and endpoint configuration.\n")
|
|
@@ -720,7 +742,7 @@ def get_eligibility_info(client, payer_id, provider_last_name, date_of_birth, me
|
|
|
720
742
|
merged_data['error_messages'] = error_messages_for_row
|
|
721
743
|
except Exception:
|
|
722
744
|
pass
|
|
723
|
-
# Surface
|
|
745
|
+
# Surface OPTUMAI eligibility failure prominently in user-facing diagnostics
|
|
724
746
|
try:
|
|
725
747
|
if sc_failure_info and isinstance(merged_data, dict):
|
|
726
748
|
merged_data['super_connector_failed'] = True
|
|
@@ -922,7 +944,7 @@ if __name__ == "__main__":
|
|
|
922
944
|
print("- Crosswalk-based payer ID resolution (O(N) complexity)")
|
|
923
945
|
elif DEBUG_MODE:
|
|
924
946
|
print("\nRunning in DEBUG MODE")
|
|
925
|
-
print("- Dual API calls (Legacy +
|
|
947
|
+
print("- Dual API calls (Legacy + OPTUMAI eligibility)")
|
|
926
948
|
print("- Validation reports and comparisons")
|
|
927
949
|
print("- Detailed logging and error reporting")
|
|
928
950
|
print("- Crosswalk-based payer ID resolution (O(N) complexity)")
|
|
@@ -1172,11 +1194,11 @@ if __name__ == "__main__":
|
|
|
1172
1194
|
output_file.write(table_header + "\n")
|
|
1173
1195
|
output_file.write("-" * len(table_header) + "\n")
|
|
1174
1196
|
|
|
1175
|
-
# Global notice when
|
|
1197
|
+
# Global notice when OPTUMAI eligibility connection failed for any patients
|
|
1176
1198
|
try:
|
|
1177
1199
|
sc_failed_count = sum(1 for r in eligibility_results if isinstance(r, dict) and r.get('super_connector_failed'))
|
|
1178
1200
|
if sc_failed_count:
|
|
1179
|
-
output_file.write("NOTICE:
|
|
1201
|
+
output_file.write("NOTICE: OPTUMAI eligibility API connection failed for {} patient(s). Fallback data used when available.\n".format(sc_failed_count))
|
|
1180
1202
|
except Exception:
|
|
1181
1203
|
pass
|
|
1182
1204
|
|
|
@@ -1239,7 +1261,7 @@ if __name__ == "__main__":
|
|
|
1239
1261
|
else:
|
|
1240
1262
|
print("No validation reports were generated.")
|
|
1241
1263
|
print("This may be because:")
|
|
1242
|
-
print(" -
|
|
1264
|
+
print(" - OPTUMAI eligibility API calls failed")
|
|
1243
1265
|
print(" - Both APIs didn't return data for the same patients")
|
|
1244
1266
|
print(" - Validation report generation encountered errors")
|
|
1245
1267
|
print("=" * 80)
|
MediLink/MediLink_Gmail.py
CHANGED
|
@@ -84,6 +84,7 @@ SCOPES = ' '.join([
|
|
|
84
84
|
'https://www.googleapis.com/auth/gmail.modify',
|
|
85
85
|
'https://www.googleapis.com/auth/gmail.compose',
|
|
86
86
|
'https://www.googleapis.com/auth/gmail.readonly',
|
|
87
|
+
'https://www.googleapis.com/auth/gmail.send',
|
|
87
88
|
'https://www.googleapis.com/auth/script.external_request',
|
|
88
89
|
'https://www.googleapis.com/auth/userinfo.email',
|
|
89
90
|
'https://www.googleapis.com/auth/script.scriptapp',
|
MediLink/MediLink_Up.py
CHANGED
|
@@ -258,16 +258,22 @@ def submit_claims(detailed_patient_data_grouped_by_endpoint, config, crosswalk):
|
|
|
258
258
|
local_claims_path = cfg.get('local_claims_path', '.')
|
|
259
259
|
transmission_result = operate_winscp(operation_type, filtered_files, endpoint_cfg, local_claims_path, config)
|
|
260
260
|
success_dict = handle_transmission_result(transmission_result, config, operation_type, method)
|
|
261
|
+
# If we attempted uploads but could not derive any status, emit explicit failures per file
|
|
262
|
+
if (not success_dict) and filtered_files:
|
|
263
|
+
success_dict = {fp: (False, "No transfer status found in WinSCP log") for fp in filtered_files}
|
|
261
264
|
submission_results[endpoint] = success_dict
|
|
262
265
|
except FileNotFoundError as e:
|
|
263
|
-
|
|
264
|
-
|
|
266
|
+
msg = "Log file not found - {}".format(str(e))
|
|
267
|
+
print("Failed to transmit files to {}. Error: {}".format(endpoint, msg))
|
|
268
|
+
submission_results[endpoint] = {fp: (False, msg) for fp in (filtered_files or [])}
|
|
265
269
|
except IOError as e:
|
|
266
|
-
|
|
267
|
-
|
|
270
|
+
msg = "Input/output error - {}".format(str(e))
|
|
271
|
+
print("Failed to transmit files to {}. Error: {}".format(endpoint, msg))
|
|
272
|
+
submission_results[endpoint] = {fp: (False, msg) for fp in (filtered_files or [])}
|
|
268
273
|
except Exception as e:
|
|
269
|
-
|
|
270
|
-
|
|
274
|
+
msg = str(e)
|
|
275
|
+
print("Failed to transmit files to {}. Error: {}".format(endpoint, msg))
|
|
276
|
+
submission_results[endpoint] = {fp: (False, msg) for fp in (filtered_files or [])}
|
|
271
277
|
elif method == 'api':
|
|
272
278
|
# Transmit files via API
|
|
273
279
|
try:
|
|
@@ -284,10 +290,14 @@ def submit_claims(detailed_patient_data_grouped_by_endpoint, config, crosswalk):
|
|
|
284
290
|
response = {"error": "API module not available"}
|
|
285
291
|
api_responses.append((file_path, response))
|
|
286
292
|
success_dict = handle_transmission_result(api_responses, config, "api", method)
|
|
293
|
+
# If API call path yielded no status, emit explicit failures per file attempted
|
|
294
|
+
if (not success_dict) and filtered_files:
|
|
295
|
+
success_dict = {fp: (False, "No API response parsed") for fp in filtered_files}
|
|
287
296
|
submission_results[endpoint] = success_dict
|
|
288
297
|
except Exception as e:
|
|
289
|
-
|
|
290
|
-
|
|
298
|
+
msg = str(e)
|
|
299
|
+
print("Failed to transmit files via API to {}. Error: {}".format(endpoint, msg))
|
|
300
|
+
submission_results[endpoint] = {fp: (False, msg) for fp in (filtered_files or [])}
|
|
291
301
|
else:
|
|
292
302
|
print("No files were converted for transmission to {}.".format(endpoint))
|
|
293
303
|
else:
|
|
@@ -495,29 +505,25 @@ def prepare_receipt_data(submission_results):
|
|
|
495
505
|
log("File path: {}".format(file_path), level="DEBUG")
|
|
496
506
|
log("File result: {}".format(file_result), level="DEBUG")
|
|
497
507
|
|
|
498
|
-
|
|
499
|
-
# Unpack the tuple to get status and message
|
|
500
|
-
status, message = file_result
|
|
501
|
-
except ValueError as e:
|
|
502
|
-
file_result_length = len(file_result) if hasattr(file_result, '__len__') else 'Unknown'
|
|
503
|
-
error_msg = 'Too many values to unpack.' if 'too many values to unpack' in str(e) else \
|
|
504
|
-
'Not enough values to unpack.' if 'not enough values to unpack' in str(e) else \
|
|
505
|
-
'Value unpacking error.'
|
|
506
|
-
log("ValueError: {} for file_result: {} (Length: {})".format(error_msg, file_result, file_result_length), level="ERROR")
|
|
507
|
-
continue
|
|
508
|
-
except Exception as e:
|
|
509
|
-
tb = traceback.format_exc()
|
|
510
|
-
log("Unexpected error: {}. Traceback: {}".format(e, tb), level="ERROR")
|
|
511
|
-
continue
|
|
512
|
-
|
|
513
|
-
log("Status: {}, Message: {}".format(status, message), level="DEBUG")
|
|
514
|
-
|
|
508
|
+
# Ensure endpoint bucket exists even if result shape is unexpected
|
|
515
509
|
if endpoint not in receipt_data:
|
|
516
510
|
receipt_data[endpoint] = {
|
|
517
511
|
"patients": [],
|
|
518
512
|
"date_of_submission": datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
|
519
513
|
}
|
|
520
514
|
|
|
515
|
+
# Normalize result tuple shape; on unexpected shape, degrade to (False, stringified)
|
|
516
|
+
try:
|
|
517
|
+
status, message = file_result
|
|
518
|
+
except Exception:
|
|
519
|
+
status = False
|
|
520
|
+
try:
|
|
521
|
+
message = str(file_result)
|
|
522
|
+
except Exception:
|
|
523
|
+
message = "Unknown result"
|
|
524
|
+
|
|
525
|
+
log("Status: {}, Message: {}".format(status, message), level="DEBUG")
|
|
526
|
+
|
|
521
527
|
# Parse patient details and add the result status and message
|
|
522
528
|
patient_data, _ = parse_837p_file(file_path)
|
|
523
529
|
for patient in patient_data:
|
MediLink/MediLink_main.py
CHANGED
|
@@ -22,7 +22,8 @@ if PERFORMANCE_LOGGING:
|
|
|
22
22
|
|
|
23
23
|
# Now import core utilities after path setup
|
|
24
24
|
from MediCafe.core_utils import get_shared_config_loader, setup_module_paths, extract_medilink_config
|
|
25
|
-
from MediCafe.error_reporter import
|
|
25
|
+
from MediCafe.error_reporter import collect_support_bundle, capture_unhandled_traceback
|
|
26
|
+
from MediCafe.error_reporter import submit_support_bundle_email
|
|
26
27
|
setup_module_paths(__file__)
|
|
27
28
|
|
|
28
29
|
# Import modules after path setup
|
|
@@ -41,6 +42,20 @@ if PERFORMANCE_LOGGING:
|
|
|
41
42
|
|
|
42
43
|
# NOTE: Configuration loading moved to function level to avoid import-time dependencies
|
|
43
44
|
|
|
45
|
+
# --- Safe logging helpers (XP/3.4.4 compatible) ---
|
|
46
|
+
def _safe_log(message, level="INFO"):
|
|
47
|
+
"""Attempt to log via MediLink logger, fallback to print on failure."""
|
|
48
|
+
try:
|
|
49
|
+
MediLink_ConfigLoader.log(message, level=level)
|
|
50
|
+
except Exception:
|
|
51
|
+
try:
|
|
52
|
+
print(message)
|
|
53
|
+
except Exception:
|
|
54
|
+
pass
|
|
55
|
+
|
|
56
|
+
def _safe_debug(message):
|
|
57
|
+
_safe_log(message, level="DEBUG")
|
|
58
|
+
|
|
44
59
|
# TODO There needs to be a crosswalk auditing feature right alongside where all the names get fetched during initial startup maybe?
|
|
45
60
|
# Vision:
|
|
46
61
|
# - Fast audit pass on startup with 3s timeout: report missing names/IDs, do not block.
|
|
@@ -58,8 +73,7 @@ def _tools_menu(config, medi):
|
|
|
58
73
|
print("\nMaintenance Tools:")
|
|
59
74
|
options = [
|
|
60
75
|
"Rebuild submission index now",
|
|
61
|
-
"Submit Error Report (
|
|
62
|
-
"Create Support Bundle (offline)",
|
|
76
|
+
"Submit Error Report (email)",
|
|
63
77
|
"Back"
|
|
64
78
|
]
|
|
65
79
|
MediLink_UI.display_menu(options)
|
|
@@ -79,26 +93,26 @@ def _tools_menu(config, medi):
|
|
|
79
93
|
print("Index rebuild error: {}".format(e))
|
|
80
94
|
elif choice == '2':
|
|
81
95
|
try:
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
if not zip_path:
|
|
85
|
-
print("Failed to create support bundle.")
|
|
96
|
+
if submit_support_bundle_email is None:
|
|
97
|
+
print("Email submission module not available.")
|
|
86
98
|
else:
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
99
|
+
print("\nSubmitting Error Report (email)...")
|
|
100
|
+
zip_path = collect_support_bundle(include_traceback=True)
|
|
101
|
+
if not zip_path:
|
|
102
|
+
print("Failed to create support bundle.")
|
|
103
|
+
else:
|
|
104
|
+
ok = submit_support_bundle_email(zip_path)
|
|
105
|
+
if ok:
|
|
106
|
+
# Optional: remove the file upon success to avoid re-sending on next startup
|
|
107
|
+
try:
|
|
108
|
+
os.remove(zip_path)
|
|
109
|
+
except Exception:
|
|
110
|
+
pass
|
|
111
|
+
else:
|
|
112
|
+
print("Submission failed. Bundle saved at {} for manual handling.".format(zip_path))
|
|
90
113
|
except Exception as e:
|
|
91
|
-
print("Error during report submission: {}".format(e))
|
|
114
|
+
print("Error during email report submission: {}".format(e))
|
|
92
115
|
elif choice == '3':
|
|
93
|
-
try:
|
|
94
|
-
zip_path = collect_support_bundle(include_traceback=True)
|
|
95
|
-
if zip_path:
|
|
96
|
-
print("Support bundle created: {}".format(zip_path))
|
|
97
|
-
else:
|
|
98
|
-
print("Failed to create support bundle.")
|
|
99
|
-
except Exception as e:
|
|
100
|
-
print("Error creating support bundle: {}".format(e))
|
|
101
|
-
elif choice == '4':
|
|
102
116
|
break
|
|
103
117
|
else:
|
|
104
118
|
MediLink_UI.display_invalid_choice()
|
|
@@ -181,8 +195,8 @@ def main_menu():
|
|
|
181
195
|
# Clear screen before showing menu header
|
|
182
196
|
try:
|
|
183
197
|
os.system('cls' if os.name == 'nt' else 'clear')
|
|
184
|
-
except Exception:
|
|
185
|
-
|
|
198
|
+
except Exception as e:
|
|
199
|
+
_safe_debug("Clear screen failed: {}".format(e)) # Fallback if cls/clear fails
|
|
186
200
|
|
|
187
201
|
# Display Welcome Message
|
|
188
202
|
welcome_start = time.time()
|
|
@@ -191,14 +205,7 @@ def main_menu():
|
|
|
191
205
|
if PERFORMANCE_LOGGING:
|
|
192
206
|
print("Welcome display completed in {:.2f} seconds".format(welcome_end - welcome_start))
|
|
193
207
|
|
|
194
|
-
# Startup: flush
|
|
195
|
-
try:
|
|
196
|
-
print("\nChecking for queued error reports...")
|
|
197
|
-
uploaded, total = flush_queued_reports()
|
|
198
|
-
if total:
|
|
199
|
-
print("Queued reports: {} | Uploaded now: {}".format(total, uploaded))
|
|
200
|
-
except Exception:
|
|
201
|
-
pass
|
|
208
|
+
# Startup: (removed) automatic HTTP queue flush for error reports to simplify UX
|
|
202
209
|
|
|
203
210
|
# Show message if new records were found during boot-time scan. TODO we need this to use the 'Last acknowledgements update:' timestamp to decide if it has already run in the last day so
|
|
204
211
|
# that we're not running it multiple times in rapid succession automatically. (user-initiated checks are fine like via selection of (1. Check for new remittances))
|
|
@@ -256,8 +263,8 @@ def main_menu():
|
|
|
256
263
|
_last_ack_updated_at = now_ts
|
|
257
264
|
# remove executed
|
|
258
265
|
_scheduled_ack_checks = [t for t in _scheduled_ack_checks if t > now_ts]
|
|
259
|
-
except Exception:
|
|
260
|
-
|
|
266
|
+
except Exception as e:
|
|
267
|
+
_safe_log("Scheduled acknowledgements check skipped: {}".format(e), level="WARNING")
|
|
261
268
|
|
|
262
269
|
# Define static menu options for consistent numbering
|
|
263
270
|
options = ["Check for new remittances", "Submit claims", "Exit", "Tools"]
|
|
@@ -269,8 +276,8 @@ def main_menu():
|
|
|
269
276
|
if _last_ack_updated_at:
|
|
270
277
|
ts_str = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(_last_ack_updated_at))
|
|
271
278
|
print("Last acknowledgements update: {}".format(ts_str))
|
|
272
|
-
except Exception:
|
|
273
|
-
|
|
279
|
+
except Exception as e:
|
|
280
|
+
_safe_debug("Display of last ack update failed: {}".format(e))
|
|
274
281
|
MediLink_UI.display_menu(options)
|
|
275
282
|
menu_display_end = time.time()
|
|
276
283
|
if PERFORMANCE_LOGGING:
|
|
@@ -483,33 +490,33 @@ if __name__ == "__main__":
|
|
|
483
490
|
print("\nOperation cancelled by user.")
|
|
484
491
|
exit_code = 1
|
|
485
492
|
except Exception as e:
|
|
486
|
-
# Unexpected error: still avoid full traceback, present succinct notice
|
|
487
493
|
sys.stderr.write("An unexpected error occurred; process halted.\n")
|
|
488
494
|
sys.stderr.write(str(e) + "\n")
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
495
|
+
from MediCafe.error_reporter import collect_support_bundle
|
|
496
|
+
zip_path = collect_support_bundle(include_traceback=True)
|
|
497
|
+
if not zip_path:
|
|
498
|
+
print("Failed to create bundle - exiting.")
|
|
499
|
+
exit_code = 1
|
|
500
|
+
else:
|
|
501
|
+
from MediLink.MediLink_Up import check_internet_connection
|
|
502
|
+
online = check_internet_connection()
|
|
503
|
+
if online:
|
|
504
|
+
success = submit_support_bundle_email(zip_path)
|
|
505
|
+
if not success:
|
|
506
|
+
print("Send failed - bundle discarded.")
|
|
507
|
+
else:
|
|
508
|
+
ans = input("Offline. Connect to internet, then press Y to retry or N to discard: ").strip().lower()
|
|
509
|
+
if ans == 'y':
|
|
510
|
+
online = check_internet_connection()
|
|
511
|
+
if online:
|
|
512
|
+
success = submit_support_bundle_email(zip_path)
|
|
513
|
+
if not success:
|
|
514
|
+
print("Send failed - bundle discarded.")
|
|
504
515
|
else:
|
|
505
|
-
print("
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
try:
|
|
510
|
-
input()
|
|
511
|
-
except Exception:
|
|
512
|
-
pass
|
|
516
|
+
print("Still offline - discarding.")
|
|
517
|
+
else:
|
|
518
|
+
print("Discarding.")
|
|
519
|
+
os.remove(zip_path) if os.path.exists(zip_path) else None
|
|
513
520
|
exit_code = 1
|
|
514
521
|
finally:
|
|
515
522
|
if exit_code == 0 and PERFORMANCE_LOGGING:
|
|
@@ -55,8 +55,9 @@ except Exception as e:
|
|
|
55
55
|
medilink_ui = None
|
|
56
56
|
medilink_patient_processor = None
|
|
57
57
|
print("[+] Fallback to core components")
|
|
58
|
-
except:
|
|
59
|
-
|
|
58
|
+
except Exception as e:
|
|
59
|
+
# Keep non-blocking behavior; include reason for easier debugging
|
|
60
|
+
print("[-] Smart import system not available: {}".format(e))
|
|
60
61
|
api_core = None
|
|
61
62
|
logging_config = None
|
|
62
63
|
core_utils = None
|
MediLink/__init__.py
CHANGED
|
@@ -1,18 +1,18 @@
|
|
|
1
|
-
MediBot/MediBot.bat,sha256=
|
|
2
|
-
MediBot/MediBot.py,sha256=
|
|
1
|
+
MediBot/MediBot.bat,sha256=vWcKZK7MdNIAnGpvpaSglN5DiAlKJVBpdtYwfQfpSQA,28234
|
|
2
|
+
MediBot/MediBot.py,sha256=ABSqWikb_c1VSuR4n8Vh5YfOqzDCi2jnnp3sg_xOYg0,51092
|
|
3
3
|
MediBot/MediBot_Charges.py,sha256=a28if_f_IoazIHiqlaFosFnfEgEoCwb9LQ6aOyk5-D0,10704
|
|
4
4
|
MediBot/MediBot_Crosswalk_Library.py,sha256=6LrpRx2UKVeH3TspS9LpR93iw5M7nTqN6IYpC-6PPGE,26060
|
|
5
5
|
MediBot/MediBot_Crosswalk_Utils.py,sha256=dFJRB_8q0iiAxZ2GY-2HsMl5Z7FvkXezzwx6LZoAglI,39589
|
|
6
6
|
MediBot/MediBot_Notepad_Utils.py,sha256=fOsjyfoSpgmQyc8TcnLm53faLMOUUL18cspo5PZqJK4,8719
|
|
7
7
|
MediBot/MediBot_Post.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
8
8
|
MediBot/MediBot_Preprocessor.py,sha256=gQRVAWbRHx_PMK6a7q93tp7Z-Dhjn5r0lJz3d0wAzeU,19067
|
|
9
|
-
MediBot/MediBot_Preprocessor_lib.py,sha256=
|
|
9
|
+
MediBot/MediBot_Preprocessor_lib.py,sha256=UsUUoleKvWsykIfOvOWwoPHNsWkxfegK20mtN8F4eLs,94583
|
|
10
10
|
MediBot/MediBot_UI.py,sha256=tQISM2gULmQVc4JbeVsn4pjgOYsQZiJpx1_IU407rO8,25870
|
|
11
11
|
MediBot/MediBot_dataformat_library.py,sha256=D46fdPtxcgfWTzaLBtSvjtozzZBNqNiODgu4vKMZrBg,10746
|
|
12
12
|
MediBot/MediBot_debug.bat,sha256=F5Lfi3nFEEo4Ddx9EbX94u3fNAMgzMp3wsn-ULyASTM,6017
|
|
13
13
|
MediBot/MediBot_docx_decoder.py,sha256=9BSjV-kB90VHnqfL_5iX4zl5u0HcHvHuL7YNfx3gXpQ,33143
|
|
14
14
|
MediBot/MediBot_smart_import.py,sha256=Emvz7NwemHGCHvG5kZcUyXMcCheidbGKaPfOTg-YCEs,6684
|
|
15
|
-
MediBot/__init__.py,sha256=
|
|
15
|
+
MediBot/__init__.py,sha256=n9eH1i-SUxoIZz_mxReofqPsZKeOCtWKIIL8cd9XbSg,3192
|
|
16
16
|
MediBot/clear_cache.bat,sha256=F6-VhETWw6xDdGWG2wUqvtXjCl3lY4sSUFqF90bM8-8,1860
|
|
17
17
|
MediBot/crash_diagnostic.bat,sha256=j8kUtyBg6NOWbXpeFuEqIRHOkVzgUrLOqO3FBMfNxTo,9268
|
|
18
18
|
MediBot/f_drive_diagnostic.bat,sha256=4572hZaiwZ5wVAarPcZJQxkOSTwAdDuT_X914noARak,6878
|
|
@@ -21,16 +21,16 @@ MediBot/get_medicafe_version.py,sha256=uyL_UIE42MyFuJ3SRYxJp8sZx8xjTqlYZ3FdQuxLd
|
|
|
21
21
|
MediBot/process_csvs.bat,sha256=3tI7h1z9eRj8rUUL4wJ7dy-Qrak20lRmpAPtGbUMbVQ,3489
|
|
22
22
|
MediBot/update_json.py,sha256=vvUF4mKCuaVly8MmoadDO59M231fCIInc0KI1EtDtPA,3704
|
|
23
23
|
MediBot/update_medicafe.py,sha256=G1lyvVOHYuho1d-TJQNN6qaB4HBWaJ2PpXqemBoPlRQ,17937
|
|
24
|
-
MediCafe/MediLink_ConfigLoader.py,sha256=
|
|
25
|
-
MediCafe/__init__.py,sha256=
|
|
24
|
+
MediCafe/MediLink_ConfigLoader.py,sha256=5AWsiy99WFcESXkzKbftT5afAoMygmb5-d0bER9TZSU,11419
|
|
25
|
+
MediCafe/__init__.py,sha256=_Eh2UabfrQ1hrTeW1LQA7ovRn13NBmR7jzzSmQwIK9c,5721
|
|
26
26
|
MediCafe/__main__.py,sha256=mRNyk3D9Ilnu2XhgVI_rut7r5Ro7UIKtwV871giAHI8,12992
|
|
27
|
-
MediCafe/api_core.py,sha256=
|
|
27
|
+
MediCafe/api_core.py,sha256=wLAdRNZdmovKReXvzsmAgKrbYon4-wbJbGCyOm_C3AU,89896
|
|
28
28
|
MediCafe/api_factory.py,sha256=I5AeJoyu6m7oCrjc2OvVvO_4KSBRutTsR1riiWhTZV0,12086
|
|
29
29
|
MediCafe/api_utils.py,sha256=KWQB0q1k5E6frOFFlKWcFpHNcqfrS7KJ_82672wbupw,14041
|
|
30
30
|
MediCafe/core_utils.py,sha256=XKUpyv7yKjIQ8iNrhD76PIURyt6GZxb98v0daiI7aaw,27303
|
|
31
31
|
MediCafe/deductible_utils.py,sha256=-ixDYwI3JNAyACrFjKqoX_hD3Awzownq441U0PSrwXw,64932
|
|
32
|
-
MediCafe/error_reporter.py,sha256=
|
|
33
|
-
MediCafe/graphql_utils.py,sha256=
|
|
32
|
+
MediCafe/error_reporter.py,sha256=TfRih7pOiopLoYKf--20-Q3q_FCFGEvUw85k3QmlzZ4,8413
|
|
33
|
+
MediCafe/graphql_utils.py,sha256=jo4CboMb9i5_qD0jkfrLbL87_Q3aFiwOntZhjF9fMsI,51928
|
|
34
34
|
MediCafe/logging_config.py,sha256=auT65LN5oDEXVhkMeLke63kJHTWxYf2o8YihAfQFgzU,5493
|
|
35
35
|
MediCafe/logging_demo.py,sha256=TwUhzafna5pMdN3zSKGrpUWRqX96F1JGGsSUtr3dygs,1975
|
|
36
36
|
MediCafe/migration_helpers.py,sha256=48GnP4xcgvDNNlzoWsKASCpF4H0KnyveHPbz6kjQy50,17737
|
|
@@ -47,31 +47,31 @@ MediLink/MediLink_Charges.py,sha256=82fnqHGvT7tfdfjucnFHiLdUE0WhHDXrcS0k_Ln3c8U,
|
|
|
47
47
|
MediLink/MediLink_ClaimStatus.py,sha256=nKX7QymhCULiaGfISYw_P0Eqy0TP6qKG4C2d3TdGFVo,22720
|
|
48
48
|
MediLink/MediLink_DataMgmt.py,sha256=9hc5jyWU65nYT66afDybOyYAcW-DvEYuHpWTun96U50,52407
|
|
49
49
|
MediLink/MediLink_Decoder.py,sha256=1gzdybNg4Vv69s5PNbX8bPNrXT_N_kPpFpt2HpkauWA,16430
|
|
50
|
-
MediLink/MediLink_Deductible.py,sha256=
|
|
50
|
+
MediLink/MediLink_Deductible.py,sha256=opGa5YQ6tfowurlf8xDWRtAtQMmoNYout0gYe3R5fUE,69537
|
|
51
51
|
MediLink/MediLink_Deductible_Validator.py,sha256=x6tHJOi88TblUpDPSH6QhIdXXRgr3rXI7kYPVGZYCgU,24998
|
|
52
52
|
MediLink/MediLink_Display_Utils.py,sha256=MonsX6VPbdvqwY_V8sHUYrXCS0fMKc4toJvG0oyr-V4,24872
|
|
53
53
|
MediLink/MediLink_Down.py,sha256=s4_z-RaqHYanjwbQCl-OSkg4XIpcIQ2Q6jXa8-q_QXw,28111
|
|
54
|
-
MediLink/MediLink_Gmail.py,sha256=
|
|
54
|
+
MediLink/MediLink_Gmail.py,sha256=zJI-pD9cfOhI7M3jJMQ6rrwnzT5wWmSMrI9DcvtXjNw,28688
|
|
55
55
|
MediLink/MediLink_Mailer.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
56
56
|
MediLink/MediLink_Parser.py,sha256=eRVZ4ckZ5gDOrcvtCUZP3DOd3Djly66rCIk0aYXLz14,12567
|
|
57
57
|
MediLink/MediLink_PatientProcessor.py,sha256=9r2w4p45d30Tn0kbXL3j5574MYOehP83tDirNOw_Aek,19977
|
|
58
58
|
MediLink/MediLink_Scan.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
59
59
|
MediLink/MediLink_Scheduler.py,sha256=UJvxhDvHraqra2_TlQVlGeh5jRFrrfK6nCVUHnKOEMY,38
|
|
60
60
|
MediLink/MediLink_UI.py,sha256=ZEJ14EGh7pDu1XjAdORDFiay4UtTsLNWwNSJ0prHFWg,10381
|
|
61
|
-
MediLink/MediLink_Up.py,sha256=
|
|
61
|
+
MediLink/MediLink_Up.py,sha256=rzhzmWa4F_el37bDlSauFl_08m-dWz2xiflf-vVRkwg,38453
|
|
62
62
|
MediLink/MediLink_insurance_utils.py,sha256=g741Fj2K26cMy0JX5d_XavMw9LgkK6hjaUJYfysT7t8,9301
|
|
63
|
-
MediLink/MediLink_main.py,sha256=
|
|
64
|
-
MediLink/MediLink_smart_import.py,sha256=
|
|
63
|
+
MediLink/MediLink_main.py,sha256=bKCV_EDwc3DxQPFp5p0Lwy_cGXM3pexIA0HUhyAAtzw,25342
|
|
64
|
+
MediLink/MediLink_smart_import.py,sha256=ZUXvAkIA2Pk2uuyLZazKfKK8YGdkZt1VAeZo_ZSUyxk,9942
|
|
65
65
|
MediLink/Soumit_api.py,sha256=5JfOecK98ZC6NpZklZW2AkOzkjvrbYxpJpZNH3rFxDw,497
|
|
66
|
-
MediLink/__init__.py,sha256=
|
|
66
|
+
MediLink/__init__.py,sha256=AzRCYizAUAcX8EnSBzpU8dWGLewh3sx-S1ooKPtowGc,3888
|
|
67
67
|
MediLink/gmail_http_utils.py,sha256=mYChIhkbA1oJaAJA-nY3XgHQY-H7zvZJUZPhUagomsI,4047
|
|
68
68
|
MediLink/gmail_oauth_utils.py,sha256=Ugr-DEqs4_RddRMSCJ_dbgA3TVeaxpbAor-dktcTIgY,3713
|
|
69
69
|
MediLink/openssl.cnf,sha256=76VdcGCykf0Typyiv8Wd1mMVKixrQ5RraG6HnfKFqTo,887
|
|
70
70
|
MediLink/test.py,sha256=DM_E8gEbhbVfTAm3wTMiNnK2GCD1e5eH6gwTk89QIc4,3116
|
|
71
71
|
MediLink/webapp.html,sha256=DwDYjVvluGJ7eDdvEogfKN4t24ZJRoIUuSBfCYCL-3w,21252
|
|
72
|
-
medicafe-0.
|
|
73
|
-
medicafe-0.
|
|
74
|
-
medicafe-0.
|
|
75
|
-
medicafe-0.
|
|
76
|
-
medicafe-0.
|
|
77
|
-
medicafe-0.
|
|
72
|
+
medicafe-0.251026.0.dist-info/LICENSE,sha256=65lb-vVujdQK7uMH3RRJSMwUW-WMrMEsc5sOaUn2xUk,1096
|
|
73
|
+
medicafe-0.251026.0.dist-info/METADATA,sha256=_UOU1GmZO36NbpKgD7pwHoqyKolvBmDRgnj3FHQdLgo,3414
|
|
74
|
+
medicafe-0.251026.0.dist-info/WHEEL,sha256=oiQVh_5PnQM0E3gPdiz09WCNmwiHDMaGer_elqB3coM,92
|
|
75
|
+
medicafe-0.251026.0.dist-info/entry_points.txt,sha256=m3RBUBjr-xRwEkKJ5W4a7NlqHZP_1rllGtjZnrRqKe8,52
|
|
76
|
+
medicafe-0.251026.0.dist-info/top_level.txt,sha256=U6-WBJ9RCEjyIs0BlzbQq_PwedCp_IV9n1616NNV5zA,26
|
|
77
|
+
medicafe-0.251026.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|