medicafe 0.250610.1__tar.gz → 0.250707.0__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.

Potentially problematic release.


This version of medicafe might be problematic. Click here for more details.

Files changed (54) hide show
  1. {medicafe-0.250610.1 → medicafe-0.250707.0}/MediLink/MediLink_API_v3.py +127 -3
  2. medicafe-0.250707.0/MediLink/MediLink_GraphQL.py +409 -0
  3. {medicafe-0.250610.1/medicafe.egg-info → medicafe-0.250707.0}/PKG-INFO +1 -1
  4. {medicafe-0.250610.1 → medicafe-0.250707.0/medicafe.egg-info}/PKG-INFO +1 -1
  5. {medicafe-0.250610.1 → medicafe-0.250707.0}/medicafe.egg-info/SOURCES.txt +1 -0
  6. {medicafe-0.250610.1 → medicafe-0.250707.0}/setup.py +1 -1
  7. {medicafe-0.250610.1 → medicafe-0.250707.0}/LICENSE +0 -0
  8. {medicafe-0.250610.1 → medicafe-0.250707.0}/MANIFEST.in +0 -0
  9. {medicafe-0.250610.1 → medicafe-0.250707.0}/MediBot/MediBot.bat +0 -0
  10. {medicafe-0.250610.1 → medicafe-0.250707.0}/MediBot/MediBot.py +0 -0
  11. {medicafe-0.250610.1 → medicafe-0.250707.0}/MediBot/MediBot_Charges.py +0 -0
  12. {medicafe-0.250610.1 → medicafe-0.250707.0}/MediBot/MediBot_Crosswalk_Library.py +0 -0
  13. {medicafe-0.250610.1 → medicafe-0.250707.0}/MediBot/MediBot_Post.py +0 -0
  14. {medicafe-0.250610.1 → medicafe-0.250707.0}/MediBot/MediBot_Preprocessor.py +0 -0
  15. {medicafe-0.250610.1 → medicafe-0.250707.0}/MediBot/MediBot_Preprocessor_lib.py +0 -0
  16. {medicafe-0.250610.1 → medicafe-0.250707.0}/MediBot/MediBot_UI.py +0 -0
  17. {medicafe-0.250610.1 → medicafe-0.250707.0}/MediBot/MediBot_dataformat_library.py +0 -0
  18. {medicafe-0.250610.1 → medicafe-0.250707.0}/MediBot/MediBot_docx_decoder.py +0 -0
  19. {medicafe-0.250610.1 → medicafe-0.250707.0}/MediBot/PDF_to_CSV_Cleaner.py +0 -0
  20. {medicafe-0.250610.1 → medicafe-0.250707.0}/MediBot/__init__.py +0 -0
  21. {medicafe-0.250610.1 → medicafe-0.250707.0}/MediBot/update_json.py +0 -0
  22. {medicafe-0.250610.1 → medicafe-0.250707.0}/MediBot/update_medicafe.py +0 -0
  23. {medicafe-0.250610.1 → medicafe-0.250707.0}/MediLink/MediLink.py +0 -0
  24. {medicafe-0.250610.1 → medicafe-0.250707.0}/MediLink/MediLink_837p_encoder.py +0 -0
  25. {medicafe-0.250610.1 → medicafe-0.250707.0}/MediLink/MediLink_837p_encoder_library.py +0 -0
  26. {medicafe-0.250610.1 → medicafe-0.250707.0}/MediLink/MediLink_API_Generator.py +0 -0
  27. {medicafe-0.250610.1 → medicafe-0.250707.0}/MediLink/MediLink_API_v2.py +0 -0
  28. {medicafe-0.250610.1 → medicafe-0.250707.0}/MediLink/MediLink_APIs.py +0 -0
  29. {medicafe-0.250610.1 → medicafe-0.250707.0}/MediLink/MediLink_Azure.py +0 -0
  30. {medicafe-0.250610.1 → medicafe-0.250707.0}/MediLink/MediLink_ClaimStatus.py +0 -0
  31. {medicafe-0.250610.1 → medicafe-0.250707.0}/MediLink/MediLink_ConfigLoader.py +0 -0
  32. {medicafe-0.250610.1 → medicafe-0.250707.0}/MediLink/MediLink_DataMgmt.py +0 -0
  33. {medicafe-0.250610.1 → medicafe-0.250707.0}/MediLink/MediLink_Decoder.py +0 -0
  34. {medicafe-0.250610.1 → medicafe-0.250707.0}/MediLink/MediLink_Deductible.py +0 -0
  35. {medicafe-0.250610.1 → medicafe-0.250707.0}/MediLink/MediLink_Down.py +0 -0
  36. {medicafe-0.250610.1 → medicafe-0.250707.0}/MediLink/MediLink_Gmail.py +0 -0
  37. {medicafe-0.250610.1 → medicafe-0.250707.0}/MediLink/MediLink_Mailer.py +0 -0
  38. {medicafe-0.250610.1 → medicafe-0.250707.0}/MediLink/MediLink_Parser.py +0 -0
  39. {medicafe-0.250610.1 → medicafe-0.250707.0}/MediLink/MediLink_Scan.py +0 -0
  40. {medicafe-0.250610.1 → medicafe-0.250707.0}/MediLink/MediLink_Scheduler.py +0 -0
  41. {medicafe-0.250610.1 → medicafe-0.250707.0}/MediLink/MediLink_UI.py +0 -0
  42. {medicafe-0.250610.1 → medicafe-0.250707.0}/MediLink/MediLink_Up.py +0 -0
  43. {medicafe-0.250610.1 → medicafe-0.250707.0}/MediLink/MediLink_batch.bat +0 -0
  44. {medicafe-0.250610.1 → medicafe-0.250707.0}/MediLink/Soumit_api.py +0 -0
  45. {medicafe-0.250610.1 → medicafe-0.250707.0}/MediLink/__init__.py +0 -0
  46. {medicafe-0.250610.1 → medicafe-0.250707.0}/MediLink/openssl.cnf +0 -0
  47. {medicafe-0.250610.1 → medicafe-0.250707.0}/MediLink/test.py +0 -0
  48. {medicafe-0.250610.1 → medicafe-0.250707.0}/MediLink/webapp.html +0 -0
  49. {medicafe-0.250610.1 → medicafe-0.250707.0}/README.md +0 -0
  50. {medicafe-0.250610.1 → medicafe-0.250707.0}/medicafe.egg-info/dependency_links.txt +0 -0
  51. {medicafe-0.250610.1 → medicafe-0.250707.0}/medicafe.egg-info/not-zip-safe +0 -0
  52. {medicafe-0.250610.1 → medicafe-0.250707.0}/medicafe.egg-info/requires.txt +0 -0
  53. {medicafe-0.250610.1 → medicafe-0.250707.0}/medicafe.egg-info/top_level.txt +0 -0
  54. {medicafe-0.250610.1 → medicafe-0.250707.0}/setup.cfg +0 -0
