medicafe 0.240716.2__py3-none-any.whl → 0.240925.9__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of medicafe might be problematic. Click here for more details.
- MediBot/MediBot.bat +56 -16
- MediBot/MediBot.py +100 -78
- MediBot/MediBot_Crosswalk_Library.py +496 -194
- MediBot/MediBot_Preprocessor.py +22 -14
- MediBot/MediBot_Preprocessor_lib.py +301 -143
- MediBot/MediBot_UI.py +25 -24
- MediBot/MediBot_dataformat_library.py +17 -25
- MediBot/MediBot_docx_decoder.py +267 -110
- MediBot/update_json.py +26 -1
- MediBot/update_medicafe.py +134 -44
- MediLink/MediLink.py +95 -53
- MediLink/MediLink_837p_encoder.py +83 -66
- MediLink/MediLink_837p_encoder_library.py +159 -102
- MediLink/MediLink_API_Generator.py +1 -7
- MediLink/MediLink_API_v3.py +348 -63
- MediLink/MediLink_APIs.py +1 -2
- MediLink/MediLink_ClaimStatus.py +21 -6
- MediLink/MediLink_ConfigLoader.py +9 -9
- MediLink/MediLink_DataMgmt.py +321 -100
- MediLink/MediLink_Decoder.py +249 -87
- MediLink/MediLink_Deductible.py +62 -56
- MediLink/MediLink_Down.py +115 -121
- MediLink/MediLink_Gmail.py +2 -11
- MediLink/MediLink_Parser.py +63 -36
- MediLink/MediLink_UI.py +36 -23
- MediLink/MediLink_Up.py +188 -115
- {medicafe-0.240716.2.dist-info → medicafe-0.240925.9.dist-info}/METADATA +1 -1
- medicafe-0.240925.9.dist-info/RECORD +47 -0
- medicafe-0.240716.2.dist-info/RECORD +0 -47
- {medicafe-0.240716.2.dist-info → medicafe-0.240925.9.dist-info}/LICENSE +0 -0
- {medicafe-0.240716.2.dist-info → medicafe-0.240925.9.dist-info}/WHEEL +0 -0
- {medicafe-0.240716.2.dist-info → medicafe-0.240925.9.dist-info}/top_level.txt +0 -0
|
@@ -1,13 +1,11 @@
|
|
|
1
|
+
# MediLink_837p_encoder_library.py
|
|
1
2
|
from datetime import datetime
|
|
2
|
-
import sys
|
|
3
|
-
from MediLink import MediLink_ConfigLoader
|
|
4
|
-
|
|
5
|
-
# Add parent directory of the project to the Python path
|
|
6
|
-
import sys
|
|
7
|
-
import os
|
|
3
|
+
import sys, os
|
|
4
|
+
from MediLink import MediLink_ConfigLoader
|
|
8
5
|
|
|
9
6
|
project_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))
|
|
10
|
-
sys.path
|
|
7
|
+
if project_dir not in sys.path:
|
|
8
|
+
sys.path.append(project_dir)
|
|
11
9
|
|
|
12
10
|
from MediBot import MediBot_Preprocessor_lib
|
|
13
11
|
load_insurance_data_from_mains = MediBot_Preprocessor_lib.load_insurance_data_from_mains
|
|
@@ -154,9 +152,10 @@ def create_1000A_submitter_name_segment(patient_data, config, endpoint):
|
|
|
154
152
|
# Submitter contact details
|
|
155
153
|
contact_name = config.get('submitter_name', 'NONE')
|
|
156
154
|
contact_telephone_number = config.get('submitter_tel', 'NONE')
|
|
155
|
+
entity_type_qualifier = '2' # if contact_name else '1' BUG - 1 if submitter_first_name is not empty.
|
|
157
156
|
|
|
158
157
|
# Construct NM1 segment for the submitter
|
|
159
|
-
nm1_segment = "NM1*41*
|
|
158
|
+
nm1_segment = "NM1*41*{}*{}*****{}*{}~".format(entity_type_qualifier, submitter_name, submitter_id_qualifier, submitter_id)
|
|
160
159
|
|
|
161
160
|
# Construct PER segment for the submitter's contact information
|
|
162
161
|
per_segment = "PER*IC*{}*TE*{}~".format(contact_name, contact_telephone_number)
|
|
@@ -182,7 +181,7 @@ def create_1000B_receiver_name_segment(config, endpoint):
|
|
|
182
181
|
receiver_edi=receiver_edi
|
|
183
182
|
)
|
|
184
183
|
|
|
185
|
-
def payer_id_to_payer_name(parsed_data, config, endpoint):
|
|
184
|
+
def payer_id_to_payer_name(parsed_data, config, endpoint, crosswalk, client):
|
|
186
185
|
"""
|
|
187
186
|
Preprocesses payer information from parsed data and enriches parsed_data with the payer name and ID.
|
|
188
187
|
|
|
@@ -198,7 +197,7 @@ def payer_id_to_payer_name(parsed_data, config, endpoint):
|
|
|
198
197
|
insurance_name = parsed_data.get('INAME', '')
|
|
199
198
|
|
|
200
199
|
# Step 2: Map insurance name to payer ID
|
|
201
|
-
payer_id = map_insurance_name_to_payer_id(insurance_name, config)
|
|
200
|
+
payer_id = map_insurance_name_to_payer_id(insurance_name, config, client)
|
|
202
201
|
|
|
203
202
|
# Step 3: Validate payer_id
|
|
204
203
|
if payer_id is None:
|
|
@@ -207,7 +206,7 @@ def payer_id_to_payer_name(parsed_data, config, endpoint):
|
|
|
207
206
|
raise ValueError(error_message)
|
|
208
207
|
|
|
209
208
|
# Step 4: Resolve payer name using payer ID
|
|
210
|
-
payer_name = resolve_payer_name(payer_id, config, endpoint, insurance_name, parsed_data)
|
|
209
|
+
payer_name = resolve_payer_name(payer_id, config, endpoint, insurance_name, parsed_data, crosswalk, client)
|
|
211
210
|
|
|
212
211
|
# Enrich parsed_data with payer name and payer ID
|
|
213
212
|
parsed_data['payer_name'] = payer_name
|
|
@@ -238,88 +237,160 @@ def create_2010BB_payer_information_segment(parsed_data):
|
|
|
238
237
|
# Build NM1 segment using provided payer name and payer ID
|
|
239
238
|
return build_nm1_segment(payer_name, payer_id)
|
|
240
239
|
|
|
241
|
-
def
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
parsed_data (dict): Parsed data containing patient information.
|
|
251
|
-
|
|
252
|
-
Returns:
|
|
253
|
-
str: The resolved payer name.
|
|
254
|
-
"""
|
|
240
|
+
def get_user_confirmation(prompt_message):
|
|
241
|
+
while True:
|
|
242
|
+
response = input(prompt_message).strip().lower()
|
|
243
|
+
if response in ['yes', 'y']:
|
|
244
|
+
return True
|
|
245
|
+
elif response in ['no', 'n']:
|
|
246
|
+
return False
|
|
247
|
+
else:
|
|
248
|
+
print("Please respond with 'yes' or 'no'.")
|
|
255
249
|
|
|
250
|
+
def resolve_payer_name(payer_id, config, primary_endpoint, insurance_name, parsed_data, crosswalk, client):
|
|
251
|
+
# Check if the payer_id is in the crosswalk with a name already attached to it.
|
|
252
|
+
if payer_id in crosswalk.get('payer_id', {}):
|
|
253
|
+
payer_info = crosswalk['payer_id'][payer_id]
|
|
254
|
+
MediLink_ConfigLoader.log("Payer ID {} found in crosswalk with name: {}".format(payer_id, payer_info['name']), level="DEBUG")
|
|
255
|
+
return payer_info['name'] # Return the name from the crosswalk directly.
|
|
256
|
+
|
|
256
257
|
# Step 1: Attempt to fetch payer name from API using primary endpoint
|
|
257
258
|
MediLink_ConfigLoader.log("Attempting to resolve Payer ID {} via API.".format(payer_id), level="INFO")
|
|
258
259
|
try:
|
|
259
|
-
return fetch_payer_name_from_api(payer_id, config, primary_endpoint)
|
|
260
|
+
return fetch_payer_name_from_api(client, payer_id, config, primary_endpoint)
|
|
260
261
|
except Exception as api_error:
|
|
261
262
|
# Step 2: Log API resolution failure and initiate user intervention
|
|
262
263
|
MediLink_ConfigLoader.log("API resolution failed for {}: {}. Initiating user intervention.".format(payer_id, str(api_error)), config, level="WARNING")
|
|
263
264
|
|
|
264
265
|
# Step 3: Print warning message for user intervention
|
|
265
266
|
print("\n\nWARNING: Unable to verify Payer ID '{}' for patient '{}'!".format(payer_id, parsed_data.get('CHART', 'unknown')))
|
|
266
|
-
print(" Claims for '{}' may be incorrectly
|
|
267
|
-
print("\nACTION REQUIRED: Please verify the internet connection and the Payer ID by searching for it")
|
|
268
|
-
print("at the expected endpoint's website or using Google.")
|
|
267
|
+
print(" Claims for '{}' may be incorrectly routed or fail without intervention.".format(insurance_name))
|
|
268
|
+
print("\nACTION REQUIRED: Please verify the internet connection and the Payer ID by searching for it at the expected endpoint's website or using Google.")
|
|
269
269
|
print("\nNote: If the Payer ID '{}' is incorrect for '{}', \nit may need to be manually corrected.".format(payer_id, insurance_name))
|
|
270
270
|
print("If the Payer ID appears correct, you may skip the correction and force-continue with this one.")
|
|
271
271
|
print("\nPlease check the Payer ID in the Crosswalk and the initial \ndata source (e.g., Carol's CSV) as needed.")
|
|
272
272
|
print("If unsure, llamar a Dani for guidance on manual corrections.")
|
|
273
|
-
|
|
273
|
+
|
|
274
274
|
# Step 4: Integrate user input logic
|
|
275
|
-
user_decision = input("\nType 'FORCE' to force-continue with the Medisoft name,
|
|
276
|
-
|
|
275
|
+
user_decision = input("\nType 'FORCE' to force-continue with the Medisoft name, or press Enter to pause processing and make corrections: ").strip().lower()
|
|
276
|
+
|
|
277
277
|
if user_decision == 'force':
|
|
278
278
|
# Step 5: Fallback to truncated insurance name
|
|
279
279
|
truncated_name = insurance_name[:10] # Temporary fallback
|
|
280
280
|
MediLink_ConfigLoader.log("Using truncated insurance name '{}' as a fallback for {}".format(truncated_name, payer_id), config, level="WARNING")
|
|
281
281
|
return truncated_name
|
|
282
|
-
elif not user_decision:
|
|
282
|
+
elif not user_decision:
|
|
283
|
+
# Step 6: Prompt user for corrected payer ID
|
|
283
284
|
corrected_payer_id = prompt_user_for_payer_id(insurance_name)
|
|
284
285
|
if corrected_payer_id:
|
|
285
286
|
try:
|
|
286
|
-
resolved_name = fetch_payer_name_from_api(corrected_payer_id, config, primary_endpoint)
|
|
287
|
+
resolved_name = fetch_payer_name_from_api(client, corrected_payer_id, config, primary_endpoint)
|
|
287
288
|
print("API resolved to insurance name: {}".format(resolved_name))
|
|
288
289
|
MediLink_ConfigLoader.log("API Resolved to standard insurance name: {} for corrected payer ID: {}".format(resolved_name, corrected_payer_id), config, level="INFO")
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
if
|
|
293
|
-
|
|
290
|
+
|
|
291
|
+
# Step 7: Ask for user confirmation using the helper
|
|
292
|
+
confirmation_prompt = "Is the standard insurance name '{}' correct? (yes/no): ".format(resolved_name)
|
|
293
|
+
if get_user_confirmation(confirmation_prompt):
|
|
294
|
+
# Step 8: Load crosswalk
|
|
295
|
+
try:
|
|
296
|
+
config, crosswalk = MediLink_ConfigLoader.load_configuration()
|
|
297
|
+
except Exception as e:
|
|
298
|
+
print("Failed to load configuration and crosswalk: {}".format(e))
|
|
299
|
+
MediLink_ConfigLoader.log("Failed to load configuration and crosswalk: {}".format(e), config, level="ERROR")
|
|
300
|
+
exit(1)
|
|
301
|
+
|
|
302
|
+
# Step 9: Update the crosswalk with the corrected Payer ID
|
|
303
|
+
if MediBot_Crosswalk_Library.update_crosswalk_with_corrected_payer_id(client, payer_id, corrected_payer_id, config, crosswalk):
|
|
294
304
|
return resolved_name
|
|
295
305
|
else:
|
|
296
306
|
print("Failed to update crosswalk with the corrected Payer ID.")
|
|
297
|
-
|
|
307
|
+
MediLink_ConfigLoader.log("Failed to update crosswalk with the corrected Payer ID.", config, level="ERROR")
|
|
308
|
+
exit(1) # Consider handling failure differently.
|
|
298
309
|
else:
|
|
310
|
+
# Step 10: Handle rejection
|
|
299
311
|
print("User did not confirm the standard insurance name. Manual intervention is required.")
|
|
300
312
|
MediLink_ConfigLoader.log("User did not confirm the standard insurance name. Manual intervention is required.", config, level="CRITICAL")
|
|
301
|
-
exit(1)
|
|
313
|
+
exit(1) # Consider handling differently.
|
|
302
314
|
except Exception as e:
|
|
315
|
+
# Step 11: Handle exceptions during resolution
|
|
303
316
|
print("Failed to resolve corrected payer ID to standard insurance name: {}".format(e))
|
|
304
317
|
MediLink_ConfigLoader.log("Failed to resolve corrected payer ID to standard insurance name: {}".format(e), config, level="ERROR")
|
|
305
|
-
exit(1)
|
|
318
|
+
exit(1) # Consider handling differently.
|
|
306
319
|
else:
|
|
320
|
+
# Step 12: Handle absence of corrected payer ID
|
|
307
321
|
print("Exiting script. Please make the necessary corrections and retry.")
|
|
308
|
-
|
|
322
|
+
MediLink_ConfigLoader.log("Exiting script due to absence of corrected Payer ID.", config, level="CRITICAL")
|
|
323
|
+
exit(1) # Consider handling differently.
|
|
324
|
+
else:
|
|
325
|
+
# Optional: Handle unexpected user input
|
|
326
|
+
print("Invalid input. Manual intervention is required.")
|
|
327
|
+
MediLink_ConfigLoader.log("Invalid user input during payer name resolution.", config, level="CRITICAL")
|
|
328
|
+
exit(1) # Consider handling differently.
|
|
329
|
+
|
|
330
|
+
def handle_missing_payer_id(insurance_name, config, crosswalk, client):
|
|
331
|
+
# Step 1: Inform about the missing Payer ID
|
|
332
|
+
print("Missing Payer ID for insurance name: {}".format(insurance_name))
|
|
333
|
+
MediLink_ConfigLoader.log("Missing Payer ID for insurance name: {}".format(insurance_name), config, level="WARNING")
|
|
334
|
+
|
|
335
|
+
# Step 2: Prompt the user for manual payer ID input
|
|
336
|
+
payer_id = prompt_user_for_payer_id(insurance_name)
|
|
337
|
+
|
|
338
|
+
if not payer_id:
|
|
339
|
+
# Step 3: Handle absence of payer ID input
|
|
340
|
+
message = "Unable to resolve missing Payer ID. Manual intervention is required."
|
|
341
|
+
MediLink_ConfigLoader.log(message, config, level="CRITICAL")
|
|
342
|
+
print(message)
|
|
343
|
+
return None
|
|
344
|
+
|
|
345
|
+
# Step 4: Resolve the payer ID to a standard insurance name via API
|
|
346
|
+
try:
|
|
347
|
+
# primary_endpoint=None should kick to the default in the API function.
|
|
348
|
+
standard_insurance_name = resolve_payer_name(payer_id, config, primary_endpoint=None, insurance_name=insurance_name, parsed_data={}, crosswalk=crosswalk, client=client)
|
|
349
|
+
message = "Resolved to standard insurance name: {} for payer ID: {}".format(standard_insurance_name, payer_id)
|
|
350
|
+
print(message)
|
|
351
|
+
MediLink_ConfigLoader.log(message, config, level="INFO")
|
|
352
|
+
except Exception as e:
|
|
353
|
+
# Step 5: Handle exceptions during resolution
|
|
354
|
+
message = "Failed to resolve payer ID to standard insurance name: {}".format(e)
|
|
355
|
+
print(message)
|
|
356
|
+
MediLink_ConfigLoader.log(message, config, level="ERROR")
|
|
357
|
+
return None
|
|
358
|
+
|
|
359
|
+
# Step 6: Ask for user confirmation
|
|
360
|
+
confirmation_prompt = "Is the standard insurance name '{}' correct? (yes/no): ".format(standard_insurance_name)
|
|
361
|
+
if get_user_confirmation(confirmation_prompt):
|
|
362
|
+
# Step 7: Update the crosswalk with the new payer ID and insurance name mapping
|
|
363
|
+
try:
|
|
364
|
+
MediBot_Crosswalk_Library.update_crosswalk_with_new_payer_id(insurance_name, payer_id, config)
|
|
365
|
+
return payer_id
|
|
366
|
+
except Exception as e:
|
|
367
|
+
print("Failed to update crosswalk with new Payer ID: {}".format(e))
|
|
368
|
+
MediLink_ConfigLoader.log("Failed to update crosswalk with new Payer ID: {}".format(e), config, level="ERROR")
|
|
369
|
+
return None
|
|
370
|
+
else:
|
|
371
|
+
# Step 8: Handle rejection
|
|
372
|
+
print("User did not confirm the standard insurance name. Manual intervention is required.")
|
|
373
|
+
MediLink_ConfigLoader.log("User did not confirm the standard insurance name. Manual intervention is required.", config, level="CRITICAL")
|
|
374
|
+
return None
|
|
309
375
|
|
|
310
376
|
def prompt_user_for_payer_id(insurance_name):
|
|
311
377
|
"""
|
|
312
|
-
Prompts the user to input the payer ID manually.
|
|
378
|
+
Prompts the user to input the payer ID manually and ensures that a valid ID is provided.
|
|
313
379
|
"""
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
380
|
+
while True:
|
|
381
|
+
print("Manual intervention required: No payer ID found for insurance name '{}'.".format(insurance_name))
|
|
382
|
+
payer_id = input("Please enter the payer ID manually: ").strip()
|
|
383
|
+
|
|
384
|
+
if payer_id:
|
|
385
|
+
return payer_id
|
|
386
|
+
else:
|
|
387
|
+
print("Error: Payer ID cannot be empty. Please try again.")
|
|
317
388
|
|
|
318
389
|
def build_nm1_segment(payer_name, payer_id):
|
|
319
390
|
# Step 1: Build NM1 segment using payer name and ID
|
|
320
391
|
return "NM1*PR*2*{}*****PI*{}~".format(payer_name, payer_id)
|
|
321
392
|
|
|
322
|
-
def map_insurance_name_to_payer_id(insurance_name, config):
|
|
393
|
+
def map_insurance_name_to_payer_id(insurance_name, config, client):
|
|
323
394
|
"""
|
|
324
395
|
Maps insurance name to payer ID using the crosswalk configuration.
|
|
325
396
|
|
|
@@ -330,13 +401,15 @@ def map_insurance_name_to_payer_id(insurance_name, config):
|
|
|
330
401
|
Returns:
|
|
331
402
|
str: The payer ID corresponding to the insurance name.
|
|
332
403
|
"""
|
|
333
|
-
try:
|
|
334
|
-
#
|
|
335
|
-
MediBot_Crosswalk_Library.check_and_initialize_crosswalk(config)
|
|
336
|
-
|
|
337
|
-
# Load crosswalk configuration
|
|
404
|
+
try:
|
|
405
|
+
# Load crosswalk configuration // BUG This should already be passed in before we get here.
|
|
338
406
|
_, crosswalk = MediLink_ConfigLoader.load_configuration(None, config.get('crosswalkPath', 'crosswalk.json'))
|
|
339
407
|
|
|
408
|
+
# Ensure crosswalk is initialized and 'payer_id' key is available
|
|
409
|
+
if 'payer_id' not in crosswalk:
|
|
410
|
+
print("Crosswalk 'payer_id' not found. Please run MediBot_Preprocessor.py with the --update-crosswalk argument.")
|
|
411
|
+
exit() # BUG Halting the script execution here for now, should be handled in the preprocessor script.
|
|
412
|
+
|
|
340
413
|
# Load insurance data from MAINS to get insurance ID
|
|
341
414
|
insurance_to_id = load_insurance_data_from_mains(config)
|
|
342
415
|
|
|
@@ -345,6 +418,7 @@ def map_insurance_name_to_payer_id(insurance_name, config):
|
|
|
345
418
|
if medisoft_id is None:
|
|
346
419
|
error_message = "No Medisoft ID found for insurance name: {}. Consider checking MAINS directly.".format(insurance_name)
|
|
347
420
|
MediLink_ConfigLoader.log(error_message, config, level="ERROR")
|
|
421
|
+
# Asking for payer ID here is not the right approach.
|
|
348
422
|
raise ValueError(error_message)
|
|
349
423
|
|
|
350
424
|
# Convert medisoft_id to string to match the JSON data type
|
|
@@ -362,7 +436,7 @@ def map_insurance_name_to_payer_id(insurance_name, config):
|
|
|
362
436
|
error_message = "No payer ID found for Medisoft ID: {}".format(medisoft_id)
|
|
363
437
|
MediLink_ConfigLoader.log(error_message, config, level="ERROR")
|
|
364
438
|
print(error_message)
|
|
365
|
-
payer_id = handle_missing_payer_id(insurance_name, config)
|
|
439
|
+
payer_id = handle_missing_payer_id(insurance_name, config, crosswalk, client)
|
|
366
440
|
|
|
367
441
|
return payer_id
|
|
368
442
|
|
|
@@ -376,47 +450,6 @@ def map_insurance_name_to_payer_id(insurance_name, config):
|
|
|
376
450
|
MediLink_ConfigLoader.log(error_message, config, level="ERROR")
|
|
377
451
|
raise e
|
|
378
452
|
|
|
379
|
-
def handle_missing_payer_id(insurance_name, config):
|
|
380
|
-
"""
|
|
381
|
-
Handles cases where the payer ID is not found for a given Medisoft ID.
|
|
382
|
-
|
|
383
|
-
"""
|
|
384
|
-
print("Missing Payer ID for insurance name: {}".format(insurance_name))
|
|
385
|
-
MediLink_ConfigLoader.log("Missing Payer ID for insurance name: {}".format(insurance_name), config, level="WARNING")
|
|
386
|
-
|
|
387
|
-
# Prompt the user for manual intervention to input the payer ID
|
|
388
|
-
payer_id = prompt_user_for_payer_id(insurance_name)
|
|
389
|
-
|
|
390
|
-
if not payer_id:
|
|
391
|
-
message = "Unable to resolve missing Payer ID. Manual intervention is required."
|
|
392
|
-
MediLink_ConfigLoader.log(message, config, level="CRITICAL")
|
|
393
|
-
return None
|
|
394
|
-
|
|
395
|
-
# Resolve the payer ID to a standard insurance name via API
|
|
396
|
-
try:
|
|
397
|
-
# primary_endpoint=None should kick to the default in the api function.
|
|
398
|
-
standard_insurance_name = resolve_payer_name(payer_id, config, primary_endpoint=None, insurance_name=insurance_name, parsed_data={})
|
|
399
|
-
message = "Resolved to standard insurance name: {} for payer ID: {}".format(standard_insurance_name, payer_id)
|
|
400
|
-
print(message)
|
|
401
|
-
MediLink_ConfigLoader.log(message, config, level="INFO")
|
|
402
|
-
except Exception as e:
|
|
403
|
-
message = "Failed to resolve payer ID to standard insurance name: {}".format(e)
|
|
404
|
-
print(message)
|
|
405
|
-
MediLink_ConfigLoader.log(message, config, level="ERROR")
|
|
406
|
-
return None
|
|
407
|
-
|
|
408
|
-
# Ask for user confirmation
|
|
409
|
-
confirmation = input("Is the standard insurance name '{}' correct? (yes/no): ".format(standard_insurance_name)).strip().lower() or 'yes'
|
|
410
|
-
|
|
411
|
-
if confirmation in ['yes', 'y']:
|
|
412
|
-
# Update the crosswalk with the new payer ID and insurance name mapping
|
|
413
|
-
MediBot_Crosswalk_Library.update_crosswalk_with_new_payer_id(insurance_name, payer_id, config)
|
|
414
|
-
return payer_id
|
|
415
|
-
else:
|
|
416
|
-
print("User did not confirm the standard insurance name. Manual intervention is required.")
|
|
417
|
-
MediLink_ConfigLoader.log("User did not confirm the standard insurance name. Manual intervention is required.", config, level="CRITICAL")
|
|
418
|
-
return None
|
|
419
|
-
|
|
420
453
|
def create_nm1_payto_address_segments(config):
|
|
421
454
|
"""
|
|
422
455
|
Constructs the NM1 segment for the Pay-To Address, N3 for street address, and N4 for city, state, and ZIP.
|
|
@@ -627,7 +660,7 @@ def format_claim_number(chart_number, date_of_service):
|
|
|
627
660
|
return formatted_claim_number
|
|
628
661
|
|
|
629
662
|
# Constructs the CLM and related segments based on parsed data and configuration.
|
|
630
|
-
def create_clm_and_related_segments(parsed_data, config):
|
|
663
|
+
def create_clm_and_related_segments(parsed_data, config, crosswalk):
|
|
631
664
|
"""
|
|
632
665
|
Insert the claim information (2300 loop),
|
|
633
666
|
ensuring that details such as claim ID, total charge amount,and service date are included.
|
|
@@ -653,9 +686,23 @@ def create_clm_and_related_segments(parsed_data, config):
|
|
|
653
686
|
parsed_data['TOS']))
|
|
654
687
|
|
|
655
688
|
# HI - Health Care Diagnosis Code
|
|
656
|
-
#
|
|
657
|
-
|
|
658
|
-
|
|
689
|
+
# Hardcoding "ABK" for ICD-10 codes as they are the only ones used now.
|
|
690
|
+
medisoft_code = ''.join(filter(str.isalnum, parsed_data['DIAG']))
|
|
691
|
+
diagnosis_code = next((key for key, value in crosswalk.get('diagnosis_to_medisoft', {}).items() if value == medisoft_code), None)
|
|
692
|
+
|
|
693
|
+
if diagnosis_code is None:
|
|
694
|
+
error_message = "Diagnosis code is empty for chart number: {}. Please verify. Medisoft code is {}".format(chart_number, medisoft_code)
|
|
695
|
+
MediLink_ConfigLoader.log(error_message, config, level="CRITICAL")
|
|
696
|
+
print(error_message)
|
|
697
|
+
diagnosis_code = input("Enter the complete diagnosis code: ")
|
|
698
|
+
# Update the crosswalk dictionary with the new pairing of diagnosis_code and medisoft_code.
|
|
699
|
+
crosswalk['diagnosis_to_medisoft'][diagnosis_code] = medisoft_code
|
|
700
|
+
MediLink_ConfigLoader.log("Updated crosswalk with new diagnosis code: {}, for Medisoft code {}".format(diagnosis_code, medisoft_code), config, level="INFO")
|
|
701
|
+
# TODO This needs to actually save the .json though which right now I'd like to route through the dedicated function for updating the crosswalk.
|
|
702
|
+
# TODO This should have been a validation exercise upstream and not a last minute check like this.
|
|
703
|
+
|
|
704
|
+
cleaned_diagnosis_code = ''.join(char for char in diagnosis_code if char.isalnum())
|
|
705
|
+
segments.append("HI*ABK:{}~".format(cleaned_diagnosis_code))
|
|
659
706
|
|
|
660
707
|
# (2310C Loop) Service Facility Location NPI and Address Information
|
|
661
708
|
segments.extend(create_service_facility_location_npi_segment(config))
|
|
@@ -675,7 +722,10 @@ def create_clm_and_related_segments(parsed_data, config):
|
|
|
675
722
|
# DTP - Date
|
|
676
723
|
segments.append("DTP*472*D8*{}~".format(convert_date_format(parsed_data['DATE'])))
|
|
677
724
|
|
|
678
|
-
# Is there REF - Line Item Control Number missing here?
|
|
725
|
+
# Is there REF - Line Item Control Number missing here? Private insurance doesn't need it, but Medicare does?
|
|
726
|
+
# segments.append("REF*6R*1~") # REF01, Reference Identification Qualifier; REF02, Line Item Control Number.
|
|
727
|
+
# 6R - Provider Control Number (Number assigned by information provider company for tracking and billing purposes)
|
|
728
|
+
# 1 - Reference information as defined for a particular Transaction Set or as specified by the Reference Identification Qualifier
|
|
679
729
|
|
|
680
730
|
return segments
|
|
681
731
|
|
|
@@ -847,10 +897,17 @@ def winscp_validate_output_directory(output_directory):
|
|
|
847
897
|
|
|
848
898
|
def get_output_directory(config):
|
|
849
899
|
# Retrieve desired default output file path from config
|
|
850
|
-
output_directory = config.get('outputFilePath', '')
|
|
900
|
+
output_directory = config.get('outputFilePath', '').strip()
|
|
851
901
|
# BUG (Low SFTP) Add WinSCP validation because of the mishandling of spaces in paths. (This shouldn't need to exist.)
|
|
902
|
+
if not output_directory:
|
|
903
|
+
print("Output file path is not specified in the configuration.")
|
|
904
|
+
output_directory = input("Please enter a valid output directory path: ").strip()
|
|
905
|
+
|
|
906
|
+
# Validate the directory path (checks for spaces and existence)
|
|
852
907
|
output_directory = winscp_validate_output_directory(output_directory)
|
|
908
|
+
|
|
853
909
|
if not os.path.isdir(output_directory):
|
|
854
|
-
print("Output directory does not exist. Please check the configuration.")
|
|
910
|
+
print("Output directory does not exist or is not accessible. Please check the configuration.")
|
|
855
911
|
return None
|
|
912
|
+
|
|
856
913
|
return output_directory
|
|
@@ -1,15 +1,9 @@
|
|
|
1
1
|
# This script requires Python 3.11 and is to be used for intalling new API clients.
|
|
2
|
-
import os
|
|
3
|
-
import time
|
|
4
|
-
import subprocess
|
|
5
|
-
import shutil
|
|
6
|
-
import tempfile
|
|
2
|
+
import os, time, subprocess, shutil, tempfile, shlex, re
|
|
7
3
|
from pathlib import Path
|
|
8
4
|
from watchdog.observers import Observer
|
|
9
5
|
from watchdog.events import FileSystemEventHandler
|
|
10
6
|
from MediLink_API_v3 import ConfigLoader
|
|
11
|
-
import shlex
|
|
12
|
-
import re
|
|
13
7
|
|
|
14
8
|
class SwaggerHandler(FileSystemEventHandler):
|
|
15
9
|
def __init__(self, json_folder):
|