medicafe 0.250318.0__tar.gz → 0.250410.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.
- {medicafe-0.250318.0 → medicafe-0.250410.0}/MediBot/MediBot_Preprocessor.py +5 -0
- {medicafe-0.250318.0 → medicafe-0.250410.0}/MediBot/MediBot_Preprocessor_lib.py +22 -1
- {medicafe-0.250318.0 → medicafe-0.250410.0}/MediLink/MediLink_837p_encoder_library.py +26 -2
- {medicafe-0.250318.0 → medicafe-0.250410.0}/MediLink/MediLink_API_v3.py +36 -11
- {medicafe-0.250318.0/medicafe.egg-info → medicafe-0.250410.0}/PKG-INFO +1 -1
- {medicafe-0.250318.0 → medicafe-0.250410.0/medicafe.egg-info}/PKG-INFO +1 -1
- {medicafe-0.250318.0 → medicafe-0.250410.0}/setup.py +1 -1
- {medicafe-0.250318.0 → medicafe-0.250410.0}/LICENSE +0 -0
- {medicafe-0.250318.0 → medicafe-0.250410.0}/MANIFEST.in +0 -0
- {medicafe-0.250318.0 → medicafe-0.250410.0}/MediBot/MediBot.bat +0 -0
- {medicafe-0.250318.0 → medicafe-0.250410.0}/MediBot/MediBot.py +0 -0
- {medicafe-0.250318.0 → medicafe-0.250410.0}/MediBot/MediBot_Charges.py +0 -0
- {medicafe-0.250318.0 → medicafe-0.250410.0}/MediBot/MediBot_Crosswalk_Library.py +0 -0
- {medicafe-0.250318.0 → medicafe-0.250410.0}/MediBot/MediBot_Post.py +0 -0
- {medicafe-0.250318.0 → medicafe-0.250410.0}/MediBot/MediBot_UI.py +0 -0
- {medicafe-0.250318.0 → medicafe-0.250410.0}/MediBot/MediBot_dataformat_library.py +0 -0
- {medicafe-0.250318.0 → medicafe-0.250410.0}/MediBot/MediBot_docx_decoder.py +0 -0
- {medicafe-0.250318.0 → medicafe-0.250410.0}/MediBot/PDF_to_CSV_Cleaner.py +0 -0
- {medicafe-0.250318.0 → medicafe-0.250410.0}/MediBot/__init__.py +0 -0
- {medicafe-0.250318.0 → medicafe-0.250410.0}/MediBot/update_json.py +0 -0
- {medicafe-0.250318.0 → medicafe-0.250410.0}/MediBot/update_medicafe.py +0 -0
- {medicafe-0.250318.0 → medicafe-0.250410.0}/MediLink/MediLink.py +0 -0
- {medicafe-0.250318.0 → medicafe-0.250410.0}/MediLink/MediLink_837p_encoder.py +0 -0
- {medicafe-0.250318.0 → medicafe-0.250410.0}/MediLink/MediLink_API_Generator.py +0 -0
- {medicafe-0.250318.0 → medicafe-0.250410.0}/MediLink/MediLink_API_v2.py +0 -0
- {medicafe-0.250318.0 → medicafe-0.250410.0}/MediLink/MediLink_APIs.py +0 -0
- {medicafe-0.250318.0 → medicafe-0.250410.0}/MediLink/MediLink_Azure.py +0 -0
- {medicafe-0.250318.0 → medicafe-0.250410.0}/MediLink/MediLink_ClaimStatus.py +0 -0
- {medicafe-0.250318.0 → medicafe-0.250410.0}/MediLink/MediLink_ConfigLoader.py +0 -0
- {medicafe-0.250318.0 → medicafe-0.250410.0}/MediLink/MediLink_DataMgmt.py +0 -0
- {medicafe-0.250318.0 → medicafe-0.250410.0}/MediLink/MediLink_Decoder.py +0 -0
- {medicafe-0.250318.0 → medicafe-0.250410.0}/MediLink/MediLink_Deductible.py +0 -0
- {medicafe-0.250318.0 → medicafe-0.250410.0}/MediLink/MediLink_Down.py +0 -0
- {medicafe-0.250318.0 → medicafe-0.250410.0}/MediLink/MediLink_Gmail.py +0 -0
- {medicafe-0.250318.0 → medicafe-0.250410.0}/MediLink/MediLink_Mailer.py +0 -0
- {medicafe-0.250318.0 → medicafe-0.250410.0}/MediLink/MediLink_Parser.py +0 -0
- {medicafe-0.250318.0 → medicafe-0.250410.0}/MediLink/MediLink_Scan.py +0 -0
- {medicafe-0.250318.0 → medicafe-0.250410.0}/MediLink/MediLink_Scheduler.py +0 -0
- {medicafe-0.250318.0 → medicafe-0.250410.0}/MediLink/MediLink_UI.py +0 -0
- {medicafe-0.250318.0 → medicafe-0.250410.0}/MediLink/MediLink_Up.py +0 -0
- {medicafe-0.250318.0 → medicafe-0.250410.0}/MediLink/MediLink_batch.bat +0 -0
- {medicafe-0.250318.0 → medicafe-0.250410.0}/MediLink/Soumit_api.py +0 -0
- {medicafe-0.250318.0 → medicafe-0.250410.0}/MediLink/__init__.py +0 -0
- {medicafe-0.250318.0 → medicafe-0.250410.0}/MediLink/test.py +0 -0
- {medicafe-0.250318.0 → medicafe-0.250410.0}/README.md +0 -0
- {medicafe-0.250318.0 → medicafe-0.250410.0}/medicafe.egg-info/SOURCES.txt +0 -0
- {medicafe-0.250318.0 → medicafe-0.250410.0}/medicafe.egg-info/dependency_links.txt +0 -0
- {medicafe-0.250318.0 → medicafe-0.250410.0}/medicafe.egg-info/not-zip-safe +0 -0
- {medicafe-0.250318.0 → medicafe-0.250410.0}/medicafe.egg-info/requires.txt +0 -0
- {medicafe-0.250318.0 → medicafe-0.250410.0}/medicafe.egg-info/top_level.txt +0 -0
- {medicafe-0.250318.0 → medicafe-0.250410.0}/setup.cfg +0 -0
|
@@ -84,6 +84,11 @@ def preprocess_csv_data(csv_data, crosswalk):
|
|
|
84
84
|
# Enrich the procedure code column based on the diagnosis code for each patient.
|
|
85
85
|
# MediLink_ConfigLoader.log("CSV Pre-processor: Populating 'Procedure Code' based on Crosswalk...", level="INFO")
|
|
86
86
|
# MediBot_Preprocessor_lib.update_procedure_codes(csv_data, crosswalk)
|
|
87
|
+
|
|
88
|
+
# Convert all text fields to uppercase
|
|
89
|
+
MediLink_ConfigLoader.log("CSV Pre-processor: Converting all text fields to uppercase...", level="INFO")
|
|
90
|
+
print("Converting all text fields to uppercase...")
|
|
91
|
+
MediBot_Preprocessor_lib.capitalize_all_fields(csv_data)
|
|
87
92
|
|
|
88
93
|
except Exception as e:
|
|
89
94
|
message = "An error occurred while pre-processing CSV data. Please repair the CSV directly and try again: {}".format(e)
|
|
@@ -714,4 +714,25 @@ def load_historical_payer_to_patient_mappings(config):
|
|
|
714
714
|
if not payer_to_patient_ids:
|
|
715
715
|
print("No historical mappings were generated.")
|
|
716
716
|
|
|
717
|
-
return dict(payer_to_patient_ids)
|
|
717
|
+
return dict(payer_to_patient_ids)
|
|
718
|
+
|
|
719
|
+
def capitalize_all_fields(csv_data):
|
|
720
|
+
"""
|
|
721
|
+
Converts all text fields in the CSV data to uppercase.
|
|
722
|
+
|
|
723
|
+
Parameters:
|
|
724
|
+
csv_data (list of dict): The CSV data where each row is represented as a dictionary.
|
|
725
|
+
|
|
726
|
+
Returns:
|
|
727
|
+
None: The function modifies the csv_data in place.
|
|
728
|
+
"""
|
|
729
|
+
for row in csv_data:
|
|
730
|
+
for key, value in row.items():
|
|
731
|
+
if isinstance(value, str):
|
|
732
|
+
row[key] = value.upper()
|
|
733
|
+
elif isinstance(value, datetime):
|
|
734
|
+
# Keep datetime objects as they are
|
|
735
|
+
pass
|
|
736
|
+
elif value is not None:
|
|
737
|
+
# Convert any other non-None values to string and then uppercase
|
|
738
|
+
row[key] = str(value).upper()
|
|
@@ -289,7 +289,7 @@ def resolve_payer_name(payer_id, config, primary_endpoint, insurance_name, parse
|
|
|
289
289
|
MediLink_ConfigLoader.log("API Resolved to standard insurance name: {} for corrected payer ID: {}".format(resolved_name, corrected_payer_id), config, level="INFO")
|
|
290
290
|
|
|
291
291
|
# Step 7: Ask for user confirmation using the helper
|
|
292
|
-
confirmation_prompt = "
|
|
292
|
+
confirmation_prompt = "Proceed with updating the Payer ID for '{}'? (yes/no): ".format(resolved_name)
|
|
293
293
|
if get_user_confirmation(confirmation_prompt):
|
|
294
294
|
# Step 8: Load crosswalk
|
|
295
295
|
try:
|
|
@@ -310,7 +310,31 @@ def resolve_payer_name(payer_id, config, primary_endpoint, insurance_name, parse
|
|
|
310
310
|
# Step 10: Handle rejection
|
|
311
311
|
print("User did not confirm the standard insurance name. Manual intervention is required.")
|
|
312
312
|
MediLink_ConfigLoader.log("User did not confirm the standard insurance name. Manual intervention is required.", config, level="CRITICAL")
|
|
313
|
-
|
|
313
|
+
|
|
314
|
+
# TODO: CRITICAL ISSUE - Current rejection handling is incorrect
|
|
315
|
+
# The current implementation exits the program when a user rejects the standard insurance name,
|
|
316
|
+
# which is an overly aggressive approach. Instead, we should:
|
|
317
|
+
# 1. Prompt the user to manually enter the correct insurance name
|
|
318
|
+
# 2. Use that manually entered name to proceed with the claim processing
|
|
319
|
+
# 3. Update the crosswalk with the corrected payer name (requires a new function to be implemented)
|
|
320
|
+
# 4. Log the correction for future reference
|
|
321
|
+
#
|
|
322
|
+
# The insurance name confirmation is primarily a sanity check to verify the API recognizes the payer ID,
|
|
323
|
+
# not a critical validation for claim processing. The payer name is not used in the crosswalk or in the
|
|
324
|
+
# actual claims once they are built. The current implementation unnecessarily halts the entire process
|
|
325
|
+
# when this check fails, rather than providing a recovery path.
|
|
326
|
+
#
|
|
327
|
+
# When revisiting this code, the entire flow of interdependent functions should be reconsidered to
|
|
328
|
+
# ensure proper error handling and recovery mechanisms are in place throughout the process.
|
|
329
|
+
|
|
330
|
+
# Placeholder for future implementation:
|
|
331
|
+
# corrected_name = input("Please enter the correct insurance name: ")
|
|
332
|
+
# MediLink_ConfigLoader.log(f"User provided corrected insurance name: {corrected_name}", config, level="INFO")
|
|
333
|
+
# print(f"Using manually entered insurance name: {corrected_name}")
|
|
334
|
+
# TODO: Implement update_crosswalk_with_corrected_payer_name(corrected_name, payer_id, config, crosswalk)
|
|
335
|
+
# return corrected_name
|
|
336
|
+
|
|
337
|
+
exit(1)
|
|
314
338
|
except Exception as e:
|
|
315
339
|
# Step 11: Handle exceptions during resolution
|
|
316
340
|
print("Failed to resolve corrected payer ID to standard insurance name: {}".format(e))
|
|
@@ -160,21 +160,35 @@ class APIClient(BaseAPIClient):
|
|
|
160
160
|
url = base_url + url_extension
|
|
161
161
|
|
|
162
162
|
try:
|
|
163
|
-
# Make the API call based on call_type
|
|
164
|
-
if call_type == 'GET':
|
|
165
|
-
response = requests.get(url, headers=headers, params=params)
|
|
166
|
-
elif call_type == 'POST':
|
|
167
|
-
headers['Content-Type'] = 'application/json'
|
|
168
|
-
response = requests.post(url, headers=headers, json=data)
|
|
169
|
-
elif call_type == 'DELETE':
|
|
170
|
-
response = requests.delete(url, headers=headers)
|
|
171
|
-
else:
|
|
172
|
-
raise ValueError("Unsupported call type: {}".format(call_type))
|
|
173
|
-
|
|
174
163
|
masked_headers = headers.copy()
|
|
175
164
|
if 'Authorization' in masked_headers:
|
|
176
165
|
masked_headers['Authorization'] = 'Bearer ***'
|
|
177
166
|
|
|
167
|
+
def make_request():
|
|
168
|
+
if call_type == 'GET':
|
|
169
|
+
return requests.get(url, headers=headers, params=params)
|
|
170
|
+
elif call_type == 'POST':
|
|
171
|
+
headers['Content-Type'] = 'application/json'
|
|
172
|
+
return requests.post(url, headers=headers, json=data)
|
|
173
|
+
elif call_type == 'DELETE':
|
|
174
|
+
return requests.delete(url, headers=headers)
|
|
175
|
+
else:
|
|
176
|
+
raise ValueError("Unsupported call type: {}".format(call_type))
|
|
177
|
+
|
|
178
|
+
# Make initial request
|
|
179
|
+
response = make_request()
|
|
180
|
+
|
|
181
|
+
# If we get a 5xx error, wait and retry once
|
|
182
|
+
if 500 <= response.status_code < 600:
|
|
183
|
+
MediLink_ConfigLoader.log(
|
|
184
|
+
"Received {} error from server for {} request to {}. Waiting 1 second before retry...".format(
|
|
185
|
+
response.status_code, call_type, url
|
|
186
|
+
),
|
|
187
|
+
level="WARNING"
|
|
188
|
+
)
|
|
189
|
+
time.sleep(1)
|
|
190
|
+
response = make_request()
|
|
191
|
+
|
|
178
192
|
# Raise an HTTPError if the response was unsuccessful
|
|
179
193
|
response.raise_for_status()
|
|
180
194
|
|
|
@@ -305,6 +319,17 @@ def fetch_payer_name_from_api(client, payer_id, config, primary_endpoint='AVAILI
|
|
|
305
319
|
endpoints = config['MediLink_Config']['endpoints'] # Re-attempt to access endpoints
|
|
306
320
|
MediLink_ConfigLoader.log("Re-loaded configuration successfully.", level="INFO")
|
|
307
321
|
|
|
322
|
+
# Sanitize and validate payer_id
|
|
323
|
+
if not isinstance(payer_id, str):
|
|
324
|
+
payer_id = str(payer_id)
|
|
325
|
+
|
|
326
|
+
payer_id = ''.join(char for char in payer_id if char.isalnum())
|
|
327
|
+
|
|
328
|
+
if not payer_id:
|
|
329
|
+
error_message = "Invalid payer_id in API v3: {}. Must contain a string of alphanumeric characters.".format(payer_id)
|
|
330
|
+
MediLink_ConfigLoader.log(error_message, level="ERROR")
|
|
331
|
+
print(error_message)
|
|
332
|
+
|
|
308
333
|
# Define endpoint rotation logic
|
|
309
334
|
endpoint_order = ([primary_endpoint] +
|
|
310
335
|
[endpoint for endpoint in endpoints if endpoint != primary_endpoint]
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|