@@ -3,8 +3,10 @@ import time, requests, yaml, json, os, traceback
3
3
 
4
4
  try:
5
5
  from MediLink import MediLink_ConfigLoader
6
+ from MediLink import MediLink_GraphQL
6
7
  except ImportError:
7
8
  import MediLink_ConfigLoader
9
+ import MediLink_GraphQL
8
10
 
9
11
  """
10
12
  TODO At some point it might make sense to test their acknoledgment endpoint. body is transactionId.
@@ -168,7 +170,15 @@ class APIClient(BaseAPIClient):
168
170
  if call_type == 'GET':
169
171
  return requests.get(url, headers=headers, params=params)
170
172
  elif call_type == 'POST':
171
- headers['Content-Type'] = 'application/json'
173
+ # Check if there are custom headers (any headers beyond Authorization and Accept)
174
+ custom_headers = {k: v for k, v in headers.items() if k not in ['Authorization', 'Accept']}
175
+
176
+ if custom_headers:
177
+ # Log that custom headers were detected
178
+ MediLink_ConfigLoader.log("Custom headers detected: {}".format(custom_headers), level="DEBUG")
179
+ else:
180
+ # Set default Content-Type if no custom headers
181
+ headers['Content-Type'] = 'application/json'
172
182
  return requests.post(url, headers=headers, json=data)
173
183
  elif call_type == 'DELETE':
174
184
  return requests.delete(url, headers=headers)
@@ -467,6 +477,108 @@ def get_eligibility_v3(client, payer_id, provider_last_name, search_option, date
467
477
 
468
478
  return client.make_api_call(endpoint_name, 'POST', url_extension, params=None, data=body)
469
479
 
480
+ def get_eligibility_super_connector(client, payer_id, provider_last_name, search_option, date_of_birth, member_id, npi,
481
+ first_name=None, last_name=None, payer_label=None, payer_name=None, service_start=None, service_end=None,
482
+ middle_name=None, gender=None, ssn=None, city=None, state=None, zip=None, group_number=None,
483
+ service_type_code=None, provider_first_name=None, tax_id_number=None, provider_name_id=None,
484
+ corporate_tax_owner_id=None, corporate_tax_owner_name=None, organization_name=None,
485
+ organization_id=None, identify_service_level_deductible=True):
486
+ """
487
+ GraphQL Super Connector version of eligibility check that maps to the same interface as get_eligibility_v3.
488
+ This function provides a drop-in replacement for the REST API with identical input/output behavior.
489
+ """
490
+ # Ensure all required parameters have values
491
+ if not all([client, payer_id, provider_last_name, search_option, date_of_birth, member_id, npi]):
492
+ raise ValueError("All required parameters must have values: client, payer_id, provider_last_name, search_option, date_of_birth, member_id, npi")
493
+
494
+ # Validate payer_id
495
+ valid_payer_ids = ["87726", "06111", "25463", "37602", "39026", "74227", "65088", "81400", "03432", "86050", "86047", "95378", "95467"]
496
+ if payer_id not in valid_payer_ids:
497
+ raise ValueError("Invalid payer_id: {}. Must be one of: {}".format(payer_id, ", ".join(valid_payer_ids)))
498
+
499
+ endpoint_name = 'UHCAPI'
500
+ url_extension = client.config['MediLink_Config']['endpoints'][endpoint_name]['additional_endpoints']['eligibility_super_connector']
501
+
502
+ # Get provider TIN from config (using existing billing_provider_tin)
503
+ provider_tin = client.config['MediLink_Config'].get('billing_provider_tin')
504
+ if not provider_tin:
505
+ raise ValueError("Provider TIN not found in configuration")
506
+
507
+ # Construct GraphQL query variables using the consolidated module
508
+ graphql_variables = MediLink_GraphQL.build_eligibility_variables(
509
+ member_id=member_id,
510
+ date_of_birth=date_of_birth,
511
+ payer_id=payer_id,
512
+ provider_last_name=provider_last_name,
513
+ provider_npi=npi
514
+ )
515
+
516
+ # Validate NPI format (should be 10 digits)
517
+ if 'providerNPI' in graphql_variables:
518
+ npi_value = graphql_variables['providerNPI']
519
+ if not npi_value.isdigit() or len(npi_value) != 10:
520
+ MediLink_ConfigLoader.log("Warning: NPI '{}' is not 10 digits, but continuing anyway".format(npi_value), level="WARNING")
521
+
522
+ # Build GraphQL request using the consolidated module
523
+ # Hardcoded switch to use sample data for testing
524
+ USE_SAMPLE_DATA = False # Set to False to use constructed data
525
+
526
+ if USE_SAMPLE_DATA:
527
+ # Use the sample data from swagger documentation
528
+ graphql_body = MediLink_GraphQL.get_sample_eligibility_request()
529
+ MediLink_ConfigLoader.log("Using SAMPLE DATA from swagger documentation", level="INFO")
530
+ else:
531
+ # Build GraphQL request with actual data using consolidated module
532
+ graphql_body = MediLink_GraphQL.build_eligibility_request(graphql_variables)
533
+ MediLink_ConfigLoader.log("Using CONSTRUCTED DATA with consolidated GraphQL module", level="INFO")
534
+
535
+ # Compare with sample data for debugging
536
+ sample_data = MediLink_GraphQL.get_sample_eligibility_request()
537
+ MediLink_ConfigLoader.log("Sample data structure: {}".format(json.dumps(sample_data, indent=2)), level="DEBUG")
538
+ MediLink_ConfigLoader.log("Constructed data structure: {}".format(json.dumps(graphql_body, indent=2)), level="DEBUG")
539
+
540
+ # Compare key differences
541
+ sample_vars = sample_data['variables']['input']
542
+ constructed_vars = graphql_body['variables']['input']
543
+
544
+ # Log differences in variables
545
+ for key in set(sample_vars.keys()) | set(constructed_vars.keys()):
546
+ sample_val = sample_vars.get(key)
547
+ constructed_val = constructed_vars.get(key)
548
+ if sample_val != constructed_val:
549
+ MediLink_ConfigLoader.log("Variable difference - {}: sample='{}', constructed='{}'".format(
550
+ key, sample_val, constructed_val), level="DEBUG")
551
+
552
+ # Log the GraphQL request
553
+ MediLink_ConfigLoader.log("GraphQL request body: {}".format(json.dumps(graphql_body, indent=2)), level="DEBUG")
554
+ MediLink_ConfigLoader.log("GraphQL variables: {}".format(json.dumps(graphql_variables, indent=2)), level="DEBUG")
555
+
556
+ # Add required headers for Super Connector
557
+ headers = {
558
+ 'Content-Type': 'application/json',
559
+ 'Accept': 'application/json',
560
+ 'tin': str(provider_tin) # Ensure TIN is a string
561
+ }
562
+
563
+ # Only add env header when using sample data
564
+ if USE_SAMPLE_DATA:
565
+ headers['env'] = 'sandbox'
566
+
567
+ # Remove None values from headers
568
+ headers = {k: v for k, v in headers.items() if v is not None}
569
+
570
+ # Log the final headers being sent
571
+ MediLink_ConfigLoader.log("Final headers being sent: {}".format(json.dumps(headers, indent=2)), level="DEBUG")
572
+
573
+ # Make the GraphQL API call
574
+ response = client.make_api_call(endpoint_name, 'POST', url_extension, params=None, data=graphql_body, headers=headers)
575
+
576
+ # Transform GraphQL response to match REST API format
577
+ # This ensures the calling code doesn't know the difference
578
+ transformed_response = MediLink_GraphQL.transform_eligibility_response(response)
579
+
580
+ return transformed_response
581
+
470
582
  def is_test_mode(client, body, endpoint_type):
471
583
  """
