medicafe 0.250812.4__tar.gz → 0.250812.5__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.
Files changed (81) hide show
  1. {medicafe-0.250812.4 → medicafe-0.250812.5}/MediBot/MediBot.bat +35 -1
  2. {medicafe-0.250812.4 → medicafe-0.250812.5}/MediBot/MediBot.py +52 -6
  3. {medicafe-0.250812.4 → medicafe-0.250812.5}/MediCafe/api_core.py +3 -0
  4. {medicafe-0.250812.4 → medicafe-0.250812.5}/MediCafe/graphql_utils.py +63 -4
  5. medicafe-0.250812.5/MediCafe/submission_index.py +288 -0
  6. medicafe-0.250812.5/MediLink/InsuranceTypeService.py +57 -0
  7. {medicafe-0.250812.4 → medicafe-0.250812.5}/MediLink/MediLink_DataMgmt.py +7 -2
  8. {medicafe-0.250812.4 → medicafe-0.250812.5}/MediLink/MediLink_Display_Utils.py +28 -6
  9. {medicafe-0.250812.4 → medicafe-0.250812.5}/MediLink/MediLink_PatientProcessor.py +69 -8
  10. {medicafe-0.250812.4 → medicafe-0.250812.5}/MediLink/MediLink_Up.py +101 -12
  11. {medicafe-0.250812.4 → medicafe-0.250812.5}/MediLink/MediLink_main.py +106 -6
  12. medicafe-0.250812.5/PKG-INFO +81 -0
  13. medicafe-0.250812.5/README.md +62 -0
  14. medicafe-0.250812.5/medicafe.egg-info/PKG-INFO +81 -0
  15. {medicafe-0.250812.4 → medicafe-0.250812.5}/medicafe.egg-info/SOURCES.txt +3 -0
  16. {medicafe-0.250812.4 → medicafe-0.250812.5}/setup.py +1 -1
  17. medicafe-0.250812.4/PKG-INFO +0 -124
  18. medicafe-0.250812.4/medicafe.egg-info/PKG-INFO +0 -124
  19. {medicafe-0.250812.4 → medicafe-0.250812.5}/LICENSE +0 -0
  20. {medicafe-0.250812.4 → medicafe-0.250812.5}/MANIFEST.in +0 -0
  21. {medicafe-0.250812.4 → medicafe-0.250812.5}/MediBot/MediBot_Charges.py +0 -0
  22. {medicafe-0.250812.4 → medicafe-0.250812.5}/MediBot/MediBot_Crosswalk_Library.py +0 -0
  23. {medicafe-0.250812.4 → medicafe-0.250812.5}/MediBot/MediBot_Crosswalk_Utils.py +0 -0
  24. {medicafe-0.250812.4 → medicafe-0.250812.5}/MediBot/MediBot_Post.py +0 -0
  25. {medicafe-0.250812.4 → medicafe-0.250812.5}/MediBot/MediBot_Preprocessor.py +0 -0
  26. {medicafe-0.250812.4 → medicafe-0.250812.5}/MediBot/MediBot_Preprocessor_lib.py +0 -0
  27. {medicafe-0.250812.4 → medicafe-0.250812.5}/MediBot/MediBot_UI.py +0 -0
  28. {medicafe-0.250812.4 → medicafe-0.250812.5}/MediBot/MediBot_dataformat_library.py +0 -0
  29. {medicafe-0.250812.4 → medicafe-0.250812.5}/MediBot/MediBot_docx_decoder.py +0 -0
  30. {medicafe-0.250812.4 → medicafe-0.250812.5}/MediBot/MediBot_smart_import.py +0 -0
  31. {medicafe-0.250812.4 → medicafe-0.250812.5}/MediBot/__init__.py +0 -0
  32. {medicafe-0.250812.4 → medicafe-0.250812.5}/MediBot/get_medicafe_version.py +0 -0
  33. {medicafe-0.250812.4 → medicafe-0.250812.5}/MediBot/update_json.py +0 -0
  34. {medicafe-0.250812.4 → medicafe-0.250812.5}/MediBot/update_medicafe.py +0 -0
  35. {medicafe-0.250812.4 → medicafe-0.250812.5}/MediCafe/MediLink_ConfigLoader.py +0 -0
  36. {medicafe-0.250812.4 → medicafe-0.250812.5}/MediCafe/__init__.py +0 -0
  37. {medicafe-0.250812.4 → medicafe-0.250812.5}/MediCafe/__main__.py +0 -0
  38. {medicafe-0.250812.4 → medicafe-0.250812.5}/MediCafe/api_core_backup.py +0 -0
  39. {medicafe-0.250812.4 → medicafe-0.250812.5}/MediCafe/api_factory.py +0 -0
  40. {medicafe-0.250812.4 → medicafe-0.250812.5}/MediCafe/api_utils.py +0 -0
  41. {medicafe-0.250812.4 → medicafe-0.250812.5}/MediCafe/core_utils.py +0 -0
  42. {medicafe-0.250812.4 → medicafe-0.250812.5}/MediCafe/logging_config.py +0 -0
  43. {medicafe-0.250812.4 → medicafe-0.250812.5}/MediCafe/logging_demo.py +0 -0
  44. {medicafe-0.250812.4 → medicafe-0.250812.5}/MediCafe/migration_helpers.py +0 -0
  45. {medicafe-0.250812.4 → medicafe-0.250812.5}/MediCafe/smart_import.py +0 -0
  46. {medicafe-0.250812.4 → medicafe-0.250812.5}/MediLink/MediLink_837p_cob_library.py +0 -0
  47. {medicafe-0.250812.4 → medicafe-0.250812.5}/MediLink/MediLink_837p_encoder.py +0 -0
  48. {medicafe-0.250812.4 → medicafe-0.250812.5}/MediLink/MediLink_837p_encoder_library.py +0 -0
  49. {medicafe-0.250812.4 → medicafe-0.250812.5}/MediLink/MediLink_837p_utilities.py +0 -0
  50. {medicafe-0.250812.4 → medicafe-0.250812.5}/MediLink/MediLink_API_Generator.py +0 -0
  51. {medicafe-0.250812.4 → medicafe-0.250812.5}/MediLink/MediLink_Azure.py +0 -0
  52. {medicafe-0.250812.4 → medicafe-0.250812.5}/MediLink/MediLink_ClaimStatus.py +0 -0
  53. {medicafe-0.250812.4 → medicafe-0.250812.5}/MediLink/MediLink_Decoder.py +0 -0
  54. {medicafe-0.250812.4 → medicafe-0.250812.5}/MediLink/MediLink_Deductible.py +0 -0
  55. {medicafe-0.250812.4 → medicafe-0.250812.5}/MediLink/MediLink_Deductible_Validator.py +0 -0
  56. {medicafe-0.250812.4 → medicafe-0.250812.5}/MediLink/MediLink_Down.py +0 -0
  57. {medicafe-0.250812.4 → medicafe-0.250812.5}/MediLink/MediLink_Gmail.py +0 -0
  58. {medicafe-0.250812.4 → medicafe-0.250812.5}/MediLink/MediLink_Mailer.py +0 -0
  59. {medicafe-0.250812.4 → medicafe-0.250812.5}/MediLink/MediLink_Parser.py +0 -0
  60. {medicafe-0.250812.4 → medicafe-0.250812.5}/MediLink/MediLink_Scan.py +0 -0
  61. {medicafe-0.250812.4 → medicafe-0.250812.5}/MediLink/MediLink_Scheduler.py +0 -0
  62. {medicafe-0.250812.4 → medicafe-0.250812.5}/MediLink/MediLink_UI.py +0 -0
  63. {medicafe-0.250812.4 → medicafe-0.250812.5}/MediLink/MediLink_insurance_utils.py +0 -0
  64. {medicafe-0.250812.4 → medicafe-0.250812.5}/MediLink/MediLink_smart_import.py +0 -0
  65. {medicafe-0.250812.4 → medicafe-0.250812.5}/MediLink/Soumit_api.py +0 -0
  66. {medicafe-0.250812.4 → medicafe-0.250812.5}/MediLink/__init__.py +0 -0
  67. {medicafe-0.250812.4 → medicafe-0.250812.5}/MediLink/gmail_http_utils.py +0 -0
  68. {medicafe-0.250812.4 → medicafe-0.250812.5}/MediLink/gmail_oauth_utils.py +0 -0
  69. {medicafe-0.250812.4 → medicafe-0.250812.5}/MediLink/insurance_type_integration_test.py +0 -0
  70. {medicafe-0.250812.4 → medicafe-0.250812.5}/MediLink/openssl.cnf +0 -0
  71. {medicafe-0.250812.4 → medicafe-0.250812.5}/MediLink/test.py +0 -0
  72. {medicafe-0.250812.4 → medicafe-0.250812.5}/MediLink/test_cob_library.py +0 -0
  73. {medicafe-0.250812.4 → medicafe-0.250812.5}/MediLink/test_timing.py +0 -0
  74. {medicafe-0.250812.4 → medicafe-0.250812.5}/MediLink/test_validation.py +0 -0
  75. {medicafe-0.250812.4 → medicafe-0.250812.5}/MediLink/webapp.html +0 -0
  76. {medicafe-0.250812.4 → medicafe-0.250812.5}/medicafe.egg-info/dependency_links.txt +0 -0
  77. {medicafe-0.250812.4 → medicafe-0.250812.5}/medicafe.egg-info/entry_points.txt +0 -0
  78. {medicafe-0.250812.4 → medicafe-0.250812.5}/medicafe.egg-info/not-zip-safe +0 -0
  79. {medicafe-0.250812.4 → medicafe-0.250812.5}/medicafe.egg-info/requires.txt +0 -0
  80. {medicafe-0.250812.4 → medicafe-0.250812.5}/medicafe.egg-info/top_level.txt +0 -0
  81. {medicafe-0.250812.4 → medicafe-0.250812.5}/setup.cfg +0 -0
