medicafe 0.250813.0__tar.gz → 0.250813.1__tar.gz
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.
- {medicafe-0.250813.0 → medicafe-0.250813.1}/MediBot/update_medicafe.py +73 -61
- {medicafe-0.250813.0 → medicafe-0.250813.1}/MediLink/MediLink_Down.py +254 -9
- {medicafe-0.250813.0 → medicafe-0.250813.1}/MediLink/MediLink_main.py +41 -10
- {medicafe-0.250813.0/medicafe.egg-info → medicafe-0.250813.1}/PKG-INFO +1 -1
- {medicafe-0.250813.0 → medicafe-0.250813.1/medicafe.egg-info}/PKG-INFO +1 -1
- {medicafe-0.250813.0 → medicafe-0.250813.1}/setup.py +1 -1
- {medicafe-0.250813.0 → medicafe-0.250813.1}/LICENSE +0 -0
- {medicafe-0.250813.0 → medicafe-0.250813.1}/MANIFEST.in +0 -0
- {medicafe-0.250813.0 → medicafe-0.250813.1}/MediBot/MediBot.bat +0 -0
- {medicafe-0.250813.0 → medicafe-0.250813.1}/MediBot/MediBot.py +0 -0
- {medicafe-0.250813.0 → medicafe-0.250813.1}/MediBot/MediBot_Charges.py +0 -0
- {medicafe-0.250813.0 → medicafe-0.250813.1}/MediBot/MediBot_Crosswalk_Library.py +0 -0
- {medicafe-0.250813.0 → medicafe-0.250813.1}/MediBot/MediBot_Crosswalk_Utils.py +0 -0
- {medicafe-0.250813.0 → medicafe-0.250813.1}/MediBot/MediBot_Post.py +0 -0
- {medicafe-0.250813.0 → medicafe-0.250813.1}/MediBot/MediBot_Preprocessor.py +0 -0
- {medicafe-0.250813.0 → medicafe-0.250813.1}/MediBot/MediBot_Preprocessor_lib.py +0 -0
- {medicafe-0.250813.0 → medicafe-0.250813.1}/MediBot/MediBot_UI.py +0 -0
- {medicafe-0.250813.0 → medicafe-0.250813.1}/MediBot/MediBot_dataformat_library.py +0 -0
- {medicafe-0.250813.0 → medicafe-0.250813.1}/MediBot/MediBot_docx_decoder.py +0 -0
- {medicafe-0.250813.0 → medicafe-0.250813.1}/MediBot/MediBot_smart_import.py +0 -0
- {medicafe-0.250813.0 → medicafe-0.250813.1}/MediBot/__init__.py +0 -0
- {medicafe-0.250813.0 → medicafe-0.250813.1}/MediBot/get_medicafe_version.py +0 -0
- {medicafe-0.250813.0 → medicafe-0.250813.1}/MediBot/update_json.py +0 -0
- {medicafe-0.250813.0 → medicafe-0.250813.1}/MediCafe/MediLink_ConfigLoader.py +0 -0
- {medicafe-0.250813.0 → medicafe-0.250813.1}/MediCafe/__init__.py +0 -0
- {medicafe-0.250813.0 → medicafe-0.250813.1}/MediCafe/__main__.py +0 -0
- {medicafe-0.250813.0 → medicafe-0.250813.1}/MediCafe/api_core.py +0 -0
- {medicafe-0.250813.0 → medicafe-0.250813.1}/MediCafe/api_core_backup.py +0 -0
- {medicafe-0.250813.0 → medicafe-0.250813.1}/MediCafe/api_factory.py +0 -0
- {medicafe-0.250813.0 → medicafe-0.250813.1}/MediCafe/api_utils.py +0 -0
- {medicafe-0.250813.0 → medicafe-0.250813.1}/MediCafe/core_utils.py +0 -0
- {medicafe-0.250813.0 → medicafe-0.250813.1}/MediCafe/graphql_utils.py +0 -0
- {medicafe-0.250813.0 → medicafe-0.250813.1}/MediCafe/logging_config.py +0 -0
- {medicafe-0.250813.0 → medicafe-0.250813.1}/MediCafe/logging_demo.py +0 -0
- {medicafe-0.250813.0 → medicafe-0.250813.1}/MediCafe/migration_helpers.py +0 -0
- {medicafe-0.250813.0 → medicafe-0.250813.1}/MediCafe/smart_import.py +0 -0
- {medicafe-0.250813.0 → medicafe-0.250813.1}/MediCafe/submission_index.py +0 -0
- {medicafe-0.250813.0 → medicafe-0.250813.1}/MediLink/InsuranceTypeService.py +0 -0
- {medicafe-0.250813.0 → medicafe-0.250813.1}/MediLink/MediLink_837p_cob_library.py +0 -0
- {medicafe-0.250813.0 → medicafe-0.250813.1}/MediLink/MediLink_837p_encoder.py +0 -0
- {medicafe-0.250813.0 → medicafe-0.250813.1}/MediLink/MediLink_837p_encoder_library.py +0 -0
- {medicafe-0.250813.0 → medicafe-0.250813.1}/MediLink/MediLink_837p_utilities.py +0 -0
- {medicafe-0.250813.0 → medicafe-0.250813.1}/MediLink/MediLink_API_Generator.py +0 -0
- {medicafe-0.250813.0 → medicafe-0.250813.1}/MediLink/MediLink_Azure.py +0 -0
- {medicafe-0.250813.0 → medicafe-0.250813.1}/MediLink/MediLink_ClaimStatus.py +0 -0
- {medicafe-0.250813.0 → medicafe-0.250813.1}/MediLink/MediLink_DataMgmt.py +0 -0
- {medicafe-0.250813.0 → medicafe-0.250813.1}/MediLink/MediLink_Decoder.py +0 -0
- {medicafe-0.250813.0 → medicafe-0.250813.1}/MediLink/MediLink_Deductible.py +0 -0
- {medicafe-0.250813.0 → medicafe-0.250813.1}/MediLink/MediLink_Deductible_Validator.py +0 -0
- {medicafe-0.250813.0 → medicafe-0.250813.1}/MediLink/MediLink_Display_Utils.py +0 -0
- {medicafe-0.250813.0 → medicafe-0.250813.1}/MediLink/MediLink_Gmail.py +0 -0
- {medicafe-0.250813.0 → medicafe-0.250813.1}/MediLink/MediLink_Mailer.py +0 -0
- {medicafe-0.250813.0 → medicafe-0.250813.1}/MediLink/MediLink_Parser.py +0 -0
- {medicafe-0.250813.0 → medicafe-0.250813.1}/MediLink/MediLink_PatientProcessor.py +0 -0
- {medicafe-0.250813.0 → medicafe-0.250813.1}/MediLink/MediLink_Scan.py +0 -0
- {medicafe-0.250813.0 → medicafe-0.250813.1}/MediLink/MediLink_Scheduler.py +0 -0
- {medicafe-0.250813.0 → medicafe-0.250813.1}/MediLink/MediLink_UI.py +0 -0
- {medicafe-0.250813.0 → medicafe-0.250813.1}/MediLink/MediLink_Up.py +0 -0
- {medicafe-0.250813.0 → medicafe-0.250813.1}/MediLink/MediLink_insurance_utils.py +0 -0
- {medicafe-0.250813.0 → medicafe-0.250813.1}/MediLink/MediLink_smart_import.py +0 -0
- {medicafe-0.250813.0 → medicafe-0.250813.1}/MediLink/Soumit_api.py +0 -0
- {medicafe-0.250813.0 → medicafe-0.250813.1}/MediLink/__init__.py +0 -0
- {medicafe-0.250813.0 → medicafe-0.250813.1}/MediLink/gmail_http_utils.py +0 -0
- {medicafe-0.250813.0 → medicafe-0.250813.1}/MediLink/gmail_oauth_utils.py +0 -0
- {medicafe-0.250813.0 → medicafe-0.250813.1}/MediLink/insurance_type_integration_test.py +0 -0
- {medicafe-0.250813.0 → medicafe-0.250813.1}/MediLink/openssl.cnf +0 -0
- {medicafe-0.250813.0 → medicafe-0.250813.1}/MediLink/test.py +0 -0
- {medicafe-0.250813.0 → medicafe-0.250813.1}/MediLink/test_cob_library.py +0 -0
- {medicafe-0.250813.0 → medicafe-0.250813.1}/MediLink/test_timing.py +0 -0
- {medicafe-0.250813.0 → medicafe-0.250813.1}/MediLink/test_validation.py +0 -0
- {medicafe-0.250813.0 → medicafe-0.250813.1}/MediLink/webapp.html +0 -0
- {medicafe-0.250813.0 → medicafe-0.250813.1}/README.md +0 -0
- {medicafe-0.250813.0 → medicafe-0.250813.1}/medicafe.egg-info/SOURCES.txt +0 -0
- {medicafe-0.250813.0 → medicafe-0.250813.1}/medicafe.egg-info/dependency_links.txt +0 -0
- {medicafe-0.250813.0 → medicafe-0.250813.1}/medicafe.egg-info/entry_points.txt +0 -0
- {medicafe-0.250813.0 → medicafe-0.250813.1}/medicafe.egg-info/not-zip-safe +0 -0
- {medicafe-0.250813.0 → medicafe-0.250813.1}/medicafe.egg-info/requires.txt +0 -0
- {medicafe-0.250813.0 → medicafe-0.250813.1}/medicafe.egg-info/top_level.txt +0 -0
- {medicafe-0.250813.0 → medicafe-0.250813.1}/setup.cfg +0 -0
@@ -292,7 +292,7 @@ def compare_versions(version1, version2):
|
|
292
292
|
|
293
293
|
def upgrade_package(package, retries=4, delay=2, target_version=None): # Updated retries to 4
|
294
294
|
"""
|
295
|
-
Attempts to upgrade the package multiple times with
|
295
|
+
Attempts to upgrade the package multiple times with escalating techniques.
|
296
296
|
"""
|
297
297
|
if not check_internet_connection():
|
298
298
|
print_status("No internet connection detected. Please check your internet connection and try again.", "ERROR")
|
@@ -302,82 +302,94 @@ def upgrade_package(package, retries=4, delay=2, target_version=None): # Update
|
|
302
302
|
if target_version:
|
303
303
|
print("Pinned target version: {}".format(target_version))
|
304
304
|
|
305
|
-
|
306
|
-
|
305
|
+
def get_installed_version_fresh(package):
|
306
|
+
"""Get installed version using a fresh subprocess to avoid pkg_resources cache issues."""
|
307
|
+
try:
|
308
|
+
process = subprocess.Popen(
|
309
|
+
[sys.executable, '-m', 'pip', 'show', package],
|
310
|
+
stdout=subprocess.PIPE,
|
311
|
+
stderr=subprocess.PIPE
|
312
|
+
)
|
313
|
+
stdout, stderr = process.communicate()
|
314
|
+
if process.returncode == 0:
|
315
|
+
for line in stdout.decode().splitlines():
|
316
|
+
if line.startswith("Version:"):
|
317
|
+
return line.split(":", 1)[1].strip()
|
318
|
+
return None
|
319
|
+
except Exception as e:
|
320
|
+
print("Warning: Could not get fresh version: {}".format(e))
|
321
|
+
return None
|
322
|
+
|
323
|
+
def try_upgrade_with_strategy(attempt, strategy_name, cmd_args):
|
324
|
+
"""Try upgrade with specific strategy and return success status."""
|
325
|
+
print("Attempt {}/{}: Using {} strategy...".format(attempt, retries, strategy_name))
|
307
326
|
|
308
|
-
# Use a more compatible approach for Python 3.4
|
309
|
-
# Try with --no-deps first to avoid dependency resolution issues
|
310
327
|
pkg_spec = package
|
311
328
|
if target_version:
|
312
329
|
pkg_spec = "{}=={}".format(package, target_version)
|
313
330
|
|
314
|
-
cmd = [
|
315
|
-
sys.executable, '-m', 'pip', 'install', '--upgrade',
|
316
|
-
'--no-deps', '--no-cache-dir', '--disable-pip-version-check', '-q', pkg_spec
|
317
|
-
]
|
331
|
+
cmd = [sys.executable, '-m', 'pip', 'install'] + cmd_args + [pkg_spec]
|
318
332
|
|
319
|
-
print("Using pip upgrade with --no-deps and --no-cache-dir")
|
320
333
|
process = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
321
334
|
stdout, stderr = process.communicate()
|
322
335
|
|
323
336
|
if process.returncode == 0:
|
324
337
|
print(stdout.decode().strip())
|
325
|
-
|
338
|
+
# Add delay to allow file system to settle
|
339
|
+
time.sleep(1)
|
340
|
+
new_version = get_installed_version_fresh(package)
|
326
341
|
expected_version = target_version or get_latest_version(package)
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
else:
|
331
|
-
print_status("Attempt {}: Upgrade succeeded!".format(attempt), "SUCCESS")
|
332
|
-
time.sleep(delay)
|
342
|
+
|
343
|
+
if expected_version and new_version and compare_versions(new_version, expected_version) >= 0:
|
344
|
+
print_status("Attempt {}: Upgrade succeeded with {}!".format(attempt, strategy_name), "SUCCESS")
|
333
345
|
return True
|
334
346
|
else:
|
335
|
-
print_status("Upgrade incomplete. Current version: {} Expected at least: {}".format(
|
336
|
-
|
337
|
-
|
338
|
-
try:
|
339
|
-
time.sleep(delay + (random.random() * 0.5))
|
340
|
-
except Exception:
|
341
|
-
time.sleep(delay)
|
347
|
+
print_status("Upgrade incomplete. Current version: {} Expected at least: {}".format(
|
348
|
+
new_version or "unknown", expected_version), "WARNING")
|
349
|
+
return False
|
342
350
|
else:
|
343
351
|
print(stderr.decode().strip())
|
344
|
-
print_status("Attempt {}: Upgrade failed with
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
352
|
+
print_status("Attempt {}: Upgrade failed with {}.".format(attempt, strategy_name), "WARNING")
|
353
|
+
return False
|
354
|
+
|
355
|
+
# Define escalation strategies for each attempt
|
356
|
+
strategies = {
|
357
|
+
1: [
|
358
|
+
("Gentle Upgrade", ['--upgrade', '--no-deps', '--no-cache-dir', '--disable-pip-version-check', '-q']),
|
359
|
+
("Force Reinstall", ['--upgrade', '--force-reinstall', '--no-cache-dir', '--disable-pip-version-check', '-q'])
|
360
|
+
],
|
361
|
+
2: [
|
362
|
+
("Clean Install", ['--upgrade', '--force-reinstall', '--no-cache-dir', '--disable-pip-version-check', '--ignore-installed', '-q']),
|
363
|
+
("User Install", ['--upgrade', '--user', '--no-cache-dir', '--disable-pip-version-check', '-q'])
|
364
|
+
],
|
365
|
+
3: [
|
366
|
+
("Aggressive Clean", ['--upgrade', '--force-reinstall', '--no-cache-dir', '--disable-pip-version-check', '--ignore-installed', '--no-deps', '-q']),
|
367
|
+
("Pre-download", ['--upgrade', '--force-reinstall', '--no-cache-dir', '--disable-pip-version-check', '--pre', '-q'])
|
368
|
+
],
|
369
|
+
4: [
|
370
|
+
("Nuclear Option", ['--upgrade', '--force-reinstall', '--no-cache-dir', '--disable-pip-version-check', '--ignore-installed', '--no-deps', '--pre', '-q']),
|
371
|
+
("Last Resort", ['--upgrade', '--force-reinstall', '--no-cache-dir', '--disable-pip-version-check', '--ignore-installed', '--no-deps', '--pre', '--user', '-q'])
|
372
|
+
]
|
373
|
+
}
|
374
|
+
|
375
|
+
for attempt in range(1, retries + 1):
|
376
|
+
print("Attempt {}/{} to upgrade {}...".format(attempt, retries, package))
|
377
|
+
|
378
|
+
# Try each strategy for this attempt
|
379
|
+
for strategy_name, cmd_args in strategies[attempt]:
|
380
|
+
if try_upgrade_with_strategy(attempt, strategy_name, cmd_args):
|
381
|
+
time.sleep(delay)
|
382
|
+
return True
|
383
|
+
|
384
|
+
# If we get here, all strategies for this attempt failed
|
385
|
+
if attempt < retries:
|
386
|
+
# Escalating delays: 2s, 3s, 5s
|
387
|
+
current_delay = delay + (attempt - 1)
|
388
|
+
print("All strategies failed for attempt {}. Retrying in {} seconds...".format(attempt, current_delay))
|
389
|
+
try:
|
390
|
+
time.sleep(current_delay + (random.random() * 1.0))
|
391
|
+
except Exception:
|
392
|
+
time.sleep(current_delay)
|
381
393
|
|
382
394
|
print_status("All upgrade attempts failed.", "ERROR")
|
383
395
|
return False
|
@@ -279,15 +279,23 @@ def main(desired_endpoint=None):
|
|
279
279
|
return None, None
|
280
280
|
|
281
281
|
|
282
|
-
def check_for_new_remittances(config=None):
|
282
|
+
def check_for_new_remittances(config=None, is_boot_scan=False):
|
283
283
|
"""
|
284
284
|
Function to check for new remittance files across all configured endpoints.
|
285
285
|
Loads the configuration, validates it, and processes each endpoint to download and handle files.
|
286
286
|
Accumulates results from all endpoints and processes them together at the end.
|
287
|
+
|
288
|
+
Args:
|
289
|
+
config: Configuration object
|
290
|
+
is_boot_scan: If True, suppresses "No records" message for boot-time scans
|
291
|
+
|
292
|
+
Returns:
|
293
|
+
bool: True if new records were found, False otherwise
|
287
294
|
"""
|
288
295
|
# Start the process and log the initiation
|
289
296
|
log("Starting check_for_new_remittances function")
|
290
|
-
|
297
|
+
if not is_boot_scan:
|
298
|
+
print("\nChecking for new files across all endpoints...")
|
291
299
|
log("Checking for new files across all endpoints...")
|
292
300
|
|
293
301
|
# Step 1: Load and validate the configuration
|
@@ -297,44 +305,95 @@ def check_for_new_remittances(config=None):
|
|
297
305
|
medi = extract_medilink_config(config)
|
298
306
|
if not medi or 'endpoints' not in medi:
|
299
307
|
log("Error: Config is missing necessary sections. Aborting...", level="ERROR")
|
300
|
-
return
|
308
|
+
return False
|
301
309
|
|
302
310
|
endpoints = medi.get('endpoints')
|
303
311
|
if not isinstance(endpoints, dict):
|
304
312
|
log("Error: 'endpoints' is not a dictionary. Aborting...", level="ERROR")
|
305
|
-
return
|
313
|
+
return False
|
314
|
+
|
315
|
+
# DIAGNOSTIC: Log endpoint configuration details
|
316
|
+
log("Found {} configured endpoints: {}".format(len(endpoints), list(endpoints.keys())), level="INFO")
|
317
|
+
for endpoint_key, endpoint_info in endpoints.items():
|
318
|
+
log("Endpoint '{}': session_name={}, remote_directory_down={}, has_filemask={}".format(
|
319
|
+
endpoint_key,
|
320
|
+
endpoint_info.get('session_name', 'NOT_SET'),
|
321
|
+
endpoint_info.get('remote_directory_down', 'NOT_SET'),
|
322
|
+
'filemask' in endpoint_info
|
323
|
+
), level="DEBUG")
|
306
324
|
|
307
325
|
# Lists to accumulate all consolidated records and translated files across all endpoints
|
308
326
|
all_consolidated_records = []
|
309
327
|
all_translated_files = []
|
328
|
+
endpoint_results = {} # Track results per endpoint for diagnostics
|
310
329
|
|
311
330
|
# Step 2: Process each endpoint and accumulate results
|
312
331
|
for endpoint_key, endpoint_info in tqdm(endpoints.items(), desc="Processing endpoints"):
|
332
|
+
log("=== Processing endpoint: {} ===".format(endpoint_key), level="INFO")
|
333
|
+
|
313
334
|
# Validate endpoint structure
|
314
335
|
if not endpoint_info or not isinstance(endpoint_info, dict):
|
315
336
|
log("Error: Invalid endpoint structure for {}. Skipping...".format(endpoint_key), level="ERROR")
|
337
|
+
endpoint_results[endpoint_key] = {"status": "error", "reason": "invalid_structure"}
|
316
338
|
continue
|
317
339
|
|
318
340
|
if 'remote_directory_down' in endpoint_info:
|
319
341
|
# Process the endpoint and handle the files
|
320
|
-
log("Processing endpoint: {}".format(
|
342
|
+
log("Processing endpoint: {} with remote_directory_down: {}".format(
|
343
|
+
endpoint_key, endpoint_info.get('remote_directory_down')), level="INFO")
|
344
|
+
|
321
345
|
consolidated_records, translated_files = process_endpoint(endpoint_key, endpoint_info, config)
|
322
346
|
|
347
|
+
# Track results for diagnostics
|
348
|
+
endpoint_results[endpoint_key] = {
|
349
|
+
"status": "processed",
|
350
|
+
"records_found": len(consolidated_records) if consolidated_records else 0,
|
351
|
+
"files_translated": len(translated_files) if translated_files else 0
|
352
|
+
}
|
353
|
+
|
323
354
|
# Accumulate the results for later processing
|
324
355
|
if consolidated_records:
|
325
356
|
all_consolidated_records.extend(consolidated_records)
|
357
|
+
log("Added {} records from endpoint {}".format(len(consolidated_records), endpoint_key), level="INFO")
|
326
358
|
if translated_files:
|
327
359
|
all_translated_files.extend(translated_files)
|
360
|
+
log("Added {} translated files from endpoint {}".format(len(translated_files), endpoint_key), level="INFO")
|
328
361
|
else:
|
329
362
|
log("Skipping endpoint '{}'. 'remote_directory_down' not configured.".format(endpoint_info.get('name', 'Unknown')), level="WARNING")
|
363
|
+
endpoint_results[endpoint_key] = {"status": "skipped", "reason": "no_remote_directory_down"}
|
364
|
+
|
365
|
+
# DIAGNOSTIC: Log summary of endpoint processing
|
366
|
+
log("=== Endpoint Processing Summary ===", level="INFO")
|
367
|
+
for endpoint_key, result in endpoint_results.items():
|
368
|
+
if result["status"] == "processed":
|
369
|
+
log("Endpoint '{}': {} records found, {} files translated".format(
|
370
|
+
endpoint_key, result["records_found"], result["files_translated"]), level="INFO")
|
371
|
+
else:
|
372
|
+
log("Endpoint '{}': {} ({})".format(
|
373
|
+
endpoint_key, result["status"], result.get("reason", "unknown")), level="WARNING")
|
330
374
|
|
331
375
|
# Step 3: After processing all endpoints, handle the accumulated results
|
332
376
|
if all_consolidated_records:
|
377
|
+
log("Total records found across all endpoints: {}".format(len(all_consolidated_records)), level="INFO")
|
333
378
|
display_consolidated_records(all_consolidated_records) # Ensure this is called only once
|
334
379
|
prompt_csv_export(all_consolidated_records, medi.get('local_storage_path', '.'))
|
380
|
+
return True
|
335
381
|
else:
|
336
382
|
log("No records to display after processing all endpoints.", level="WARNING")
|
337
|
-
|
383
|
+
# Enhanced diagnostic message when no records found
|
384
|
+
if not is_boot_scan:
|
385
|
+
print("No records to display after processing all endpoints.")
|
386
|
+
print("\nDiagnostic Information:")
|
387
|
+
print("- Total endpoints configured: {}".format(len(endpoints)))
|
388
|
+
print("- Endpoints with remote_directory_down: {}".format(
|
389
|
+
sum(1 for ep in endpoints.values() if 'remote_directory_down' in ep)))
|
390
|
+
print("- Endpoints processed: {}".format(
|
391
|
+
sum(1 for result in endpoint_results.values() if result["status"] == "processed")))
|
392
|
+
print("- Endpoints skipped: {}".format(
|
393
|
+
sum(1 for result in endpoint_results.values() if result["status"] == "skipped")))
|
394
|
+
print("- Endpoints with errors: {}".format(
|
395
|
+
sum(1 for result in endpoint_results.values() if result["status"] == "error")))
|
396
|
+
return False
|
338
397
|
|
339
398
|
|
340
399
|
def process_endpoint(endpoint_key, endpoint_info, config):
|
@@ -347,19 +406,205 @@ def process_endpoint(endpoint_key, endpoint_info, config):
|
|
347
406
|
medi = extract_medilink_config(config)
|
348
407
|
local_storage_path = medi.get('local_storage_path', '.')
|
349
408
|
log("[Process Endpoint] Local storage path set to {}".format(local_storage_path))
|
409
|
+
|
410
|
+
# DIAGNOSTIC: Check WinSCP availability and configuration
|
411
|
+
try:
|
412
|
+
from MediLink_DataMgmt import get_winscp_path
|
413
|
+
winscp_path = get_winscp_path(config)
|
414
|
+
if os.path.exists(winscp_path):
|
415
|
+
log("[Process Endpoint] WinSCP found at: {}".format(winscp_path), level="INFO")
|
416
|
+
else:
|
417
|
+
log("[Process Endpoint] WinSCP not found at: {}".format(winscp_path), level="ERROR")
|
418
|
+
return [], []
|
419
|
+
except Exception as e:
|
420
|
+
log("[Process Endpoint] Error checking WinSCP path: {}".format(e), level="ERROR")
|
421
|
+
return [], []
|
422
|
+
|
423
|
+
# DIAGNOSTIC: Log endpoint configuration details
|
424
|
+
log("[Process Endpoint] Endpoint config - session_name: {}, remote_directory_down: {}, filemask: {}".format(
|
425
|
+
endpoint_info.get('session_name', 'NOT_SET'),
|
426
|
+
endpoint_info.get('remote_directory_down', 'NOT_SET'),
|
427
|
+
endpoint_info.get('filemask', 'NOT_SET')
|
428
|
+
), level="DEBUG")
|
429
|
+
|
430
|
+
# DIAGNOSTIC: Check if we're in test mode
|
431
|
+
if config.get("MediLink_Config", {}).get("TestMode", False):
|
432
|
+
log("[Process Endpoint] Test mode is enabled - simulating download", level="WARNING")
|
433
|
+
|
350
434
|
downloaded_files = operate_winscp("download", None, endpoint_info, local_storage_path, config)
|
351
435
|
|
352
436
|
if downloaded_files:
|
353
437
|
log("[Process Endpoint] WinSCP Downloaded the following files: \n{}".format(downloaded_files))
|
354
|
-
|
438
|
+
consolidated_records, translated_files = handle_files(local_storage_path, downloaded_files)
|
439
|
+
log("[Process Endpoint] File processing complete - {} records, {} translated files".format(
|
440
|
+
len(consolidated_records) if consolidated_records else 0,
|
441
|
+
len(translated_files) if translated_files else 0
|
442
|
+
), level="INFO")
|
443
|
+
return consolidated_records, translated_files
|
355
444
|
else:
|
356
|
-
log("[Process Endpoint]No files were downloaded for endpoint: {}.".format(endpoint_key), level="WARNING")
|
445
|
+
log("[Process Endpoint] No files were downloaded for endpoint: {}.".format(endpoint_key), level="WARNING")
|
446
|
+
|
447
|
+
# DIAGNOSTIC: Check if WinSCP log exists and analyze it
|
448
|
+
try:
|
449
|
+
log_filename = "winscp_download.log"
|
450
|
+
log_path = os.path.join(local_storage_path, log_filename)
|
451
|
+
if os.path.exists(log_path):
|
452
|
+
log("[Process Endpoint] WinSCP log exists at: {}".format(log_path), level="INFO")
|
453
|
+
# Read last few lines of log for diagnostics
|
454
|
+
try:
|
455
|
+
with open(log_path, 'r') as f:
|
456
|
+
lines = f.readlines()
|
457
|
+
if lines:
|
458
|
+
last_lines = lines[-5:] # Last 5 lines
|
459
|
+
log("[Process Endpoint] Last 5 lines of WinSCP log:", level="DEBUG")
|
460
|
+
for line in last_lines:
|
461
|
+
log("[Process Endpoint] Log: {}".format(line.strip()), level="DEBUG")
|
462
|
+
except Exception as e:
|
463
|
+
log("[Process Endpoint] Error reading WinSCP log: {}".format(e), level="ERROR")
|
464
|
+
else:
|
465
|
+
log("[Process Endpoint] WinSCP log not found at: {}".format(log_path), level="WARNING")
|
466
|
+
except Exception as e:
|
467
|
+
log("[Process Endpoint] Error checking WinSCP log: {}".format(e), level="ERROR")
|
468
|
+
|
357
469
|
return [], []
|
358
470
|
|
359
471
|
except Exception as e:
|
360
472
|
# Handle any exceptions that occur during the processing
|
361
473
|
log("Error processing endpoint {}: {}".format(endpoint_key, e), level="ERROR")
|
474
|
+
import traceback
|
475
|
+
log("Full traceback: {}".format(traceback.format_exc()), level="DEBUG")
|
362
476
|
return [], []
|
363
477
|
|
478
|
+
def test_endpoint_connectivity(config=None, endpoint_key=None):
|
479
|
+
"""
|
480
|
+
Test basic connectivity to a specific endpoint or all endpoints.
|
481
|
+
This is a diagnostic function to help identify connection issues.
|
482
|
+
|
483
|
+
Args:
|
484
|
+
config: Configuration object
|
485
|
+
endpoint_key: Specific endpoint to test, or None for all endpoints
|
486
|
+
|
487
|
+
Returns:
|
488
|
+
dict: Results of connectivity tests
|
489
|
+
"""
|
490
|
+
if config is None:
|
491
|
+
config, _ = load_configuration()
|
492
|
+
|
493
|
+
medi = extract_medilink_config(config)
|
494
|
+
if not medi or 'endpoints' not in medi:
|
495
|
+
log("Error: Config is missing necessary sections.", level="ERROR")
|
496
|
+
return {}
|
497
|
+
|
498
|
+
endpoints = medi.get('endpoints')
|
499
|
+
results = {}
|
500
|
+
|
501
|
+
# Determine which endpoints to test
|
502
|
+
if endpoint_key:
|
503
|
+
if endpoint_key in endpoints:
|
504
|
+
test_endpoints = {endpoint_key: endpoints[endpoint_key]}
|
505
|
+
else:
|
506
|
+
log("Error: Endpoint '{}' not found in configuration.".format(endpoint_key), level="ERROR")
|
507
|
+
return {}
|
508
|
+
else:
|
509
|
+
test_endpoints = endpoints
|
510
|
+
|
511
|
+
log("Testing connectivity for {} endpoint(s)...".format(len(test_endpoints)), level="INFO")
|
512
|
+
|
513
|
+
for ep_key, ep_info in test_endpoints.items():
|
514
|
+
log("Testing endpoint: {}".format(ep_key), level="INFO")
|
515
|
+
result = {"status": "unknown", "details": []}
|
516
|
+
|
517
|
+
# Check basic configuration
|
518
|
+
if not ep_info.get('session_name'):
|
519
|
+
result["status"] = "error"
|
520
|
+
result["details"].append("Missing session_name")
|
521
|
+
elif not ep_info.get('remote_directory_down'):
|
522
|
+
result["status"] = "error"
|
523
|
+
result["details"].append("Missing remote_directory_down")
|
524
|
+
else:
|
525
|
+
result["details"].append("Configuration appears valid")
|
526
|
+
|
527
|
+
# Check WinSCP availability
|
528
|
+
try:
|
529
|
+
from MediLink_DataMgmt import get_winscp_path
|
530
|
+
winscp_path = get_winscp_path(config)
|
531
|
+
if os.path.exists(winscp_path):
|
532
|
+
result["details"].append("WinSCP found at: {}".format(winscp_path))
|
533
|
+
else:
|
534
|
+
result["status"] = "error"
|
535
|
+
result["details"].append("WinSCP not found at: {}".format(winscp_path))
|
536
|
+
except Exception as e:
|
537
|
+
result["status"] = "error"
|
538
|
+
result["details"].append("Error checking WinSCP: {}".format(e))
|
539
|
+
|
540
|
+
# Check test mode
|
541
|
+
if config.get("MediLink_Config", {}).get("TestMode", False):
|
542
|
+
result["details"].append("Test mode is enabled - no real connection will be made")
|
543
|
+
result["status"] = "test_mode"
|
544
|
+
|
545
|
+
results[ep_key] = result
|
546
|
+
|
547
|
+
return results
|
548
|
+
|
549
|
+
|
364
550
|
if __name__ == "__main__":
|
365
|
-
|
551
|
+
import sys
|
552
|
+
|
553
|
+
print("=" * 60)
|
554
|
+
print("MediLink_Down Standalone Testing Tool")
|
555
|
+
print("=" * 60)
|
556
|
+
print()
|
557
|
+
|
558
|
+
# Check if endpoint was provided as command line argument
|
559
|
+
if len(sys.argv) > 1:
|
560
|
+
desired_endpoint = sys.argv[1]
|
561
|
+
print("Testing specific endpoint: {}".format(desired_endpoint))
|
562
|
+
print()
|
563
|
+
main(desired_endpoint)
|
564
|
+
else:
|
565
|
+
# No specific endpoint provided - run connectivity diagnostics
|
566
|
+
print("No specific endpoint provided.")
|
567
|
+
print("Running connectivity diagnostics for all endpoints...")
|
568
|
+
print()
|
569
|
+
|
570
|
+
try:
|
571
|
+
config, _ = load_configuration()
|
572
|
+
connectivity_results = test_endpoint_connectivity(config)
|
573
|
+
|
574
|
+
if connectivity_results:
|
575
|
+
print("Connectivity Test Results:")
|
576
|
+
print("-" * 40)
|
577
|
+
|
578
|
+
for endpoint, result in connectivity_results.items():
|
579
|
+
status = result["status"]
|
580
|
+
details = result["details"]
|
581
|
+
|
582
|
+
if status == "error":
|
583
|
+
print("[ERROR] {}: {}".format(endpoint, status))
|
584
|
+
elif status == "test_mode":
|
585
|
+
print("[TEST] {}: {} (Test Mode)".format(endpoint, status))
|
586
|
+
else:
|
587
|
+
print("[OK] {}: {}".format(endpoint, status))
|
588
|
+
|
589
|
+
for detail in details:
|
590
|
+
print(" - {}".format(detail))
|
591
|
+
print()
|
592
|
+
|
593
|
+
# Show available endpoints for testing
|
594
|
+
medi = extract_medilink_config(config)
|
595
|
+
endpoints = medi.get('endpoints', {})
|
596
|
+
if endpoints:
|
597
|
+
print("Available endpoints for testing:")
|
598
|
+
print("-" * 30)
|
599
|
+
for endpoint in endpoints.keys():
|
600
|
+
print(" - {}".format(endpoint))
|
601
|
+
print()
|
602
|
+
print("To test a specific endpoint, run:")
|
603
|
+
print(" python MediLink_Down.py <endpoint_name>")
|
604
|
+
else:
|
605
|
+
print("ERROR: No connectivity test results returned.")
|
606
|
+
|
607
|
+
except Exception as e:
|
608
|
+
print("ERROR: Failed to run diagnostics: {}".format(e))
|
609
|
+
import traceback
|
610
|
+
traceback.print_exc()
|
@@ -140,6 +140,21 @@ def main_menu():
|
|
140
140
|
if PERFORMANCE_LOGGING:
|
141
141
|
print("Test mode check completed in {:.2f} seconds".format(test_mode_end - test_mode_start))
|
142
142
|
|
143
|
+
# Boot-time one-time ack poll (silent policy: just show summary output)
|
144
|
+
try:
|
145
|
+
print("\nChecking acknowledgements (boot-time scan)...")
|
146
|
+
ack_result = MediLink_Down.check_for_new_remittances(config, is_boot_scan=True)
|
147
|
+
_last_ack_updated_at = int(time.time())
|
148
|
+
except Exception:
|
149
|
+
ack_result = False
|
150
|
+
pass
|
151
|
+
|
152
|
+
# Clear screen before showing menu header
|
153
|
+
try:
|
154
|
+
os.system('cls' if os.name == 'nt' else 'clear')
|
155
|
+
except Exception:
|
156
|
+
pass # Fallback if cls/clear fails
|
157
|
+
|
143
158
|
# Display Welcome Message
|
144
159
|
welcome_start = time.time()
|
145
160
|
MediLink_UI.display_welcome()
|
@@ -147,6 +162,11 @@ def main_menu():
|
|
147
162
|
if PERFORMANCE_LOGGING:
|
148
163
|
print("Welcome display completed in {:.2f} seconds".format(welcome_end - welcome_start))
|
149
164
|
|
165
|
+
# Show message if new records were found during boot-time scan
|
166
|
+
if ack_result:
|
167
|
+
print("\n[INFO] New records were found during the boot-time acknowledgement scan.")
|
168
|
+
print("You can view them by selecting 'Check for new remittances' from the menu.")
|
169
|
+
|
150
170
|
# Normalize the directory path for file operations.
|
151
171
|
path_norm_start = time.time()
|
152
172
|
medi = extract_medilink_config(config)
|
@@ -205,14 +225,6 @@ def main_menu():
|
|
205
225
|
end_date_str = end_date.strftime('%m/%d/%Y')
|
206
226
|
start_date_str = start_date.strftime('%m/%d/%Y')
|
207
227
|
|
208
|
-
# Boot-time one-time ack poll (silent policy: just show summary output)
|
209
|
-
try:
|
210
|
-
print("\nChecking acknowledgements (boot-time scan)...")
|
211
|
-
MediLink_Down.check_for_new_remittances(config)
|
212
|
-
_last_ack_updated_at = int(time.time())
|
213
|
-
except Exception:
|
214
|
-
pass
|
215
|
-
|
216
228
|
while True:
|
217
229
|
# Run any due scheduled ack checks before showing menu
|
218
230
|
try:
|
@@ -221,7 +233,7 @@ def main_menu():
|
|
221
233
|
due = [t for t in _scheduled_ack_checks if t <= now_ts]
|
222
234
|
if due:
|
223
235
|
print("\nAuto-checking acknowledgements (scheduled)...")
|
224
|
-
MediLink_Down.check_for_new_remittances(config)
|
236
|
+
MediLink_Down.check_for_new_remittances(config, is_boot_scan=False)
|
225
237
|
_last_ack_updated_at = now_ts
|
226
238
|
# remove executed
|
227
239
|
_scheduled_ack_checks = [t for t in _scheduled_ack_checks if t > now_ts]
|
@@ -255,11 +267,30 @@ def main_menu():
|
|
255
267
|
if choice == '1':
|
256
268
|
# Handle remittance checking.
|
257
269
|
remittance_start = time.time()
|
258
|
-
MediLink_Down.check_for_new_remittances(config)
|
270
|
+
result = MediLink_Down.check_for_new_remittances(config, is_boot_scan=False)
|
259
271
|
_last_ack_updated_at = int(time.time())
|
260
272
|
remittance_end = time.time()
|
261
273
|
if PERFORMANCE_LOGGING:
|
262
274
|
print("Remittance check completed in {:.2f} seconds".format(remittance_end - remittance_start))
|
275
|
+
|
276
|
+
# If no records found, offer connectivity diagnostics
|
277
|
+
if not result:
|
278
|
+
print("\nNo records found. Would you like to run connectivity diagnostics? (y/n): ", end="")
|
279
|
+
try:
|
280
|
+
diagnostic_choice = input().strip().lower()
|
281
|
+
if diagnostic_choice in ['y', 'yes']:
|
282
|
+
print("\nRunning connectivity diagnostics...")
|
283
|
+
connectivity_results = MediLink_Down.test_endpoint_connectivity(config)
|
284
|
+
print("\nConnectivity Test Results:")
|
285
|
+
for endpoint, result in connectivity_results.items():
|
286
|
+
print(" {}: {} - {}".format(
|
287
|
+
endpoint,
|
288
|
+
result["status"],
|
289
|
+
"; ".join(result["details"])
|
290
|
+
))
|
291
|
+
except Exception:
|
292
|
+
pass # Ignore input errors
|
293
|
+
|
263
294
|
# UX hint: suggest deeper United details
|
264
295
|
try:
|
265
296
|
print("Tip: For United details, run the United Claims Status option for the same date window.")
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|