472
584
  Checks if Test Mode is enabled in the client's configuration and simulates the response if it is.
@@ -557,10 +669,11 @@ if __name__ == "__main__":
557
669
 
558
670
  # Define a configuration to enable or disable tests
559
671
  test_config = {
560
- 'test_fetch_payer_name': True,
672
+ 'test_fetch_payer_name': False,
561
673
  'test_claim_summary': False,
562
674
  'test_eligibility': False,
563
675
  'test_eligibility_v3': False,
676
+ 'test_eligibility_super_connector': False,
564
677
  'test_claim_submission': False,
565
678
  }
566
679
 
@@ -606,6 +719,17 @@ if __name__ == "__main__":
606
719
  except Exception as e:
607
720
  print("TEST API: Error in Eligibility v3 Test: {}".format(e))
608
721
 
722
+ # Test 5: Get Eligibility Super Connector (GraphQL)
723
+ if test_config.get('test_eligibility_super_connector', False):
724
+ try:
725
+ for case in api_test_cases:
726
+ eligibility_super_connector = get_eligibility_super_connector(client, payer_id=case['payer_id'], provider_last_name=case['provider_last_name'],
727
+ search_option=case['search_option'], date_of_birth=case['date_of_birth'],
728
+ member_id=case['member_id'], npi=case['npi'])
729
+ print("TEST API: Eligibility Super Connector: {}".format(eligibility_super_connector))
730
+ except Exception as e:
731
+ print("TEST API: Error in Eligibility Super Connector Test: {}".format(e))
732
+
609
733
  """
610
734
  # Example of iterating over multiple patients (if needed)
611
735
  patients = [
@@ -621,7 +745,7 @@ if __name__ == "__main__":
621
745
  except Exception as e:
622
746
  print("Error in getting eligibility for {}: {}".format(patient['provider_last_name'], e))
623
747
  """
