medicafe 0.250711.1__py3-none-any.whl → 0.250720.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.

@@ -52,6 +52,11 @@ try:
52
52
  except ImportError:
53
53
  import MediLink_ConfigLoader
54
54
 
55
+ try:
56
+ from MediLink import MediLink_Deductible_Validator
57
+ except ImportError:
58
+ import MediLink_Deductible_Validator
59
+
55
60
  project_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))
56
61
  if project_dir not in sys.path:
57
62
  sys.path.append(project_dir)
@@ -122,26 +127,39 @@ patients = [
122
127
  # Function to handle manual patient deductible lookup
123
128
  def manual_deductible_lookup():
124
129
  print("\n--- Manual Patient Deductible Lookup ---")
130
+ print("Available Payer IDs: {}".format(", ".join(payer_ids)))
131
+ print("Enter 'quit' at any time to return to main menu.\n")
132
+
125
133
  while True:
126
- member_id = input("Enter the Member ID of the subscriber (or press Enter to skip): ").strip()
127
- if not member_id:
128
- print("No Member ID entered. Skipping manual lookup.\n")
134
+ member_id = input("Enter the Member ID of the subscriber (or 'quit' to exit): ").strip()
135
+ if member_id.lower() == 'quit':
136
+ print("Returning to main menu.\n")
129
137
  break
138
+ if not member_id:
139
+ print("No Member ID entered. Please try again.\n")
140
+ continue
130
141
 
131
142
  dob_input = input("Enter the Date of Birth (YYYY-MM-DD): ").strip()
143
+ if dob_input.lower() == 'quit':
144
+ print("Returning to main menu.\n")
145
+ break
146
+
132
147
  formatted_dob = validate_and_format_date(dob_input)
133
148
  if not formatted_dob:
134
149
  print("Invalid DOB format. Please enter in YYYY-MM-DD format.\n")
135
150
  continue
136
151
 
137
- # Create a temporary list for single patient
138
- single_patient = [(formatted_dob, member_id)]
139
- print("Processing manual lookup for Member ID: {}, DOB: {}".format(member_id, formatted_dob))
152
+ print("\nProcessing manual lookup for Member ID: {}, DOB: {}".format(member_id, formatted_dob))
153
+ print("Checking {} payer IDs...".format(len(payer_ids)))
140
154
 
141
155
  # Fetch eligibility data
142
- for payer_id in payer_ids:
143
- eligibility_data = get_eligibility_info(client, payer_id, provider_last_name, formatted_dob, member_id, npi)
156
+ found_data = False
157
+ for i, payer_id in enumerate(payer_ids, 1):
158
+ print("Checking Payer ID {} ({}/{}): {}".format(payer_id, i, len(payer_ids), payer_id))
159
+
160
+ eligibility_data = get_eligibility_info(client, payer_id, provider_last_name, formatted_dob, member_id, npi, run_validation=True)
144
161
  if eligibility_data:
162
+ found_data = True
145
163
  # Generate unique output file for manual request
146
164
  output_file_name = "eligibility_report_manual_{}_{}.txt".format(member_id, formatted_dob)
147
165
  output_file_path = os.path.join(os.getenv('TEMP'), output_file_name)
@@ -153,26 +171,27 @@ def manual_deductible_lookup():
153
171
  print(table_header)
154
172
  print("-" * len(table_header))
155
173
  display_eligibility_info(eligibility_data, formatted_dob, member_id, output_file)
156
- # Open the generated file in Notepad
157
- os.system('notepad.exe "{}"'.format(output_file_path))
174
+
175
+ # Ask if user wants to open the report
176
+ open_report = input("\nEligibility data found! Open the report? (Y/N): ").strip().lower()
177
+ if open_report in ['y', 'yes']:
178
+ os.system('notepad.exe "{}"'.format(output_file_path))
158
179
  print("Manual eligibility report generated: {}\n".format(output_file_path))
159
180
  break # Assuming one payer ID per manual lookup
160
181
  else:
161
182
  print("No eligibility data found for Payer ID: {}".format(payer_id))
162
183
 
184
+ if not found_data:
185
+ print("\nNo eligibility data found for any Payer ID.")
186
+
163
187
  # Ask if the user wants to perform another manual lookup
164
188
  continue_choice = input("\nDo you want to perform another manual lookup? (Y/N): ").strip().lower()
165
189
  if continue_choice in ['n', 'no']:
166
190
  break
167
191
 
168
- # Display available Payer IDs as a note
169
- print("\nNOTE: The tool can only look up the following Payer IDs:")
170
- print(", ".join(payer_ids))
171
- print("-------------------------------------------------\n")
172
-
173
192
 
174
193
  # Function to get eligibility information
175
- def get_eligibility_info(client, payer_id, provider_last_name, date_of_birth, member_id, npi):
194
+ def get_eligibility_info(client, payer_id, provider_last_name, date_of_birth, member_id, npi, run_validation=False):
176
195
  try:
177
196
  # Log the parameters being sent to the function
178
197
  MediLink_ConfigLoader.log("Calling eligibility check with parameters:", level="DEBUG")
@@ -184,20 +203,46 @@ def get_eligibility_info(client, payer_id, provider_last_name, date_of_birth, me
184
203
 
185
204
  # Configuration flag to control which API to use
186
205
  # Set to False to use the new Super Connector API, True to use the legacy v3 API
187
- USE_LEGACY_API = False
206
+ USE_LEGACY_API = True # Changed to True to use legacy as primary
207
+
208
+ # Always get legacy response first
209
+ MediLink_ConfigLoader.log("Getting legacy get_eligibility_v3 API response", level="INFO")
210
+ legacy_eligibility = MediLink_API_v3.get_eligibility_v3(
211
+ client, payer_id, provider_last_name, 'MemberIDDateOfBirth', date_of_birth, member_id, npi
212
+ )
188
213
 
189
- if USE_LEGACY_API:
190
- # Use the legacy get_eligibility_v3 function as primary
191
- MediLink_ConfigLoader.log("Using legacy get_eligibility_v3 API", level="INFO")
192
- eligibility = MediLink_API_v3.get_eligibility_v3(
214
+ # Also get Super Connector response for comparison
215
+ MediLink_ConfigLoader.log("Getting new get_eligibility_super_connector API response", level="INFO")
216
+ super_connector_eligibility = None
217
+ try:
218
+ super_connector_eligibility = MediLink_API_v3.get_eligibility_super_connector(
193
219
  client, payer_id, provider_last_name, 'MemberIDDateOfBirth', date_of_birth, member_id, npi
194
220
  )
195
- else:
196
- # Use the new Super Connector API as primary
197
- MediLink_ConfigLoader.log("Using new get_eligibility_super_connector API", level="INFO")
198
- eligibility = MediLink_API_v3.get_eligibility_super_connector(
199
- client, payer_id, provider_last_name, 'MemberIDDateOfBirth', date_of_birth, member_id, npi
221
+ except Exception as e:
222
+ MediLink_ConfigLoader.log("Super Connector API failed: {}".format(e), level="ERROR")
223
+
224
+ # Run validation if requested and we have both responses
225
+ if run_validation and legacy_eligibility and super_connector_eligibility:
226
+ validation_file_path = os.path.join(os.getenv('TEMP'), 'validation_report_{}_{}.txt'.format(member_id, date_of_birth))
227
+ validation_report = MediLink_Deductible_Validator.run_validation_comparison(
228
+ legacy_eligibility, super_connector_eligibility, validation_file_path
200
229
  )
230
+ print("\nValidation report generated: {}".format(validation_file_path))
231
+
232
+ # Log any Super Connector API errors
233
+ if super_connector_eligibility and "rawGraphQLResponse" in super_connector_eligibility:
234
+ raw_response = super_connector_eligibility.get('rawGraphQLResponse', {})
235
+ errors = raw_response.get('errors', [])
236
+ if errors:
237
+ print("Super Connector API returned {} error(s):".format(len(errors)))
238
+ for i, error in enumerate(errors):
239
+ print(" Error {}: {} - {}".format(i+1, error.get('code', 'UNKNOWN'), error.get('description', 'No description')))
240
+
241
+ # Open validation report in Notepad
242
+ os.system('notepad.exe "{}"'.format(validation_file_path))
243
+
244
+ # Return the primary response (legacy for now)
245
+ eligibility = legacy_eligibility if USE_LEGACY_API else super_connector_eligibility
201
246
 
202
247
  # Log the response
203
248
  MediLink_ConfigLoader.log("Eligibility response: {}".format(json.dumps(eligibility, indent=4)), level="DEBUG")
@@ -229,7 +274,25 @@ def extract_super_connector_patient_info(eligibility_data):
229
274
  if not eligibility_data:
230
275
  return {'lastName': '', 'firstName': '', 'middleName': ''}
231
276
 
232
- # The response structure is flat at the top level
277
+ # Handle multiple eligibility records - use the first one with valid data
278
+ if "rawGraphQLResponse" in eligibility_data:
279
+ raw_response = eligibility_data.get('rawGraphQLResponse', {})
280
+ data = raw_response.get('data', {})
281
+ check_eligibility = data.get('checkEligibility', {})
282
+ eligibility_list = check_eligibility.get('eligibility', [])
283
+
284
+ # Try to get from the first eligibility record
285
+ if eligibility_list:
286
+ first_eligibility = eligibility_list[0]
287
+ member_info = first_eligibility.get('eligibilityInfo', {}).get('member', {})
288
+ if member_info:
289
+ return {
290
+ 'lastName': member_info.get("lastName", ""),
291
+ 'firstName': member_info.get("firstName", ""),
292
+ 'middleName': member_info.get("middleName", "")
293
+ }
294
+
295
+ # Fallback to top-level fields
233
296
  return {
234
297
  'lastName': eligibility_data.get("lastName", ""),
235
298
  'firstName': eligibility_data.get("firstName", ""),
@@ -258,44 +321,95 @@ def extract_super_connector_remaining_amount(eligibility_data):
258
321
  if met_amount is not None:
259
322
  return str(met_amount)
260
323
 
261
- # Navigate to the rawGraphQLResponse structure
262
- raw_response = eligibility_data.get('rawGraphQLResponse', {})
263
- if not raw_response:
264
- return "Not Found"
265
-
266
- data = raw_response.get('data', {})
267
- check_eligibility = data.get('checkEligibility', {})
268
- eligibility_list = check_eligibility.get('eligibility', [])
269
-
270
- if not eligibility_list:
271
- return "Not Found"
272
-
273
- first_eligibility = eligibility_list[0]
274
- service_levels = first_eligibility.get('serviceLevels', [])
324
+ # Collect all deductible amounts to find the most relevant one
325
+ all_deductible_amounts = []
275
326
 
276
- # Look for deductible information in service levels
277
- for service_level in service_levels:
278
- individual_services = service_level.get('individual', [])
279
- for individual in individual_services:
280
- services = individual.get('services', [])
281
- for service in services:
282
- # Look for deductible-related information
283
- if service.get('service') == 'deductible' or 'deductible' in service.get('text', '').lower():
284
- return service.get('remainingAmount', "")
285
-
286
- # Check the message.deductible.text field for deductible information
287
- message = service.get('message', {})
288
- deductible_msg = message.get('deductible', {})
289
- if deductible_msg and deductible_msg.get('text'):
290
- return deductible_msg.get('text', "")
291
-
292
- # If no specific deductible found, try to get from plan levels
293
- plan_levels = first_eligibility.get('eligibilityInfo', {}).get('planLevels', [])
327
+ # Look for deductible information in planLevels (based on validation report)
328
+ plan_levels = eligibility_data.get('planLevels', [])
294
329
  for plan_level in plan_levels:
295
- if plan_level.get('level') == 'deductibleInfo/outOfPocket/coPayMax':
330
+ if plan_level.get('level') == 'deductibleInfo':
331
+ # Collect individual deductible amounts
296
332
  individual_levels = plan_level.get('individual', [])
297
333
  if individual_levels:
298
- return individual_levels[0].get('remainingAmount', "")
334
+ for individual in individual_levels:
335
+ remaining = individual.get('remainingAmount')
336
+ if remaining is not None:
337
+ try:
338
+ amount = float(remaining)
339
+ all_deductible_amounts.append(('individual', amount))
340
+ except (ValueError, TypeError):
341
+ pass
342
+
343
+ # Collect family deductible amounts
344
+ family_levels = plan_level.get('family', [])
345
+ if family_levels:
346
+ for family in family_levels:
347
+ remaining = family.get('remainingAmount')
348
+ if remaining is not None:
349
+ try:
350
+ amount = float(remaining)
351
+ all_deductible_amounts.append(('family', amount))
352
+ except (ValueError, TypeError):
353
+ pass
354
+
355
+ # Navigate to the rawGraphQLResponse structure as fallback
356
+ raw_response = eligibility_data.get('rawGraphQLResponse', {})
357
+ if raw_response:
358
+ data = raw_response.get('data', {})
359
+ check_eligibility = data.get('checkEligibility', {})
360
+ eligibility_list = check_eligibility.get('eligibility', [])
361
+
362
+ # Try all eligibility records for deductible information
363
+ for eligibility in eligibility_list:
364
+ plan_levels = eligibility.get('eligibilityInfo', {}).get('planLevels', [])
365
+ for plan_level in plan_levels:
366
+ if plan_level.get('level') == 'deductibleInfo':
367
+ # Collect individual deductible amounts
368
+ individual_levels = plan_level.get('individual', [])
369
+ if individual_levels:
370
+ for individual in individual_levels:
371
+ remaining = individual.get('remainingAmount')
372
+ if remaining is not None:
373
+ try:
374
+ amount = float(remaining)
375
+ all_deductible_amounts.append(('individual', amount))
376
+ except (ValueError, TypeError):
377
+ pass
378
+
379
+ # Collect family deductible amounts
380
+ family_levels = plan_level.get('family', [])
381
+ if family_levels:
382
+ for family in family_levels:
383
+ remaining = family.get('remainingAmount')
384
+ if remaining is not None:
385
+ try:
386
+ amount = float(remaining)
387
+ all_deductible_amounts.append(('family', amount))
388
+ except (ValueError, TypeError):
389
+ pass
390
+
391
+ # Select the most relevant deductible amount
392
+ if all_deductible_amounts:
393
+ # Strategy: Prefer individual over family, and prefer non-zero amounts
394
+ # First, try to find non-zero individual amounts
395
+ non_zero_individual = [amt for type_, amt in all_deductible_amounts if type_ == 'individual' and amt > 0]
396
+ if non_zero_individual:
397
+ return str(max(non_zero_individual)) # Return highest non-zero individual amount
398
+
399
+ # If no non-zero individual, try non-zero family amounts
400
+ non_zero_family = [amt for type_, amt in all_deductible_amounts if type_ == 'family' and amt > 0]
401
+ if non_zero_family:
402
+ return str(max(non_zero_family)) # Return highest non-zero family amount
403
+
404
+ # If all amounts are zero, return the first individual amount (or family if no individual)
405
+ individual_amounts = [amt for type_, amt in all_deductible_amounts if type_ == 'individual']
406
+ if individual_amounts:
407
+ return str(individual_amounts[0])
408
+
409
+ # Fallback to first family amount
410
+ family_amounts = [amt for type_, amt in all_deductible_amounts if type_ == 'family']
411
+ if family_amounts:
412
+ return str(family_amounts[0])
299
413
 
300
414
  return "Not Found"
301
415
 
@@ -314,12 +428,57 @@ def extract_super_connector_insurance_info(eligibility_data):
314
428
  if not eligibility_data:
315
429
  return {'insuranceType': '', 'insuranceTypeCode': '', 'memberId': '', 'payerId': ''}
316
430
 
317
- # Get plan type description instead of coverage type
431
+ # Handle multiple eligibility records - use the first one with valid data
432
+ if "rawGraphQLResponse" in eligibility_data:
433
+ raw_response = eligibility_data.get('rawGraphQLResponse', {})
434
+ data = raw_response.get('data', {})
435
+ check_eligibility = data.get('checkEligibility', {})
436
+ eligibility_list = check_eligibility.get('eligibility', [])
437
+
438
+ # Try to get from the first eligibility record
439
+ if eligibility_list:
440
+ first_eligibility = eligibility_list[0]
441
+ insurance_info = first_eligibility.get('eligibilityInfo', {}).get('insuranceInfo', {})
442
+ if insurance_info:
443
+ return {
444
+ 'insuranceType': insurance_info.get("planTypeDescription", ""),
445
+ 'insuranceTypeCode': insurance_info.get("productServiceCode", ""),
446
+ 'memberId': insurance_info.get("memberId", ""),
447
+ 'payerId': insurance_info.get("payerId", "")
448
+ }
449
+
450
+ # Fallback to top-level fields
318
451
  insurance_type = eligibility_data.get("planTypeDescription", "")
452
+ if not insurance_type:
453
+ insurance_type = eligibility_data.get("productType", "")
454
+
455
+ # Clean up the insurance type if it's too long (like the LPPO description)
456
+ if insurance_type and len(insurance_type) > 50:
457
+ # Extract just the plan type part
458
+ if "PPO" in insurance_type:
459
+ insurance_type = "Preferred Provider Organization (PPO)"
460
+ elif "HMO" in insurance_type:
461
+ insurance_type = "Health Maintenance Organization (HMO)"
462
+ elif "EPO" in insurance_type:
463
+ insurance_type = "Exclusive Provider Organization (EPO)"
464
+ elif "POS" in insurance_type:
465
+ insurance_type = "Point of Service (POS)"
466
+
467
+ # Get insurance type code from multiple possible locations
468
+ insurance_type_code = eligibility_data.get("productServiceCode", "")
469
+ if not insurance_type_code:
470
+ # Try to get from coverageTypes
471
+ coverage_types = eligibility_data.get("coverageTypes", [])
472
+ if coverage_types:
473
+ insurance_type_code = coverage_types[0].get("typeCode", "")
474
+
475
+ # Note: We're not mapping "M" to "PR" as "M" likely means "Medical"
476
+ # and "PR" should be "12" for PPO according to CMS standards
477
+ # This mapping should be handled by the API developers
319
478
 
320
479
  return {
321
480
  'insuranceType': insurance_type,
322
- 'insuranceTypeCode': eligibility_data.get("productServiceCode", ""),
481
+ 'insuranceTypeCode': insurance_type_code,
323
482
  'memberId': eligibility_data.get("subscriberId", ""),
324
483
  'payerId': eligibility_data.get("payerId", "") # Use payerId instead of legalEntityCode (this should be payer_id from the inputs)
325
484
  }
@@ -334,7 +493,21 @@ def extract_super_connector_policy_status(eligibility_data):
334
493
  if not eligibility_data:
335
494
  return ""
336
495
 
337
- # Policy status is at the top level
496
+ # Handle multiple eligibility records - use the first one with valid data
497
+ if "rawGraphQLResponse" in eligibility_data:
498
+ raw_response = eligibility_data.get('rawGraphQLResponse', {})
499
+ data = raw_response.get('data', {})
500
+ check_eligibility = data.get('checkEligibility', {})
501
+ eligibility_list = check_eligibility.get('eligibility', [])
502
+
503
+ # Try to get from the first eligibility record
504
+ if eligibility_list:
505
+ first_eligibility = eligibility_list[0]
506
+ insurance_info = first_eligibility.get('eligibilityInfo', {}).get('insuranceInfo', {})
507
+ if insurance_info:
508
+ return insurance_info.get("policyStatus", "")
509
+
510
+ # Fallback to top-level field
338
511
  return eligibility_data.get("policyStatus", "")
339
512
 
340
513
  def is_legacy_response_format(data):
@@ -403,47 +576,111 @@ def display_eligibility_info(data, dob, member_id, output_file):
403
576
 
404
577
  # Main Execution Flow
405
578
  if __name__ == "__main__":
406
- # Step 1: Handle Manual Deductible Lookups
407
- manual_deductible_lookup()
408
-
409
- # Step 2: Proceed with Existing CSV Processing
410
- print("--- Starting Batch Eligibility Processing ---")
411
- output_file_path = os.path.join(os.getenv('TEMP'), 'eligibility_report.txt')
412
- with open(output_file_path, 'w') as output_file:
413
- table_header = "{:<20} | {:<10} | {:<40} | {:<5} | {:<14} | {:<14}".format(
414
- "Patient Name", "DOB", "Insurance Type", "PayID", "Policy Status", "Remaining Amt")
415
- output_file.write(table_header + "\n")
416
- output_file.write("-" * len(table_header) + "\n")
417
- print(table_header)
418
- print("-" * len(table_header))
419
-
420
- # Set to keep track of processed patients
421
- processed_patients = set()
422
-
423
- # Loop through each payer_id and patient to call the API, then display the eligibility information
424
- errors = []
425
- for payer_id in payer_ids:
426
- for dob, member_id in patients:
427
- # Skip if this patient has already been processed
428
- if (dob, member_id) in processed_patients:
429
- continue
430
- try:
431
- eligibility_data = get_eligibility_info(client, payer_id, provider_last_name, dob, member_id, npi)
432
- if eligibility_data is not None:
433
- display_eligibility_info(eligibility_data, dob, member_id, output_file) # Display as we get the result
434
- processed_patients.add((dob, member_id)) # Mark this patient as processed
435
- except Exception as e:
436
- errors.append((dob, member_id, str(e)))
437
-
438
- # Display errors if any
439
- if errors:
440
- error_msg = "\nErrors encountered during API calls:\n"
441
- output_file.write(error_msg)
442
- print(error_msg)
443
- for error in errors:
444
- error_details = "DOB: {}, Member ID: {}, Error: {}\n".format(error[0], error[1], error[2])
445
- output_file.write(error_details)
446
- print(error_details)
447
-
448
- # Open the generated file in Notepad
449
- os.system('notepad.exe "{}"'.format(output_file_path))
579
+ print("\n" + "=" * 80)
580
+ print("MEDILINK DEDUCTIBLE LOOKUP TOOL")
581
+ print("=" * 80)
582
+ print("This tool provides manual and batch eligibility lookups with validation.")
583
+ print("Validation reports compare legacy vs Super Connector API responses.")
584
+ print("=" * 80)
585
+
586
+ while True:
587
+ print("\nChoose an option:")
588
+ print("1. Manual Patient Lookup (with validation)")
589
+ print("2. Batch CSV Processing (with validation)")
590
+ print("3. Exit")
591
+
592
+ choice = input("\nEnter your choice (1-3): ").strip()
593
+
594
+ if choice == "1":
595
+ # Step 1: Handle Manual Deductible Lookups
596
+ manual_deductible_lookup()
597
+
598
+ # Ask if user wants to continue
599
+ continue_choice = input("\nDo you want to perform another operation? (Y/N): ").strip().lower()
600
+ if continue_choice in ['n', 'no']:
601
+ print("\nExiting. Thank you for using MediLink Deductible Tool!")
602
+ break
603
+
604
+ elif choice == "2":
605
+ # Step 2: Proceed with Existing CSV Processing
606
+ print("\n--- Starting Batch Eligibility Processing ---")
607
+ print("Processing {} patients from CSV data...".format(len(patients)))
608
+
609
+ # Ask for confirmation before starting batch processing
610
+ confirm = input("Proceed with batch processing? (Y/N): ").strip().lower()
611
+ if confirm not in ['y', 'yes']:
612
+ print("Batch processing cancelled.")
613
+ continue
614
+
615
+ output_file_path = os.path.join(os.getenv('TEMP'), 'eligibility_report.txt')
616
+ with open(output_file_path, 'w') as output_file:
617
+ table_header = "{:<20} | {:<10} | {:<40} | {:<5} | {:<14} | {:<14}".format(
618
+ "Patient Name", "DOB", "Insurance Type", "PayID", "Policy Status", "Remaining Amt")
619
+ output_file.write(table_header + "\n")
620
+ output_file.write("-" * len(table_header) + "\n")
621
+ print(table_header)
622
+ print("-" * len(table_header))
623
+
624
+ # Set to keep track of processed patients
625
+ processed_patients = set()
626
+
627
+ # Loop through each payer_id and patient to call the API, then display the eligibility information
628
+ errors = []
629
+ validation_reports = []
630
+ total_patients = len(patients) * len(payer_ids)
631
+ processed_count = 0
632
+
633
+ for payer_id in payer_ids:
634
+ for dob, member_id in patients:
635
+ # Skip if this patient has already been processed
636
+ if (dob, member_id) in processed_patients:
637
+ continue
638
+ try:
639
+ processed_count += 1
640
+ print("Processing patient {}/{}: Member ID {}, DOB {}".format(
641
+ processed_count, total_patients, member_id, dob))
642
+
643
+ # Run with validation enabled for batch processing
644
+ eligibility_data = get_eligibility_info(client, payer_id, provider_last_name, dob, member_id, npi, run_validation=True)
645
+ if eligibility_data is not None:
646
+ display_eligibility_info(eligibility_data, dob, member_id, output_file) # Display as we get the result
647
+ processed_patients.add((dob, member_id)) # Mark this patient as processed
648
+ except Exception as e:
649
+ errors.append((dob, member_id, str(e)))
650
+
651
+ # Display errors if any
652
+ if errors:
653
+ error_msg = "\nErrors encountered during API calls:\n"
654
+ output_file.write(error_msg)
655
+ print(error_msg)
656
+ for error in errors:
657
+ error_details = "DOB: {}, Member ID: {}, Error: {}\n".format(error[0], error[1], error[2])
658
+ output_file.write(error_details)
659
+ print(error_details)
660
+
661
+ # Ask if user wants to open the report
662
+ open_report = input("\nBatch processing complete! Open the eligibility report? (Y/N): ").strip().lower()
663
+ if open_report in ['y', 'yes']:
664
+ os.system('notepad.exe "{}"'.format(output_file_path))
665
+
666
+ # Print summary of validation reports
667
+ print("\n" + "=" * 80)
668
+ print("VALIDATION SUMMARY")
669
+ print("=" * 80)
670
+ print("Validation reports have been generated for each patient processed.")
671
+ print("Each report compares the legacy API response with the Super Connector API response.")
672
+ print("Check the TEMP directory for validation_report_*.txt files.")
673
+ print("=" * 80)
674
+
675
+ # Ask if user wants to continue
676
+ continue_choice = input("\nDo you want to perform another operation? (Y/N): ").strip().lower()
677
+ if continue_choice in ['n', 'no']:
678
+ print("\nExiting. Thank you for using MediLink Deductible Tool!")
679
+ break
680
+
681
+ elif choice == "3":
682
+ print("\nExiting. Thank you for using MediLink Deductible Tool!")
683
+ break
684
+
685
+ else:
686
+ print("Invalid choice. Please enter 1, 2, or 3.")