@@ -2,11 +2,31 @@
2
2
  @echo off
3
3
  setlocal enabledelayedexpansion
4
4
 
5
- :: Debug mode selection
5
+ :: Clear screen before launcher header
6
+ cls
7
+
8
+ :: Launcher header
6
9
  echo ========================================
7
10
  echo MediCafe Launcher
8
11
  echo ========================================
9
12
  echo.
13
+
14
+ :: Hidden debug access: 1-second Enter-to-open gate; otherwise start normal mode
15
+ echo Press Enter within 1 second to open Debug Options... (otherwise starting Normal Mode)
16
+ rem Prefer timeout for key-break; fall back to ping if unavailable
17
+ where timeout >nul 2>&1
18
+ if errorlevel 1 (
19
+ rem Fallback: simple 1-second delay (no key detection on XP fallback)
20
+ ping -n 2 127.0.0.1 >nul
21
+ goto start_normal_mode
22
+ ) else (
23
+ timeout /t 1 >nul 2>nul
24
+ if errorlevel 1 goto show_debug_menu
25
+ goto start_normal_mode
26
+ )
27
+
28
+ :show_debug_menu
29
+ echo.
10
30
  echo Choose your mode:
11
31
  echo 1. Normal Mode - Production
12
32
  echo 2. Debug Mode - Full diagnostics (Interactive)
@@ -127,6 +147,8 @@ set "claims_status_script=..\MediLink\MediLink_ClaimStatus.py"
127
147
  set "deductible_script=..\MediLink\MediLink_Deductible.py"
128
148
  set "package_version="
129
149
  set PYTHONWARNINGS=ignore
150
+ set "PRES_WARN_UPDATE_SCRIPT=0"
151
+ set "PRES_WARN_NO_INTERNET=0"
130
152
 
131
153
  :: Check if Python is installed
132
154
  python --version >nul 2>&1