624
- # Test 5: UHC Claim Submission
748
+ # Test 6: UHC Claim Submission
625
749
  if test_config.get('test_claim_submission', False):
626
750
  try:
627
751
  x12_request_data = (
@@ -0,0 +1,409 @@
1
+ # MediLink_GraphQL.py
2
+ """
3
+ GraphQL module for United Healthcare Super Connector API
4
+ Handles query templates, query building, and response transformations
5
+ """
6
+
7
+ import json
8
+
9
+ class GraphQLQueryBuilder:
10
+ """Builder class for constructing GraphQL queries for Super Connector API"""
11
+
12
+ @staticmethod
13
+ def get_eligibility_query() -> str:
14
+ """
15
+ Returns the GraphQL query for eligibility checks.
16
+ Uses the exact working format from the successful cURL request.
17
+ """
18
+ return GraphQLQueryBuilder.get_working_eligibility_query()
19
+
20
+ @staticmethod
21
+ def build_eligibility_variables(
22
+ member_id,
23
+ first_name=None,
24
+ last_name=None,
25
+ date_of_birth=None,
26
+ service_start_date=None,
27
+ service_end_date=None,
28
+ coverage_types=None,
29
+ payer_id=None,
30
+ provider_last_name=None,
31
+ provider_first_name=None,
32
+ provider_npi=None,
33
+ group_number=None,
34
+ trn_id=None,
35
+ service_level_codes=None,
36
+ plan_start_date=None,
37
+ plan_end_date=None,
38
+ family_indicator=None
39
+ ):
40
+ """
41
+ Builds the variables object for the eligibility GraphQL query.
42
+ Uses the exact format that works with the Super Connector API.
43
+
44
+ Args:
45
+ member_id: Unique identifier for the member
46
+ first_name: First name of the member (not used in working format)
47
+ last_name: Last name of the member (not used in working format)
48
+ date_of_birth: Date of birth in ISO 8601 format (YYYY-MM-DD)
49
+ service_start_date: Start date of the service (not used in working format)
50
+ service_end_date: End date of the service (not used in working format)
51
+ coverage_types: Types of coverage (not used in working format)
52
+ payer_id: Payer identifier
53
+ provider_last_name: Last name of the provider
54
+ provider_first_name: First name of the provider (not used in working format)
55
+ provider_npi: National Provider Identifier (NPI) of the provider
56
+ group_number: Group number (not used in working format)
57
+ trn_id: Transaction identifier (not used in working format)
58
+ service_level_codes: Service level codes (not used in working format)
59
+ plan_start_date: Start date of the plan (not used in working format)
60
+ plan_end_date: End date of the plan (not used in working format)
61
+ family_indicator: Indicator for family/individual (not used in working format)
62
+
63
+ Returns:
64
+ Dictionary containing the variables for the GraphQL query in working format
65
+ """
66
+ # Build variables in the exact format that works with the API
67
+ variables = {
68
+ "memberId": member_id,
69
+ "firstName": "", # Always empty string in working format
70
+ "lastName": "", # Always empty string in working format
71
+ "dateOfBirth": date_of_birth,
72
+ "coverageTypes": [], # Always empty array in working format
73
+ "payerId": payer_id,
74
+ "providerFirstName": "", # Always empty string in working format
75
+ "providerLastName": provider_last_name,
76
+ "providerNPI": str(provider_npi) if provider_npi else None,
77
+ # Required empty fields from working format
78
+ "groupNumber": "",
79
+ "serviceLevelCodes": [],
80
+ "planStartDate": "",
81
+ "planEndDate": "",
82
+ "familyIndicator": "",
83
+ "trnId": ""
84
+ }
85
+
86
+ # Remove None values but keep empty strings and arrays
87
+ variables = {k: v for k, v in variables.items() if v is not None}
88
+
89
+ return variables
90
+
91
+ @staticmethod
92
+ def build_eligibility_request(variables):
93
+ """
94
+ Builds the complete GraphQL request body for eligibility checks.
95
+ Uses the working query format.
96
+
97
+ Args:
98
+ variables: Variables dictionary for the GraphQL query
99
+
100
+ Returns:
101
+ Complete GraphQL request body
102
+ """
103
+ return GraphQLQueryBuilder.build_working_eligibility_request(variables)
104
+
105
+ @staticmethod
106
+ def get_sample_eligibility_request():
107
+ """
108
+ Returns the sample GraphQL request from the swagger documentation.
109
+ This is for testing purposes to verify the endpoint is working.
110
+ """
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 } } } } } } }",
113
+ "variables": {
114
+ "input": {
115
+ "memberId": "0001234567",
116
+ "firstName": "ABC",
117
+ "lastName": "EFGH",
118
+ "dateOfBirth": "YYYY-MM-DD",
119
+ "serviceStartDate": "YYYY-MM-DD",
120
+ "serviceEndDate": "YYYY-MM-DD",
121
+ "coverageTypes": [
122
+ "Medical"
123
+ ],
124
+ "payerId": "12345",
125
+ "providerLastName": "XYZ",
126
+ "providerFirstName": "QWERT",
127
+ "providerNPI": "1234567890",
128
+ "groupNumber": "",
129
+ "serviceLevelCodes": [],
130
+ "planStartDate": "",
131
+ "planEndDate": "",
132
+ "familyIndicator": "",
133
+ "trnId": ""
134
+ }
135
+ }
136
+ }
137
+
138
+ @staticmethod
139
+ def get_working_eligibility_query():
140
+ """
141
+ Returns the exact GraphQL query format that works with the Super Connector API.
142
+ This matches the exact format from the successful cURL request.
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 idCardImages {\r\n side\r\n content\r\n contentType\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}"""
145
+
146
+ @staticmethod
147
+ def build_working_eligibility_request(variables):
148
+ """
149
+ Builds the complete GraphQL request body using the working query format.
150
+
151
+ Args:
152
+ variables: Variables dictionary for the GraphQL query
153
+
154
+ Returns:
155
+ Complete GraphQL request body with working query format
156
+ """
157
+ return {
158
+ "query": GraphQLQueryBuilder.get_working_eligibility_query(),
159
+ "variables": {
160
+ "input": variables
161
+ }
162
+ }
163
+
164
+ class GraphQLResponseTransformer:
165
+ """Transforms GraphQL responses to match REST API format"""
166
+
167
+ @staticmethod
168
+ def transform_eligibility_response(graphql_response):
169
+ """
170
+ Transforms the GraphQL eligibility response to match the REST API format.
171
+ This ensures the calling code receives the same structure regardless of endpoint.
172
+
173
+ Args:
174
+ graphql_response: Raw GraphQL response from Super Connector API
175
+
176
+ Returns:
177
+ Transformed response matching REST API format
178
+ """
179
+ try:
180
+ # Check if GraphQL response has data
181
+ if 'data' not in graphql_response or 'checkEligibility' not in graphql_response['data']:
182
+ return {
183
+ 'statuscode': '404',
184
+ 'message': 'No eligibility data found in GraphQL response'
185
+ }
186
+
187
+ eligibility_data = graphql_response['data']['checkEligibility']['eligibility']
188
+ if not eligibility_data:
189
+ return {
190
+ 'statuscode': '404',
191
+ 'message': 'No eligibility records found'
192
+ }
193
+
194
+ # Take the first eligibility record (assuming single member query)
195
+ first_eligibility = eligibility_data[0]
196
+ eligibility_info = first_eligibility.get('eligibilityInfo', {})
197
+
198
+ # Transform to REST-like format
199
+ rest_response = {
200
+ 'statuscode': '200',
201
+ 'message': 'Eligibility found',
202
+ 'rawGraphQLResponse': graphql_response # Include original response for debugging
203
+ }
204
+
205
+ # Safely extract member information
206
+ member_info = eligibility_info.get('member', {})
207
+ if member_info:
208
+ rest_response.update({
209
+ 'memberId': member_info.get('memberId'),
210
+ 'firstName': member_info.get('firstName'),
211
+ 'lastName': member_info.get('lastName'),
212
+ 'middleName': member_info.get('middleName'),
213
+ 'suffix': member_info.get('suffix'),
214
+ 'dateOfBirth': member_info.get('dateOfBirth'),
215
+ 'gender': member_info.get('gender'),
216
+ 'relationship': member_info.get('relationship'),
217
+ 'relationshipCode': member_info.get('relationshipCode'),
218
+ 'individualRelationshipCode': member_info.get('individualRelationshipCode'),
219
+ 'dependentSequenceNumber': member_info.get('dependentSequenceNumber')
220
+ })
221
+
222
+ # Safely extract insurance information
223
+ insurance_info = eligibility_info.get('insuranceInfo', {})
224
+ if insurance_info:
225
+ rest_response.update({
226
+ 'policyNumber': insurance_info.get('policyNumber'),
227
+ 'eligibilityStartDate': insurance_info.get('eligibilityStartDate'),
228
+ 'eligibilityEndDate': insurance_info.get('eligibilityEndDate'),
229
+ 'planStartDate': insurance_info.get('planStartDate'),
230
+ 'planEndDate': insurance_info.get('planEndDate'),
231
+ 'policyStatus': insurance_info.get('policyStatus'),
232
+ 'planTypeDescription': insurance_info.get('planTypeDescription'),
233
+ 'planVariation': insurance_info.get('planVariation'),
234
+ 'reportingCode': insurance_info.get('reportingCode'),
235
+ 'stateOfIssueCode': insurance_info.get('stateOfIssueCode'),
236
+ 'productType': insurance_info.get('productType'),
237
+ 'productId': insurance_info.get('productId'),
238
+ 'productCode': insurance_info.get('productCode'),
239
+ 'lineOfBusiness': insurance_info.get('lineOfBusiness'),
240
+ 'lineOfBusinessCode': insurance_info.get('lineOfBusinessCode'),
241
+ 'coverageTypes': insurance_info.get('coverageTypes', [])
242
+ })
243
+
244
+ # Safely extract associated IDs
245
+ associated_ids = eligibility_info.get('associatedIds', {})
246
+ if associated_ids:
247
+ rest_response.update({
248
+ 'alternateId': associated_ids.get('alternateId'),
249
+ 'medicaidRecipientId': associated_ids.get('medicaidRecipientId'),
250
+ 'exchangeMemberId': associated_ids.get('exchangeMemberId'),
251
+ 'alternateSubscriberId': associated_ids.get('alternateSubscriberId'),
252
+ 'hicNumber': associated_ids.get('hicNumber'),
253
+ 'mbiNumber': associated_ids.get('mbiNumber'),
254
+ 'subscriberMemberFacingIdentifier': associated_ids.get('subscriberMemberFacingIdentifier'),
255
+ 'survivingSpouseId': associated_ids.get('survivingSpouseId'),
256
+ 'subscriberId': associated_ids.get('subscriberId'),
257
+ 'memberReplacementId': associated_ids.get('memberReplacementId'),
258
+ 'legacyMemberId': associated_ids.get('legacyMemberId'),
259
+ 'customerAccountIdentifier': associated_ids.get('customerAccountIdentifier')
260
+ })
261
+
262
+ # Safely extract plan levels
263
+ plan_levels = eligibility_info.get('planLevels', [])
264
+ if plan_levels:
265
+ rest_response['planLevels'] = plan_levels
266
+
267
+ # Safely extract delegated info
268
+ delegated_info = eligibility_info.get('delegatedInfo', [])
269
+ if delegated_info:
270
+ rest_response['delegatedInfo'] = delegated_info
271
+
272
+ # Safely extract additional information
273
+ additional_info = eligibility_info.get('additionalInfo', {})
274
+ if additional_info:
275
+ rest_response['isReferralRequired'] = additional_info.get('isReferralRequired')
276
+
277
+ # Safely extract primary care physician
278
+ pcp = first_eligibility.get('primaryCarePhysician', {})
279
+ if pcp:
280
+ rest_response.update({
281
+ 'pcpIsFound': pcp.get('isPcpFound'),
282
+ 'pcpLastName': pcp.get('lastName'),
283
+ 'pcpFirstName': pcp.get('firstName'),
284
+ 'pcpMiddleName': pcp.get('middleName'),
285
+ 'pcpPhoneNumber': pcp.get('phoneNumber'),
286
+ 'pcpAddress': pcp.get('address'),
287
+ 'pcpNetworkStatusCode': pcp.get('networkStatusCode'),
288
+ 'pcpAffiliateHospitalName': pcp.get('affiliateHospitalName'),
289
+ 'pcpProviderGroupName': pcp.get('providerGroupName')
290
+ })
291
+
292
+ # Safely extract coordination of benefit
293
+ cob = first_eligibility.get('coordinationOfBenefit', {})
294
+ if cob:
295
+ # Transform COB to handle missing 'id' field in payer
296
+ transformed_cob = cob.copy()
297
+ if 'coordinationOfBenefitDetails' in transformed_cob:
298
+ for detail in transformed_cob['coordinationOfBenefitDetails']:
299
+ if 'payer' in detail and 'id' not in detail['payer']:
300
+ # Add empty id field for compatibility
301
+ detail['payer']['id'] = None
302
+ rest_response['coordinationOfBenefit'] = transformed_cob
303
+
304
+ # Safely extract ID card images
305
+ id_card_images = first_eligibility.get('idCardImages', [])
306
+ if id_card_images:
307
+ rest_response['idCardImages'] = id_card_images
308
+
309
+ # Safely extract provider network information
310
+ provider_network = first_eligibility.get('providerNetwork', {})
311
+ if provider_network:
312
+ rest_response.update({
313
+ 'networkStatus': provider_network.get('status'),
314
+ 'networkTier': provider_network.get('tier')
315
+ })
316
+
317
+ # Safely extract service levels
318
+ service_levels = first_eligibility.get('serviceLevels', [])
319
+ if service_levels:
320
+ rest_response['serviceLevels'] = service_levels
321
+
322
+ # Extract first service as example for compatibility
323
+ if service_levels and len(service_levels) > 0:
324
+ first_service_level = service_levels[0]
325
+ individual_services = first_service_level.get('individual', [])
326
+ if individual_services and len(individual_services) > 0:
327
+ first_individual = individual_services[0]
328
+ services = first_individual.get('services', [])
329
+ if services and len(services) > 0:
330
+ first_service = services[0]
331
+ rest_response.update({
332
+ 'serviceCode': first_service.get('serviceCode'),
333
+ 'serviceText': first_service.get('text'),
334
+ 'serviceStatus': first_service.get('status'),
335
+ 'coPayAmount': first_service.get('coPayAmount'),
336
+ 'coPayFrequency': first_service.get('coPayFrequency'),
337
+ 'coInsurancePercent': first_service.get('coInsurancePercent'),
338
+ 'planAmount': first_service.get('planAmount'),
339
+ 'remainingAmount': first_service.get('remainingAmount'),
340
+ 'metYearToDateAmount': first_service.get('metYearToDateAmount')
341
+ })
342
+
343
+ # Safely extract extended attributes
344
+ extended_attrs = first_eligibility.get('extendedAttributes', {})
345
+ if extended_attrs:
346
+ rest_response.update({
347
+ 'fundingCode': extended_attrs.get('fundingCode'),
348
+ 'fundingType': extended_attrs.get('fundingType'),
349
+ 'hsa': extended_attrs.get('hsa'),
350
+ 'cdhp': extended_attrs.get('cdhp'),
351
+ 'governmentProgramCode': extended_attrs.get('governmentProgramCode'),
352
+ 'cmsPackageBenefitPlanCode': extended_attrs.get('cmsPackageBenefitPlanCode'),
353
+ 'cmsSegmentId': extended_attrs.get('cmsSegmentId'),
354
+ 'cmsContractId': extended_attrs.get('cmsContractId'),
355
+ 'marketType': extended_attrs.get('marketType'),
356
+ 'obligorId': extended_attrs.get('obligorId'),
357
+ 'marketSite': extended_attrs.get('marketSite'),
358
+ 'benefitPlanId': extended_attrs.get('benefitPlanId'),
359
+ 'virtualVisit': extended_attrs.get('virtualVisit'),
360
+ 'planVariation': extended_attrs.get('planVariation'),
361
+ 'groupNumber': extended_attrs.get('groupNumber'),
362
+ 'legacyPanelNumber': extended_attrs.get('legacyPanelNumber'),
363
+ 'coverageLevel': extended_attrs.get('coverageLevel'),
364
+ 'sharedArrangement': extended_attrs.get('sharedArrangement'),
365
+ 'productServiceCode': extended_attrs.get('productServiceCode'),
366
+ 'designatedVirtualClinicNetwork': extended_attrs.get('designatedVirtualClinicNetwork'),
367
+ 'medicaidVariableCode': extended_attrs.get('medicaidVariableCode'),
368
+ 'healthInsuranceExchangeId': extended_attrs.get('healthInsuranceExchangeId'),
369
+ 'memberDiv': extended_attrs.get('memberDiv'),
370
+ 'legalEntityCode': extended_attrs.get('legalEntityCode')
371
+ })
372
+
373
+ # Safely extract other beneficiaries
374
+ other_beneficiaries = first_eligibility.get('otherBeneficiaries', [])
375
+ if other_beneficiaries:
376
+ rest_response['otherBeneficiaries'] = other_beneficiaries
377
+
378
+ return rest_response
379
+
380
+ except Exception as e:
381
+ # Log the error and the response structure for debugging
382
+ print("Error transforming GraphQL response: {}".format(str(e)))
383
+ print("Response structure: {}".format(json.dumps(graphql_response, indent=2)))
384
+ return {
385
+ 'statuscode': '500',
386
+ 'message': 'Error processing GraphQL response: {}'.format(str(e)),
387
+ 'rawGraphQLResponse': graphql_response
388
+ }
389
+
390
+ # Convenience functions for easy access
391
+ def get_eligibility_query():
392
+ """Get the eligibility GraphQL query (working format)"""
393
+ return GraphQLQueryBuilder.get_eligibility_query()
394
+
395
+ def build_eligibility_variables(**kwargs):
396
+ """Build eligibility query variables in working format"""
397
+ return GraphQLQueryBuilder.build_eligibility_variables(**kwargs)
398
+
399
+ def build_eligibility_request(variables):
400
+ """Build complete eligibility request body with working format"""
401
+ return GraphQLQueryBuilder.build_eligibility_request(variables)
402
+
403
+ def transform_eligibility_response(graphql_response):
404
+ """Transform GraphQL eligibility response to REST format"""
405
+ return GraphQLResponseTransformer.transform_eligibility_response(graphql_response)
406
+
407
+ def get_sample_eligibility_request():
408
+ """Get the sample GraphQL request from swagger documentation"""
409
+ return GraphQLQueryBuilder.get_sample_eligibility_request()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: medicafe
3
- Version: 0.250610.1
3
+ Version: 0.250707.0
4
4
  Summary: MediCafe
5
5
  Home-page: https://github.com/katanada2
6
6
  Author: Daniel Vidaud
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: medicafe
3
- Version: 0.250610.1
3
+ Version: 0.250707.0
4
4
  Summary: MediCafe
5
5
  Home-page: https://github.com/katanada2
6
6
  Author: Daniel Vidaud
@@ -31,6 +31,7 @@ MediLink/MediLink_Decoder.py
31
31
  MediLink/MediLink_Deductible.py
32
32
  MediLink/MediLink_Down.py
33
33
  MediLink/MediLink_Gmail.py
34
+ MediLink/MediLink_GraphQL.py
34
35
  MediLink/MediLink_Mailer.py
35
36
  MediLink/MediLink_Parser.py
36
37
  MediLink/MediLink_Scan.py
@@ -2,7 +2,7 @@ from setuptools import setup, find_packages
2
2
 
3
3
  setup(
4
4
  name='medicafe',
5
- version="0.250610.1",
5
+ version="0.250707.0",
6
6
  description='MediCafe',
7
7
  long_description="""
8
8
  # Project Overview: MediCafe
File without changes
File without changes
File without changes
File without changes