@@ -186,6 +208,7 @@ if defined package_version (
186
208
  ping -n 1 google.com >nul 2>&1
187
209
  if errorlevel 1 (
188
210
  set "internet_available=0"
211
+ set "PRES_WARN_NO_INTERNET=1"
189
212
  ) else (
190
213
  set "internet_available=1"
191
214
  echo Internet connection detected.
@@ -322,6 +345,7 @@ if exist "%upgrade_medicafe_local%" (
322
345
  ping -n 2 127.0.0.1 >nul
323
346
  ) else (
324
347
  echo update_medicafe.py not detected in any known location.
348
+ set "PRES_WARN_UPDATE_SCRIPT=1"
325
349
  echo.
326
350
  echo Checked locations:
327
351
  echo - Site-packages: C:\Python34\Lib\site-packages\MediBot\update_medicafe.py
@@ -351,6 +375,16 @@ echo .//* Welcome to MediCafe *\\.
351
375
  echo --------------------------------------------------------------
352
376
  echo.
353
377
 
378
+ :: Preserve important warnings/errors from boot sequence
379
+ if "%PRES_WARN_UPDATE_SCRIPT%"=="1" (
380
+ echo [WARNING] Update helper script not detected during startup. Update features may be limited.
381
+ echo.
382
+ )
383
+ if "%PRES_WARN_NO_INTERNET%"=="1" (
384
+ echo [WARNING] No internet connectivity detected during startup.
385
+ echo.
386
+ )
387
+
354
388
  if "!internet_available!"=="0" (
355
389
  echo NOTE: No internet detected. Options 1-5 require internet.
356
390
  echo.
@@ -73,6 +73,45 @@ except ImportError as e:
73
73
  # Make API client optional - don't log warning for now
74
74
  pass
75
75
 
76
+ # Buffer for startup warnings/errors so we can re-display them after clearing the console
77
+ STARTUP_NOTICES = []
78
+
79
+ def record_startup_warning(message):
80
+ """Record a startup warning, log it, and print it immediately.
81
+ Stored warnings will be reprinted after the screen is cleared.
82
+ """
83
+ try:
84
+ STARTUP_NOTICES.append(('WARNING', message))
85
+ except Exception:
86
+ pass
87
+ try:
88
+ if MediLink_ConfigLoader:
89
+ MediLink_ConfigLoader.log(message, level="WARNING")
90
+ except Exception:
91
+ pass
92
+ try:
93
+ print(message)
94
+ except Exception:
95
+ pass
96
+
97
+ def record_startup_error(message):
98
+ """Record a startup error, log it, and print it immediately.
99
+ Stored errors will be reprinted after the screen is cleared.
100
+ """
101
+ try:
102
+ STARTUP_NOTICES.append(('ERROR', message))
103
+ except Exception:
104
+ pass
105
+ try:
106
+ if MediLink_ConfigLoader:
107
+ MediLink_ConfigLoader.log(message, level="ERROR")
108
+ except Exception:
109
+ pass
110
+ try:
111
+ print(message)
112
+ except Exception:
113
+ pass
114
+
76
115
  def identify_field(header, field_mapping):
77
116
  for medisoft_field, patterns in field_mapping.items():
78
117
  for pattern in patterns:
@@ -448,12 +487,10 @@ class ExecutionState:
448
487
  MediLink_ConfigLoader.log("Crosswalk update completed successfully.", level="INFO")
449
488
  print("Crosswalk update completed successfully.")
450
489
  else:
451
- MediLink_ConfigLoader.log("Crosswalk update failed.", level="ERROR")
452
- print("Crosswalk update failed.")
490
+ record_startup_error("Crosswalk update failed.")
453
491
 
454
492
  except Exception as e:
455
- MediLink_ConfigLoader.log("MediBot: Failed to load or update configuration: {}".format(e), level="ERROR")
456
- print("MediBot: Failed to load or update configuration: {}".format(e))
493
+ record_startup_error("MediBot: Failed to load or update configuration: {}".format(e))
457
494
  raise # Re-throwing the exception or using a more sophisticated error handling mechanism might be needed
458
495
  # Handle the exception somehow (e.g., retry, halt, log)??
459
496
 
@@ -544,9 +581,18 @@ if __name__ == "__main__":
544
581
  MediLink_ConfigLoader.log("Load Complete event triggered. Clearing console. Displaying Menu...", level="INFO")
545
582
  # Windows XP console buffer fix: Use cls with echo to reset buffer state
546
583
  # Add a debug switch to optionally skip clearing the console for debugging purposes
547
- CLEAR_CONSOLE_ON_LOAD = False # Set to False to keep previous output visible for debugging
584
+ CLEAR_CONSOLE_ON_LOAD = True # Clear screen before menu for cleaner UI
548
585
  if CLEAR_CONSOLE_ON_LOAD:
549
586
  _ = os.system('cls && echo.')
587
+ # Re-display critical startup notices so the user still sees them
588
+ if STARTUP_NOTICES:
589
+ print("Important notices from startup:")
590
+ for lvl, msg in STARTUP_NOTICES:
591
+ try:
592
+ print("[{}] {}".format(lvl, msg))
593
+ except Exception:
594
+ print(msg)
595
+ print("-" * 60)
550
596
 
551
597
  proceed, selected_patient_ids, selected_indices, fixed_values = user_interaction(csv_data, interaction_mode, error_message, reverse_mapping)
552
598
 
@@ -556,7 +602,7 @@ if __name__ == "__main__":
556
602
 
557
603
  # Check if MAPAT_MED_PATH is missing or invalid
558
604
  if (not _ac()) or (not _ac().get_mapat_med_path()) or (not os.path.exists(_ac().get_mapat_med_path())):
559
- print("Warning: MAPAT.MED PATH is missing or invalid. Please check the path configuration.")
605
+ record_startup_warning("Warning: MAPAT.MED PATH is missing or invalid. Please check the path configuration.")
560
606
 
561
607
  # Perform the existing patients check
562
608
  existing_patients, patients_to_process = MediBot_Preprocessor.check_existing_patients(selected_patient_ids, _ac().get_mapat_med_path() if _ac() else '')
@@ -79,6 +79,9 @@ class ConfigLoader:
79
79
  print("Attempting to load Swagger file: {}".format(swagger_path))
80
80
  with open(swagger_path, 'r') as swagger_file:
81
81
  if swagger_path.endswith('.yaml') or swagger_path.endswith('.yml'):
82
+ if yaml is None:
83
+ print("YAML parsing not available (PyYAML not installed). Please install PyYAML or provide a JSON Swagger file.")
84
+ return None
82
85
  print("Parsing YAML file: {}".format(swagger_path))
83
86
  swagger_data = yaml.safe_load(swagger_file)
84
87
  elif swagger_path.endswith('.json'):
@@ -109,7 +109,7 @@ class GraphQLQueryBuilder:
109
109
  This is for testing purposes to verify the endpoint is working.
110
110
  """
111
111
  return {
112
- "query": "query Query($input: EligibilityInput!) { checkEligibility(input: $input) { eligibility { eligibilityInfo { trnId member { memberId firstName lastName middleName suffix dateOfBirth gender relationship relationshipCode relationshipTypeCode individualRelationshipCode dependentSequenceNumber } contact { addresses { type street1 street2 city state country zip zip4 } } insuranceInfo { policyNumber eligibilityStartDate eligibilityEndDate planStartDate planEndDate policyStatus planTypeDescription planVariation reportingCode stateOfIssueCode productType productId productCode payerId lineOfBusiness lineOfBusinessCode coverageTypes { typeCode description } } associatedIds { alternateId medicaidRecipientId exchangeMemberId alternateSubscriberId hicNumber mbiNumber subscriberMemberFacingIdentifier survivingSpouseId subscriberId memberReplacementId legacyMemberId customerAccountIdentifier } planLevels { level family { networkStatus planAmount planAmountFrequency remainingAmount } individual { networkStatus planAmount planAmountFrequency remainingAmount } } delegatedInfo { entity payerId contact { phone fax email } addresses { type street1 street2 city state country zip zip4 } } additionalInfo { isReferralRequired } } primaryCarePhysician { isPcpFound lastName firstName middleName phoneNumber address { type street1 street2 city state country zip zip4 } networkStatusCode affiliateHospitalName providerGroupName } coordinationOfBenefit { coordinationOfBenefitDetails { payer { name phoneNumber address { type street1 street2 city state country zip zip4 } } cobPrimacy { indicator description message } } uhgPrimacyStatus { policyEffectiveDate policyTerminationDate primacy { indicator description message } } } idCardImages { side content contentType } providerNetwork { status tier } extendedAttributes { fundingCode fundingType hsa cdhp governmentProgramCode cmsPackageBenefitPlanCode cmsSegmentId cmsContractId marketType obligorId marketSite benefitPlanId virtualVisit planVariation groupNumber legacyPanelNumber coverageLevel sharedArrangement productServiceCode designatedVirtualClinicNetwork medicaidVariableCode healthInsuranceExchangeId memberDiv legalEntityCode } otherBeneficiaries { memberId firstName lastName middleName suffix dateOfBirth gender relationship relationshipCode relationshipTypeCode individualRelationshipCode dependentSequenceNumber } serviceLevels { family { networkStatus services { isVendorOnly service serviceCode serviceDate text status coPayAmount coPayFrequency coInsurancePercent planAmount remainingAmount metYearToDateAmount isReferralObtainedCopay isReferralObtainedCoInsurance referralCopayAmount referralCoInsurancePercent benefitsAllowedFrequencies benefitsRemainingFrequencies message { note { isSingleMessageDetail isViewDetail messages text subMessages { service status copay msg startDate endDate minCopay minCopayMsg maxCopay maxCopayMsg isPrimaryIndicator } limitationInfo { lmtPeriod lmtType lmtOccurPerPeriod lmtDollarPerPeriod message } isMultipleCopaysFound isMultipleCoinsuranceFound } coPay { isSingleMessageDetail isViewDetail messages text subMessages { service status copay msg startDate endDate minCopay minCopayMsg maxCopay maxCopayMsg isPrimaryIndicator } limitationInfo { lmtPeriod lmtType lmtOccurPerPeriod lmtDollarPerPeriod message } isMultipleCopaysFound isMultipleCoinsuranceFound } coInsurance { isSingleMessageDetail isViewDetail messages text subMessages { service status copay msg startDate endDate minCopay minCopayMsg maxCopay maxCopayMsg isPrimaryIndicator } limitationInfo { lmtPeriod lmtType lmtOccurPerPeriod lmtDollarPerPeriod message } isMultipleCopaysFound isMultipleCoinsuranceFound } deductible { isSingleMessageDetail isViewDetail messages text subMessages { service status copay msg startDate endDate minCopay minCopayMsg maxCopay maxCopayMsg isPrimaryIndicator } limitationInfo { lmtPeriod lmtType lmtOccurPerPeriod lmtDollarPerPeriod message } isMultipleCopaysFound isMultipleCoinsuranceFound } benefitsAllowed { isSingleMessageDetail isViewDetail messages text subMessages { service status copay msg startDate endDate minCopay minCopayMsg maxCopay maxCopayMsg isPrimaryIndicator } limitationInfo { lmtPeriod lmtType lmtOccurPerPeriod lmtDollarPerPeriod message } isMultipleCopaysFound isMultipleCoinsuranceFound } benefitsRemaining { isSingleMessageDetail isViewDetail messages text subMessages { service status copay msg startDate endDate minCopay minCopayMsg maxCopay maxCopayMsg isPrimaryIndicator } limitationInfo { lmtPeriod lmtType lmtOccurPerPeriod lmtDollarPerPeriod message } isMultipleCopaysFound isMultipleCoinsuranceFound } coPayList coInsuranceList } } } individual { networkStatus services { isVendorOnly service serviceCode serviceDate text status coPayAmount coPayFrequency coInsurancePercent planAmount remainingAmount metYearToDateAmount isReferralObtainedCopay isReferralObtainedCoInsurance referralCopayAmount referralCoInsurancePercent benefitsAllowedFrequencies benefitsRemainingFrequencies message { note { isSingleMessageDetail isViewDetail messages text subMessages { service status copay msg startDate endDate minCopay minCopayMsg maxCopay maxCopayMsg isPrimaryIndicator } limitationInfo { lmtPeriod lmtType lmtOccurPerPeriod lmtDollarPerPeriod message } isMultipleCopaysFound isMultipleCoinsuranceFound } coPay { isSingleMessageDetail isViewDetail messages text subMessages { service status copay msg startDate endDate minCopay minCopayMsg maxCopay maxCopayMsg isPrimaryIndicator } limitationInfo { lmtPeriod lmtType lmtOccurPerPeriod lmtDollarPerPeriod message } isMultipleCopaysFound isMultipleCoinsuranceFound } coInsurance { isSingleMessageDetail isViewDetail messages text subMessages { service status copay msg startDate endDate minCopay minCopayMsg maxCopay maxCopayMsg isPrimaryIndicator } limitationInfo { lmtPeriod lmtType lmtOccurPerPeriod lmtDollarPerPeriod message } isMultipleCopaysFound isMultipleCoinsuranceFound } deductible { isSingleMessageDetail isViewDetail messages text subMessages { service status copay msg startDate endDate minCopay minCopayMsg maxCopay maxCopayMsg isPrimaryIndicator } limitationInfo { lmtPeriod lmtType lmtOccurPerPeriod lmtDollarPerPeriod message } isMultipleCopaysFound isMultipleCoinsuranceFound } benefitsAllowed { isSingleMessageDetail isViewDetail messages text subMessages { service status copay msg startDate endDate minCopay minCopayMsg maxCopay maxCopayMsg isPrimaryIndicator } limitationInfo { lmtPeriod lmtType lmtOccurPerPeriod lmtDollarPerPeriod message } isMultipleCopaysFound isMultipleCoinsuranceFound } benefitsRemaining { isSingleMessageDetail isViewDetail messages text subMessages { service status copay msg startDate endDate minCopay minCopayMsg maxCopay maxCopayMsg isPrimaryIndicator } limitationInfo { lmtPeriod lmtType lmtOccurPerPeriod lmtDollarPerPeriod message } isMultipleCopaysFound isMultipleCoinsuranceFound } coPayList coInsuranceList } } } } } } }",
112
+ "query": "query Query($input: EligibilityInput!) { checkEligibility(input: $input) { eligibility { eligibilityInfo { trnId member { memberId firstName lastName middleName suffix dateOfBirth gender relationship relationshipCode relationshipTypeCode individualRelationshipCode dependentSequenceNumber } contact { addresses { type street1 street2 city state country zip zip4 } } insuranceInfo { policyNumber eligibilityStartDate eligibilityEndDate planStartDate planEndDate policyStatus planTypeDescription planVariation reportingCode stateOfIssueCode productType productId productCode payerId lineOfBusiness lineOfBusinessCode coverageTypes { typeCode description } } associatedIds { alternateId medicaidRecipientId exchangeMemberId alternateSubscriberId hicNumber mbiNumber subscriberMemberFacingIdentifier survivingSpouseId subscriberId memberReplacementId legacyMemberId customerAccountIdentifier } planLevels { level family { networkStatus planAmount planAmountFrequency remainingAmount } individual { networkStatus planAmount planAmountFrequency remainingAmount } } delegatedInfo { entity payerId contact { phone fax email } addresses { type street1 street2 city state country zip zip4 } } additionalInfo { isReferralRequired } } primaryCarePhysician { isPcpFound lastName firstName middleName phoneNumber address { type street1 street2 city state country zip zip4 } networkStatusCode affiliateHospitalName providerGroupName } coordinationOfBenefit { coordinationOfBenefitDetails { payer { name phoneNumber address { type street1 street2 city state country zip zip4 } } cobPrimacy { indicator description message } } uhgPrimacyStatus { policyEffectiveDate policyTerminationDate primacy { indicator description message } } } idCardImages { side content contentType } providerNetwork { status tier } extendedAttributes { fundingCode fundingType hsa cdhp governmentProgramCode cmsPackageBenefitPlanCode cmsSegmentId cmsContractId marketType obligorId marketSite benefitPlanId virtualVisit planVariation groupNumber legacyPanelNumber coverageLevel sharedArrangement productServiceCode designatedVirtualClinicNetwork medicaidVariableCode healthInsuranceExchangeId memberDiv legalEntityCode } otherBeneficiaries { memberId firstName lastName middleName suffix dateOfBirth gender relationship relationshipCode relationshipTypeCode individualRelationshipCode dependentSequenceNumber } serviceLevels { family { networkStatus services { isVendorOnly service serviceCode serviceDate text status coPayAmount coPayFrequency coInsurancePercent planAmount remainingAmount metYearToDateAmount isReferralObtainedCopay isReferralObtainedCoInsurance referralCopayAmount referralCoInsurancePercent benefitsAllowedFrequencies benefitsRemainingFrequencies message { note { isSingleMessageDetail isViewDetail messages text subMessages { service status copay msg startDate endDate minCopay minCopayMsg maxCopay maxCopayMsg isPrimaryIndicator } limitationInfo { lmtPeriod lmtType lmtOccurPerPeriod lmtDollarPerPeriod message } isMultipleCopaysFound isMultipleCoinsuranceFound } coPay { isSingleMessageDetail isViewDetail messages text subMessages { service status copay msg startDate endDate minCopay minCopayMsg maxCopay maxCopayMsg isPrimaryIndicator } limitationInfo { lmtPeriod lmtType lmtOccurPerPeriod lmtDollarPerPeriod message } isMultipleCopaysFound isMultipleCoinsuranceFound } coInsurance { isSingleMessageDetail isViewDetail messages text subMessages { service status copay msg startDate endDate minCopay minCopayMsg maxCopay maxCopayMsg isPrimaryIndicator } limitationInfo { lmtPeriod lmtType lmtOccurPerPeriod lmtDollarPerPeriod message } isMultipleCopaysFound isMultipleCoinsuranceFound } deductible { isSingleMessageDetail isViewDetail messages text subMessages { service status copay msg startDate endDate minCopay minCopayMsg maxCopay maxCopayMsg isPrimaryIndicator } limitationInfo { lmtPeriod lmtType lmtOccurPerPeriod lmtDollarPerPeriod message } isMultipleCopaysFound isMultipleCoinsuranceFound } benefitsAllowed { isSingleMessageDetail isViewDetail messages text subMessages { service status copay msg startDate endDate minCopay minCopayMsg maxCopay maxCopayMsg isPrimaryIndicator } limitationInfo { lmtPeriod lmtType lmtOccurPerPeriod lmtDollarPerPeriod message } isMultipleCopaysFound isMultipleCoinsuranceFound } benefitsRemaining { isSingleMessageDetail isViewDetail messages text subMessages { service status copay msg startDate endDate minCopay minCopayMsg maxCopay maxCopayMsg isPrimaryIndicator } limitationInfo { lmtPeriod lmtType lmtOccurPerPeriod lmtDollarPerPeriod message } isMultipleCopaysFound isMultipleCoinsuranceFound } coPayList coInsuranceList } } } } } } }",
113
113
  "variables": {
114
114
  "input": {
115
115
  "memberId": "0001234567",
@@ -141,7 +141,7 @@ class GraphQLQueryBuilder:
141
141
  Returns the exact GraphQL query format that works with the Super Connector API.
142
142
  This matches the exact format from the successful cURL request.
143
143
  """
144
- return """query Query($input: EligibilityInput!) {\r\n \r\n checkEligibility(input: $input) {\r\n eligibility {\r\n eligibilityInfo {\r\n trnId\r\n member {\r\n memberId\r\n firstName\r\n lastName\r\n middleName\r\n suffix\r\n dateOfBirth\r\n gender\r\n relationship\r\n relationshipCode\r\n relationshipTypeCode\r\n individualRelationshipCode\r\n dependentSequenceNumber\r\n }\r\n contact {\r\n addresses {\r\n type\r\n street1\r\n street2\r\n city\r\n state\r\n country\r\n zip\r\n zip4\r\n }\r\n }\r\n insuranceInfo {\r\n policyNumber\r\n eligibilityStartDate\r\n eligibilityEndDate\r\n planStartDate\r\n planEndDate\r\n policyStatus\r\n planTypeDescription\r\n planVariation\r\n reportingCode\r\n stateOfIssueCode\r\n productType\r\n productId\r\n productCode\r\n payerId\r\n lineOfBusiness\r\n lineOfBusinessCode\r\n coverageTypes {\r\n typeCode\r\n description\r\n }\r\n }\r\n associatedIds {\r\n alternateId\r\n medicaidRecipientId\r\n exchangeMemberId\r\n alternateSubscriberId\r\n hicNumber\r\n mbiNumber\r\n subscriberMemberFacingIdentifier\r\n survivingSpouseId\r\n subscriberId\r\n memberReplacementId\r\n legacyMemberId\r\n customerAccountIdentifier\r\n }\r\n planLevels {\r\n level\r\n family {\r\n networkStatus\r\n planAmount\r\n planAmountFrequency\r\n remainingAmount\r\n }\r\n individual {\r\n networkStatus\r\n planAmount\r\n planAmountFrequency\r\n remainingAmount\r\n }\r\n }\r\n delegatedInfo {\r\n entity\r\n payerId\r\n contact {\r\n phone\r\n fax\r\n email\r\n }\r\n addresses {\r\n type\r\n street1\r\n street2\r\n city\r\n state\r\n country\r\n zip\r\n zip4\r\n }\r\n }\r\n additionalInfo {\r\n isReferralRequired\r\n }\r\n }\r\n primaryCarePhysician {\r\n isPcpFound\r\n lastName\r\n firstName\r\n middleName\r\n phoneNumber\r\n address {\r\n type\r\n street1\r\n street2\r\n city\r\n state\r\n country\r\n zip\r\n zip4\r\n }\r\n networkStatusCode\r\n affiliateHospitalName\r\n providerGroupName\r\n }\r\n coordinationOfBenefit {\r\n coordinationOfBenefitDetails {\r\n payer {\r\n name\r\n phoneNumber\r\n address {\r\n type\r\n street1\r\n street2\r\n city\r\n state\r\n country\r\n zip\r\n zip4\r\n }\r\n }\r\n cobPrimacy {\r\n indicator\r\n description\r\n message\r\n }\r\n }\r\n uhgPrimacyStatus {\r\n policyEffectiveDate\r\n policyTerminationDate\r\n primacy {\r\n indicator\r\n description\r\n message\r\n }\r\n }\r\n }\r\n providerNetwork {\r\n status\r\n tier\r\n }\r\n extendedAttributes {\r\n fundingCode\r\n fundingType\r\n hsa\r\n cdhp\r\n governmentProgramCode\r\n cmsPackageBenefitPlanCode\r\n cmsSegmentId\r\n cmsContractId\r\n marketType\r\n obligorId\r\n marketSite\r\n benefitPlanId\r\n virtualVisit\r\n planVariation\r\n groupNumber\r\n legacyPanelNumber\r\n coverageLevel\r\n sharedArrangement\r\n productServiceCode\r\n designatedVirtualClinicNetwork\r\n medicaidVariableCode\r\n healthInsuranceExchangeId\r\n memberDiv\r\n legalEntityCode\r\n }\r\n otherBeneficiaries {\r\n memberId\r\n firstName\r\n lastName\r\n middleName\r\n suffix\r\n dateOfBirth\r\n gender\r\n relationship\r\n relationshipCode\r\n relationshipTypeCode\r\n individualRelationshipCode\r\n dependentSequenceNumber\r\n }\r\n serviceLevels {\r\n family {\r\n networkStatus\r\n services {\r\n isVendorOnly\r\n service\r\n serviceCode\r\n serviceDate\r\n text\r\n status\r\n coPayAmount\r\n coPayFrequency\r\n coInsurancePercent\r\n planAmount\r\n remainingAmount\r\n metYearToDateAmount\r\n isReferralObtainedCopay\r\n isReferralObtainedCoInsurance\r\n referralCopayAmount\r\n referralCoInsurancePercent\r\n benefitsAllowedFrequencies\r\n benefitsRemainingFrequencies\r\n message {\r\n note {\r\n isSingleMessageDetail\r\n isViewDetail\r\n messages\r\n text\r\n subMessages {\r\n service\r\n status\r\n copay\r\n msg\r\n startDate\r\n endDate\r\n minCopay\r\n minCopayMsg\r\n maxCopay\r\n maxCopayMsg\r\n isPrimaryIndicator\r\n }\r\n limitationInfo {\r\n lmtPeriod\r\n lmtType\r\n lmtOccurPerPeriod\r\n lmtDollarPerPeriod\r\n message\r\n }\r\n isMultipleCopaysFound\r\n isMultipleCoinsuranceFound\r\n }\r\n coPay {\r\n isSingleMessageDetail\r\n isViewDetail\r\n messages\r\n text\r\n subMessages {\r\n service\r\n status\r\n copay\r\n msg\r\n startDate\r\n endDate\r\n minCopay\r\n minCopayMsg\r\n maxCopay\r\n maxCopayMsg\r\n isPrimaryIndicator\r\n }\r\n limitationInfo {\r\n lmtPeriod\r\n lmtType\r\n lmtOccurPerPeriod\r\n lmtDollarPerPeriod\r\n message\r\n }\r\n isMultipleCopaysFound\r\n isMultipleCoinsuranceFound\r\n }\r\n coInsurance {\r\n isSingleMessageDetail\r\n isViewDetail\r\n messages\r\n text\r\n subMessages {\r\n service\r\n status\r\n copay\r\n msg\r\n startDate\r\n endDate\r\n minCopay\r\n minCopayMsg\r\n maxCopay\r\n maxCopayMsg\r\n isPrimaryIndicator\r\n }\r\n limitationInfo {\r\n lmtPeriod\r\n lmtType\r\n lmtOccurPerPeriod\r\n lmtDollarPerPeriod\r\n message\r\n }\r\n isMultipleCopaysFound\r\n isMultipleCoinsuranceFound\r\n }\r\n deductible {\r\n isSingleMessageDetail\r\n isViewDetail\r\n messages\r\n text\r\n subMessages {\r\n service\r\n status\r\n copay\r\n msg\r\n startDate\r\n endDate\r\n minCopay\r\n minCopayMsg\r\n maxCopay\r\n maxCopayMsg\r\n isPrimaryIndicator\r\n }\r\n limitationInfo {\r\n lmtPeriod\r\n lmtType\r\n lmtOccurPerPeriod\r\n lmtDollarPerPeriod\r\n message\r\n }\r\n isMultipleCopaysFound\r\n isMultipleCoinsuranceFound\r\n }\r\n benefitsAllowed {\r\n isSingleMessageDetail\r\n isViewDetail\r\n messages\r\n text\r\n subMessages {\r\n service\r\n status\r\n copay\r\n msg\r\n startDate\r\n endDate\r\n minCopay\r\n minCopayMsg\r\n maxCopay\r\n maxCopayMsg\r\n isPrimaryIndicator\r\n }\r\n limitationInfo {\r\n lmtPeriod\r\n lmtType\r\n lmtOccurPerPeriod\r\n lmtDollarPerPeriod\r\n message\r\n }\r\n isMultipleCopaysFound\r\n isMultipleCoinsuranceFound\r\n }\r\n benefitsRemaining {\r\n isSingleMessageDetail\r\n isViewDetail\r\n messages\r\n text\r\n subMessages {\r\n service\r\n status\r\n copay\r\n msg\r\n startDate\r\n endDate\r\n minCopay\r\n minCopayMsg\r\n maxCopay\r\n maxCopayMsg\r\n isPrimaryIndicator\r\n }\r\n limitationInfo {\r\n lmtPeriod\r\n lmtType\r\n lmtOccurPerPeriod\r\n lmtDollarPerPeriod\r\n message\r\n }\r\n isMultipleCopaysFound\r\n isMultipleCoinsuranceFound\r\n }\r\n coPayList\r\n coInsuranceList\r\n }\r\n }\r\n }\r\n individual {\r\n networkStatus\r\n services {\r\n isVendorOnly\r\n service\r\n serviceCode\r\n serviceDate\r\n text\r\n status\r\n coPayAmount\r\n coPayFrequency\r\n coInsurancePercent\r\n planAmount\r\n remainingAmount\r\n metYearToDateAmount\r\n isReferralObtainedCopay\r\n isReferralObtainedCoInsurance\r\n referralCopayAmount\r\n referralCoInsurancePercent\r\n benefitsAllowedFrequencies\r\n benefitsRemainingFrequencies\r\n message {\r\n note {\r\n isSingleMessageDetail\r\n isViewDetail\r\n messages\r\n text\r\n subMessages {\r\n service\r\n status\r\n copay\r\n msg\r\n startDate\r\n endDate\r\n minCopay\r\n minCopayMsg\r\n maxCopay\r\n maxCopayMsg\r\n isPrimaryIndicator\r\n }\r\n limitationInfo {\r\n lmtPeriod\r\n lmtType\r\n lmtOccurPerPeriod\r\n lmtDollarPerPeriod\r\n message\r\n }\r\n isMultipleCopaysFound\r\n isMultipleCoinsuranceFound\r\n }\r\n coPay {\r\n isSingleMessageDetail\r\n isViewDetail\r\n messages\r\n text\r\n subMessages {\r\n service\r\n status\r\n copay\r\n msg\r\n startDate\r\n endDate\r\n minCopay\r\n minCopayMsg\r\n maxCopay\r\n maxCopayMsg\r\n isPrimaryIndicator\r\n }\r\n limitationInfo {\r\n lmtPeriod\r\n lmtType\r\n lmtOccurPerPeriod\r\n lmtDollarPerPeriod\r\n message\r\n }\r\n isMultipleCopaysFound\r\n isMultipleCoinsuranceFound\r\n }\r\n coInsurance {\r\n isSingleMessageDetail\r\n isViewDetail\r\n messages\r\n text\r\n subMessages {\r\n service\r\n status\r\n copay\r\n msg\r\n startDate\r\n endDate\r\n minCopay\r\n minCopayMsg\r\n maxCopay\r\n maxCopayMsg\r\n isPrimaryIndicator\r\n }\r\n limitationInfo {\r\n lmtPeriod\r\n lmtType\r\n lmtOccurPerPeriod\r\n lmtDollarPerPeriod\r\n message\r\n }\r\n isMultipleCopaysFound\r\n isMultipleCoinsuranceFound\r\n }\r\n deductible {\r\n isSingleMessageDetail\r\n isViewDetail\r\n messages\r\n text\r\n subMessages {\r\n service\r\n status\r\n copay\r\n msg\r\n startDate\r\n endDate\r\n minCopay\r\n minCopayMsg\r\n maxCopay\r\n maxCopayMsg\r\n isPrimaryIndicator\r\n }\r\n limitationInfo {\r\n lmtPeriod\r\n lmtType\r\n lmtOccurPerPeriod\r\n lmtDollarPerPeriod\r\n message\r\n }\r\n isMultipleCopaysFound\r\n isMultipleCoinsuranceFound\r\n }\r\n benefitsAllowed {\r\n isSingleMessageDetail\r\n isViewDetail\r\n messages\r\n text\r\n subMessages {\r\n service\r\n status\r\n copay\r\n msg\r\n startDate\r\n endDate\r\n minCopay\r\n minCopayMsg\r\n maxCopay\r\n maxCopayMsg\r\n isPrimaryIndicator\r\n }\r\n limitationInfo {\r\n lmtPeriod\r\n lmtType\r\n lmtOccurPerPeriod\r\n lmtDollarPerPeriod\r\n message\r\n }\r\n isMultipleCopaysFound\r\n isMultipleCoinsuranceFound\r\n }\r\n benefitsRemaining {\r\n isSingleMessageDetail\r\n isViewDetail\r\n messages\r\n text\r\n subMessages {\r\n service\r\n status\r\n copay\r\n msg\r\n startDate\r\n endDate\r\n minCopay\r\n minCopayMsg\r\n maxCopay\r\n maxCopayMsg\r\n isPrimaryIndicator\r\n }\r\n limitationInfo {\r\n lmtPeriod\r\n lmtType\r\n lmtOccurPerPeriod\r\n lmtDollarPerPeriod\r\n message\r\n }\r\n isMultipleCopaysFound\r\n isMultipleCoinsuranceFound\r\n }\r\n coPayList\r\n coInsuranceList\r\n }\r\n }\r\n }\r\n }\r\n }\r\n }\r\n}"""
144
+ return """query Query($input: EligibilityInput!) {\r\n \r\n checkEligibility(input: $input) {\r\n eligibility {\r\n eligibilityInfo {\r\n trnId\r\n member {\r\n memberId\r\n firstName\r\n lastName\r\n middleName\r\n suffix\r\n dateOfBirth\r\n gender\r\n relationship\r\n relationshipCode\r\n relationshipTypeCode\r\n individualRelationshipCode\r\n dependentSequenceNumber\r\n }\r\n contact {\r\n addresses {\r\n type\r\n street1\r\n street2\r\n city\r\n state\r\n country\r\n zip\r\n zip4\r\n }\r\n }\r\n insuranceInfo {\r\n policyNumber\r\n eligibilityStartDate\r\n eligibilityEndDate\r\n planStartDate\r\n planEndDate\r\n policyStatus\r\n planTypeDescription\r\n planVariation\r\n reportingCode\r\n stateOfIssueCode\r\n productType\r\n productId\r\n productCode\r\n payerId\r\n lineOfBusiness\r\n lineOfBusinessCode\r\n coverageTypes {\r\n typeCode\r\n description\r\n }\r\n }\r\n associatedIds {\r\n alternateId\r\n medicaidRecipientId\r\n exchangeMemberId\r\n alternateSubscriberId\r\n hicNumber\r\n mbiNumber\r\n subscriberMemberFacingIdentifier\r\n survivingSpouseId\r\n subscriberId\r\n memberReplacementId\r\n legacyMemberId\r\n customerAccountIdentifier\r\n }\r\n planLevels {\r\n level\r\n family {\r\n networkStatus\r\n planAmount\r\n planAmountFrequency\r\n remainingAmount\r\n }\r\n individual {\r\n networkStatus\r\n planAmount\r\n planAmountFrequency\r\n remainingAmount\r\n }\r\n }\r\n delegatedInfo {\r\n entity\r\n payerId\r\n contact {\r\n phone\r\n fax\r\n email\r\n }\r\n addresses {\r\n type\r\n street1\r\n street2\r\n city\r\n state\r\n country\r\n zip\r\n zip4\r\n }\r\n }\r\n additionalInfo {\r\n isReferralRequired\r\n }\r\n }\r\n primaryCarePhysician {\r\n isPcpFound\r\n lastName\r\n firstName\r\n middleName\r\n phoneNumber\r\n address {\r\n type\r\n street1\r\n street2\r\n city\r\n state\r\n country\r\n zip\r\n zip4\r\n }\r\n networkStatusCode\r\n affiliateHospitalName\r\n providerGroupName\r\n }\r\n coordinationOfBenefit {\r\n coordinationOfBenefitDetails {\r\n payer {\r\n name\r\n phoneNumber\r\n address {\r\n type\r\n street1\r\n street2\r\n city\r\n state\r\n country\r\n zip\r\n zip4\r\n }\r\n }\r\n cobPrimacy {\r\n indicator\r\n description\r\n message\r\n }\r\n }\r\n uhgPrimacyStatus {\r\n policyEffectiveDate\r\n policyTerminationDate\r\n primacy {\r\n indicator\r\n description\r\n message\r\n }\r\n }\r\n }\r\n providerNetwork {\r\n status\r\n tier\r\n }\r\n extendedAttributes {\r\n fundingCode\r\n fundingType\r\n hsa\r\n cdhp\r\n governmentProgramCode\r\n cmsPackageBenefitPlanCode\r\n cmsSegmentId\r\n cmsContractId\r\n marketType\r\n obligorId\r\n marketSite\r\n benefitPlanId\r\n virtualVisit\r\n planVariation\r\n groupNumber\r\n legacyPanelNumber\r\n coverageLevel\r\n sharedArrangement\r\n productServiceCode\r\n designatedVirtualClinicNetwork\r\n medicaidVariableCode\r\n healthInsuranceExchangeId\r\n memberDiv\r\n legalEntityCode\r\n }\r\n otherBeneficiaries {\r\n memberId\r\n firstName\r\n lastName\r\n middleName\r\n suffix\r\n dateOfBirth\r\n gender\r\n relationship\r\n relationshipCode\r\n relationshipTypeCode\r\n individualRelationshipCode\r\n dependentSequenceNumber\r\n }\r\n serviceLevels {\r\n family {\r\n networkStatus\r\n services {\r\n isVendorOnly\r\n service\r\n serviceCode\r\n serviceDate\r\n text\r\n status\r\n coPayAmount\r\n coPayFrequency\r\n coInsurancePercent\r\n planAmount\r\n remainingAmount\r\n metYearToDateAmount\r\n isReferralObtainedCopay\r\n isReferralObtainedCoInsurance\r\n referralCopayAmount\r\n referralCoInsurancePercent\r\n benefitsAllowedFrequencies\r\n benefitsRemainingFrequencies\r\n message {\r\n note {\r\n isSingleMessageDetail\r\n isViewDetail\r\n messages\r\n text\r\n subMessages {\r\n service\r\n status\r\n copay\r\n msg\r\n startDate\r\n endDate\r\n minCopay\r\n minCopayMsg\r\n maxCopay\r\n maxCopayMsg\r\n isPrimaryIndicator\r\n }\r\n limitationInfo {\r\n lmtPeriod\r\n lmtType\r\n lmtOccurPerPeriod\r\n lmtDollarPerPeriod\r\n message\r\n }\r\n isMultipleCopaysFound\r\n isMultipleCoinsuranceFound\r\n }\r\n coPay {\r\n isSingleMessageDetail\r\n isViewDetail\r\n messages\r\n text\r\n subMessages {\r\n service\r\n status\r\n copay\r\n msg\r\n startDate\r\n endDate\r\n minCopay\r\n minCopayMsg\r\n maxCopay\r\n maxCopayMsg\r\n isPrimaryIndicator\r\n }\r\n limitationInfo {\r\n lmtPeriod\r\n lmtType\r\n lmtOccurPerPeriod\r\n lmtDollarPerPeriod\r\n message\r\n }\r\n isMultipleCopaysFound\r\n isMultipleCoinsuranceFound\r\n }\r\n coInsurance {\r\n isSingleMessageDetail\r\n isViewDetail\r\n messages\r\n text\r\n subMessages {\r\n service\r\n status\r\n copay\r\n msg\r\n startDate\r\n endDate\r\n minCopay\r\n minCopayMsg\r\n maxCopay\r\n maxCopayMsg\r\n isPrimaryIndicator\r\n }\r\n limitationInfo {\r\n lmtPeriod\r\n lmtType\r\n lmtOccurPerPeriod\r\n lmtDollarPerPeriod\r\n message\r\n }\r\n isMultipleCopaysFound\r\n isMultipleCoinsuranceFound\r\n }\r\n deductible {\r\n isSingleMessageDetail\r\n isViewDetail\r\n messages\r\n text\r\n subMessages {\r\n service\r\n status\r\n copay\r\n msg\r\n startDate\r\n endDate\r\n minCopay\r\n minCopayMsg\r\n maxCopay\r\n maxCopayMsg\r\n isPrimaryIndicator\r\n }\r\n limitationInfo {\r\n lmtPeriod\r\n lmtType\r\n lmtOccurPerPeriod\r\n lmtDollarPerPeriod\r\n message\r\n }\r\n isMultipleCopaysFound\r\n isMultipleCoinsuranceFound\r\n }\r\n benefitsAllowed {\r\n isSingleMessageDetail\r\n isViewDetail\r\n messages\r\n text\r\n subMessages {\r\n service\r\n status\r\n copay\r\n msg\r\n startDate\r\n endDate\r\n minCopay\r\n minCopayMsg\r\n maxCopay\r\n maxCopayMsg\r\n isPrimaryIndicator\r\n }\r\n limitationInfo {\r\n lmtPeriod\r\n lmtType\r\n lmtOccurPerPeriod\r\n lmtDollarPerPeriod\r\n message\r\n }\r\n isMultipleCopaysFound\r\n isMultipleCoinsuranceFound\r\n }\r\n benefitsRemaining {\r\n isSingleMessageDetail\r\n isViewDetail\r\n messages\r\n text\r\n subMessages {\r\n service\r\n status\r\n copay\r\n msg\r\n startDate\r\n endDate\r\n minCopay\r\n minCopayMsg\r\n maxCopay\r\n maxCopayMsg\r\n isPrimaryIndicator\r\n }\r\n limitationInfo {\r\n lmtPeriod\r\n lmtType\r\n lmtOccurPerPeriod\r\n lmtDollarPerPeriod\r\n message\r\n }\r\n isMultipleCopaysFound\r\n isMultipleCoinsuranceFound\r\n }\r\n coPayList\r\n coInsuranceList\r\n }\r\n }\r\n }\r\n }\r\n }\r\n }\r\n}"""
145
145
 
146
146
  @staticmethod
147
147
  def build_working_eligibility_request(variables):
@@ -424,6 +424,7 @@ class GraphQLResponseTransformer:
424
424
  }
425
425
 
426
426
  # Convenience functions for easy access
427
+
427
428
  def get_eligibility_query():
428
429
  """Get the eligibility GraphQL query (working format)"""
429
430
  return GraphQLQueryBuilder.get_eligibility_query()
@@ -433,7 +434,7 @@ def build_eligibility_variables(**kwargs):
433
434
  return GraphQLQueryBuilder.build_eligibility_variables(**kwargs)
434
435
 
435
436
  def build_eligibility_request(variables):
436
- """Build complete eligibility request body with working format"""
437
+ """Build complete GraphQL request body with working format"""
437
438
  return GraphQLQueryBuilder.build_eligibility_request(variables)
438
439
 
439
440
  def transform_eligibility_response(graphql_response):
@@ -442,4 +443,62 @@ def transform_eligibility_response(graphql_response):
442
443
 
443
444
  def get_sample_eligibility_request():
444
445
  """Get the sample GraphQL request from swagger documentation"""
445
- return GraphQLQueryBuilder.get_sample_eligibility_request()
446
+ return GraphQLQueryBuilder.get_sample_eligibility_request()
447
+
448
+ # -----------------------------------------------------------------------------
449
+ # Phase 2 scaffolding: centralized direct SBR09 extraction (placeholder)
450
+ # -----------------------------------------------------------------------------
451
+
452
+ # Placeholder path for future API-provided SBR09 value.
453
+ # Accepts either a top-level key (e.g., 'sbr09Code') or a dotted path
454
+ # (e.g., 'eligibilityInfo.insuranceInfo.sbr09'). Update when contract is finalized.
455
+ FUTURE_SBR09_FIELD_PATH = '<INSERT_SBR09_FIELD_PATH>'
456
+
457
+
458
+ def _get_nested_value(data, dotted_path):
459
+ """Safely get nested value from dict given a dotted path."""
460
+ try:
461
+ current = data
462
+ for part in dotted_path.split('.'):
463
+ if not isinstance(current, dict) or part not in current:
464
+ return None
465
+ current = current[part]
466
+ return current
467
+ except Exception:
468
+ return None
469
+
470
+
471
+ def _is_valid_sbr09(code):
472
+ if not isinstance(code, str):
473
+ return False
474
+ c = code.strip().upper()
475
+ return 1 <= len(c) <= 3 and c.isalnum()
476
+
477
+
478
+ def _normalize_sbr09(code):
479
+ return str(code).strip().upper()
480
+
481
+
482
+ def extract_sbr09_direct(response_dict):
483
+ """
484
+ Extract SBR09 directly from a transformed GraphQL response or raw GraphQL if the
485
+ provider API supplies it. Returns None until FUTURE_SBR09_FIELD_PATH is set and value is present.
486
+
487
+ - No mapping is performed. Only format checks are applied.
488
+ - Accepts either top-level key or dotted path.
489
+ """
490
+ if not FUTURE_SBR09_FIELD_PATH or FUTURE_SBR09_FIELD_PATH.startswith('<'):
491
+ return None
492
+
493
+ # Try top-level lookup
494
+ raw_value = response_dict.get(FUTURE_SBR09_FIELD_PATH)
495
+
496
+ # If not found, try dotted path
497
+ if raw_value is None and '.' in FUTURE_SBR09_FIELD_PATH:
498
+ raw_value = _get_nested_value(response_dict, FUTURE_SBR09_FIELD_PATH)
499
+
500
+ if raw_value is None:
501
+ return None
502
+
503
+ candidate = _normalize_sbr09(raw_value)
504
+ return candidate if _is_valid_sbr09(candidate) else None
@@ -0,0 +1,288 @@
1
+ """
2
+ submission_index.py - Centralized submission index scaffolding (Phase 3)
3
+
4
+ Purpose:
5
+ - Provide a shared, efficient index of successful claim submissions (and optionally attempts)
6
+ - Avoid repeated scanning of historical receipt files across apps (MediLink, MediBot)
7
+ - Enable fast deconfliction, window validation, and reporting
8
+
9
+ Design:
10
+ - Backed by a compact JSONL file in receipts_root (one JSON record per line)
11
+ - Claim key: (patient_id, payer_id or primary_insurance, date_of_service, service_hash)
12
+ - Fields: claim_key, patient_id, payer_id, primary_insurance, dos, endpoint, submitted_at,
13
+ receipt_file, status, checksum, notes, duplicate_override
14
+
15
+ This is an incremental implementation with JSONL; SQLite can be added later if needed.
16
+ """
17
+ import os
18
+ import json
19
+ import time
20
+
21
+ META_FILENAME = 'submission_index_meta.json'
22
+ INDEX_FILENAME = 'submission_index.jsonl'
23
+ LOCK_FILENAME = 'submission_index.lock'
24
+
25
+
26
+ def build_initial_index(receipts_root, lookback_days=200):
27
+ """
28
+ Initial index builder for legacy receipts.
29
+ NOTE: Legacy receipts do not include patient_id in the printed table, so we cannot
30
+ reliably backfill claim-level keys from historical receipts. This builder will:
31
+ - Create index/meta files if missing
32
+ - Record meta stats
33
+ - Return 0 (no historical claim entries)
34
+ """
35
+ if not os.path.isdir(receipts_root):
36
+ return 0
37
+ _ensure_files_exist(receipts_root)
38
+ count, max_mtime = _get_receipt_stats(receipts_root)
39
+ meta = _read_meta(receipts_root)
40
+ meta['last_indexed_mtime'] = max_mtime
41
+ meta['last_indexed_count'] = count
42
+ meta['last_full_build_at'] = time.time()
43
+ meta['rebuild_state'] = 'none'
44
+ meta['rebuild_progress'] = 0
45
+ _write_meta(receipts_root, meta)
46
+ return 0
47
+
48
+
49
+ def append_submission_record(receipts_root, record):
50
+ """
51
+ Append a new successful submission record to the index after a claim is submitted.
52
+ """
53
+ try:
54
+ _ensure_files_exist(receipts_root)
55
+ line = json.dumps(record)
56
+ path = _index_path(receipts_root)
57
+ with open(path, 'a') as f:
58
+ f.write(line)
59
+ f.write("\n")
60
+ except Exception:
61
+ pass
62
+
63
+
64
+ def find_by_claim_key(receipts_root, claim_key):
65
+ """
66
+ Look up a claim by its stable key to detect potential duplicates.
67
+ Returns the first matching record or None.
68
+ """
69
+ try:
70
+ path = _index_path(receipts_root)
71
+ if not os.path.exists(path):
72
+ return None
73
+ with open(path, 'r') as f:
74
+ for line in f:
75
+ try:
76
+ entry = json.loads(line.strip())
77
+ if isinstance(entry, dict) and entry.get('claim_key') == claim_key:
78
+ return entry
79
+ except Exception:
80
+ continue
81
+ except Exception:
82
+ return None
83
+ return None
84
+
85
+
86
+ def reconcile_recent_receipts(receipts_root, since_timestamp, max_seconds):
87
+ """
88
+ Incrementally scan receipts newer than 'since_timestamp' and update meta only.
89
+ JSONL index is built at submission time; this reconcile only updates meta counters.
90
+ Returns number of new files detected.
91
+ """
92
+ start = time.time()
93
+ count = 0
94
+ try:
95
+ for root, dirs, files in os.walk(receipts_root):
96
+ for name in files:
97
+ try:
98
+ _ = name.encode('ascii')
99
+ except Exception:
100
+ continue
101
+ try:
102
+ mtime = os.path.getmtime(os.path.join(root, name))
103
+ if mtime > since_timestamp:
104
+ count += 1
105
+ except Exception:
106
+ continue
107
+ if int(time.time() - start) >= int(max_seconds):
108
+ return count
109
+ except Exception:
110
+ return count
111
+ return count
112
+
113
+
114
+ def compute_claim_key(patient_id, payer_id, primary_insurance, date_of_service, service_hash):
115
+ """
116
+ Compute a deterministic claim key for deconfliction.
117
+ """
118
+ return "|".join([
119
+ (patient_id or ""),
120
+ (payer_id or primary_insurance or ""),
121
+ (date_of_service or ""),
122
+ (service_hash or "")
123
+ ])
124
+
125
+
126
+ # ------------------------- ASCII-safe meta/lock helpers -----------------------
127
+
128
+ def _meta_path(root_dir):
129
+ return os.path.join(root_dir, META_FILENAME)
130
+
131
+
132
+ def _index_path(root_dir):
133
+ return os.path.join(root_dir, INDEX_FILENAME)
134
+
135
+
136
+ def _lock_path(root_dir):
137
+ return os.path.join(root_dir, LOCK_FILENAME)
138
+
139
+
140
+ def _ensure_files_exist(root_dir):
141
+ try:
142
+ meta_path = _meta_path(root_dir)
143
+ if not os.path.exists(meta_path):
144
+ _write_meta(root_dir, {
145
+ 'last_indexed_mtime': 0.0,
146
+ 'last_indexed_count': 0,
147
+ 'last_full_build_at': 0.0,
148
+ 'rebuild_state': 'none',
149
+ 'rebuild_progress': 0
150
+ })
151
+ index_path = _index_path(root_dir)
152
+ if not os.path.exists(index_path):
153
+ with open(index_path, 'w') as f:
154
+ f.write("")
155
+ except Exception:
156
+ pass
157
+
158
+
159
+ def _read_meta(root_dir):
160
+ path = _meta_path(root_dir)
161
+ if not os.path.exists(path):
162
+ return {
163
+ 'last_indexed_mtime': 0.0,
164
+ 'last_indexed_count': 0,
165
+ 'last_full_build_at': 0.0,
166
+ 'rebuild_state': 'none', # 'none' | 'pending' | 'in_progress'
167
+ 'rebuild_progress': 0
168
+ }
169
+ try:
170
+ with open(path, 'r') as f:
171
+ data = f.read()
172
+ try:
173
+ meta = json.loads(data)
174
+ except Exception:
175
+ return {
176
+ 'last_indexed_mtime': 0.0,
177
+ 'last_indexed_count': 0,
178
+ 'last_full_build_at': 0.0,
179
+ 'rebuild_state': 'none',
180
+ 'rebuild_progress': 0
181
+ }
182
+ return meta if isinstance(meta, dict) else {}
183
+ except Exception:
184
+ return {
185
+ 'last_indexed_mtime': 0.0,
186
+ 'last_indexed_count': 0,
187
+ 'last_full_build_at': 0.0,
188
+ 'rebuild_state': 'none',
189
+ 'rebuild_progress': 0
190
+ }
191
+
192
+
193
+ def _write_meta(root_dir, meta):
194
+ try:
195
+ with open(_meta_path(root_dir), 'w') as f:
196
+ f.write(json.dumps(meta))
197
+ except Exception:
198
+ pass
199
+
200
+
201
+ def _try_acquire_lock(root_dir):
202
+ lock = _lock_path(root_dir)
203
+ try:
204
+ fd = os.open(lock, os.O_CREAT | os.O_EXCL | os.O_WRONLY)
205
+ os.close(fd)
206
+ return True
207
+ except Exception:
208
+ return False
209
+
210
+
211
+ def _release_lock(root_dir):
212
+ try:
213
+ os.remove(_lock_path(root_dir))
214
+ except Exception:
215
+ pass
216
+
217
+
218
+ def _get_receipt_stats(receipts_root):
219
+ count = 0
220
+ max_mtime = 0.0
221
+ try:
222
+ for root, dirs, files in os.walk(receipts_root):
223
+ for name in files:
224
+ try:
225
+ _ = name.encode('ascii')
226
+ except Exception:
227
+ continue
228
+ count += 1
229
+ try:
230
+ mtime = os.path.getmtime(os.path.join(root, name))
231
+ if mtime > max_mtime:
232
+ max_mtime = mtime
233
+ except Exception:
234
+ continue
235
+ except Exception:
236
+ pass
237
+ return count, max_mtime
238
+
239
+
240
+ # ------------------------- Public entry point --------------------------------
241
+
242
+ def ensure_submission_index(receipts_root, lookback_days=200, large_growth_threshold=0.1, max_inline_seconds=2):
243
+ """
244
+ XP/ASCII-safe, inline-only upkeep for the submission index.
245
+ - No background tasks
246
+ - Bounded work per call
247
+ - Chunked rebuild across boots
248
+ """
249
+ if not receipts_root or not os.path.isdir(receipts_root):
250
+ return
251
+
252
+ # Ensure files exist early
253
+ _ensure_files_exist(receipts_root)
254
+
255
+ if not _try_acquire_lock(receipts_root):
256
+ return
257
+
258
+ try:
259
+ meta = _read_meta(receipts_root)
260
+ current_count, current_max_mtime = _get_receipt_stats(receipts_root)
261
+
262
+ if meta.get('last_indexed_mtime', 0.0) == 0.0 and meta.get('last_indexed_count', 0) == 0:
263
+ # First-time or corrupt meta: do bounded initial build
264
+ build_initial_index(receipts_root, lookback_days)
265
+ return
266
+
267
+ # Incremental reconcile if new files detected by mtime
268
+ if current_max_mtime > meta.get('last_indexed_mtime', 0.0):
269
+ added = reconcile_recent_receipts(receipts_root, meta.get('last_indexed_mtime', 0.0), max_inline_seconds)
270
+ meta['last_indexed_mtime'] = current_max_mtime
271
+ meta['last_indexed_count'] = meta.get('last_indexed_count', 0) + int(added)
272
+ _write_meta(receipts_root, meta)
273
+ return
274
+
275
+ # Large growth heuristic -> schedule chunked rebuild (across boots)
276
+ last_count = meta.get('last_indexed_count', 0)
277
+ delta = current_count - last_count
278
+ if delta > 0 and delta >= max(100, int(large_growth_threshold * (last_count or 1))):
279
+ if meta.get('rebuild_state') == 'none':
280
+ meta['rebuild_state'] = 'pending'
281
+ meta['rebuild_progress'] = 0
282
+ _write_meta(receipts_root, meta)
283
+ return
284
+
285
+ # If rebuild pending, we would process a chunk here in a future implementation
286
+ return
287
+ finally:
288
+ _release_lock(receipts_root)