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
MediLink/MediLink_Down.py
CHANGED
|
@@ -1,138 +1,97 @@
|
|
|
1
1
|
# MediLink_Down.py
|
|
2
|
-
import os
|
|
3
|
-
import
|
|
4
|
-
import
|
|
5
|
-
import glob
|
|
6
|
-
import csv
|
|
7
|
-
from MediLink_Decoder import process_file
|
|
8
|
-
from MediLink_ConfigLoader import load_configuration, log
|
|
2
|
+
import os, shutil
|
|
3
|
+
from MediLink_Decoder import process_decoded_file, display_consolidated_records, write_records_to_csv
|
|
4
|
+
from MediLink_ConfigLoader import log, load_configuration
|
|
9
5
|
from MediLink_DataMgmt import operate_winscp
|
|
10
6
|
|
|
11
|
-
def
|
|
7
|
+
def handle_files(local_storage_path, downloaded_files):
|
|
8
|
+
"""
|
|
9
|
+
Moves downloaded files to the appropriate directory and translates them to CSV format.
|
|
10
|
+
"""
|
|
11
|
+
log("Starting to handle downloaded files.")
|
|
12
|
+
|
|
13
|
+
# Set the local response directory
|
|
12
14
|
local_response_directory = os.path.join(local_storage_path, "responses")
|
|
15
|
+
os.makedirs(local_response_directory, exist_ok=True)
|
|
13
16
|
|
|
14
|
-
|
|
15
|
-
|
|
17
|
+
# Supported file extensions
|
|
18
|
+
file_extensions = ['.era', '.277', '.277ibr', '.277ebr', '.dpt', '.ebt', '.ibt', '.txt']
|
|
16
19
|
|
|
17
|
-
|
|
18
|
-
file_extensions = ['.era', '.277', '.277ibr', '.277ebr', '.dpt', '.ebt', '.ibt'] # Extendable list of file extensions
|
|
20
|
+
files_moved = []
|
|
19
21
|
|
|
20
|
-
for
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
source_path = os.path.join(download_dir, file)
|
|
22
|
+
for file in downloaded_files:
|
|
23
|
+
if any(file.lower().endswith(ext) for ext in file_extensions): # Case-insensitive match
|
|
24
|
+
source_path = os.path.join(local_storage_path, file)
|
|
24
25
|
destination_path = os.path.join(local_response_directory, file)
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
26
|
+
|
|
27
|
+
try:
|
|
28
|
+
shutil.move(source_path, destination_path)
|
|
29
|
+
log("Moved '{}' to '{}'".format(file, local_response_directory))
|
|
30
|
+
files_moved.append(destination_path)
|
|
31
|
+
except Exception as e:
|
|
32
|
+
log("Error moving file '{}' to '{}': {}".format(file, destination_path, e), level="ERROR")
|
|
33
|
+
|
|
34
|
+
if not files_moved:
|
|
35
|
+
log("No files were moved. Ensure that files with supported extensions exist in the download directory.", level="WARNING")
|
|
36
|
+
|
|
37
|
+
# Translate the files
|
|
38
|
+
consolidated_records, translated_files = translate_files(files_moved, local_response_directory)
|
|
39
|
+
|
|
40
|
+
return consolidated_records, translated_files
|
|
37
41
|
|
|
38
42
|
def translate_files(files, output_directory):
|
|
43
|
+
"""
|
|
44
|
+
Translates given files into CSV format and returns the list of translated files and consolidated records.
|
|
45
|
+
"""
|
|
46
|
+
log("Translating files: {}".format(files), level="DEBUG")
|
|
47
|
+
|
|
48
|
+
if not files:
|
|
49
|
+
log("No files provided for translation. Exiting translate_files.", level="WARNING")
|
|
50
|
+
return [], []
|
|
51
|
+
|
|
39
52
|
translated_files = []
|
|
40
53
|
consolidated_records = []
|
|
41
|
-
|
|
54
|
+
|
|
55
|
+
# Supported file extensions with selector
|
|
56
|
+
file_type_selector = {
|
|
57
|
+
'.era': False,
|
|
58
|
+
'.277': False,
|
|
59
|
+
'.277ibr': False,
|
|
60
|
+
'.277ebr': False,
|
|
61
|
+
'.dpt': False,
|
|
62
|
+
'.ebt': True, # Only EBT files are processed
|
|
63
|
+
'.ibt': False,
|
|
64
|
+
'.txt': False
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
file_counts = {ext: 0 for ext in file_type_selector.keys()}
|
|
42
68
|
|
|
43
69
|
for file in files:
|
|
44
70
|
ext = os.path.splitext(file)[1]
|
|
45
|
-
if ext
|
|
71
|
+
if file_type_selector.get(ext, False): # Check if the file type is selected
|
|
46
72
|
file_counts[ext] += 1
|
|
47
73
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
74
|
+
try:
|
|
75
|
+
records = process_decoded_file(os.path.join(output_directory, file), output_directory, return_records=True)
|
|
76
|
+
consolidated_records.extend(records)
|
|
77
|
+
csv_file_path = os.path.join(output_directory, os.path.basename(file) + '_decoded.csv')
|
|
78
|
+
translated_files.append(csv_file_path)
|
|
79
|
+
log("Translated file to CSV: {}".format(csv_file_path), level="INFO")
|
|
80
|
+
except ValueError:
|
|
81
|
+
log("Unsupported file type: {}".format(file), level="WARNING")
|
|
82
|
+
except Exception as e:
|
|
83
|
+
log("Error processing file {}: {}".format(file, e), level="ERROR")
|
|
84
|
+
|
|
85
|
+
log("Detected and processed file counts by type:")
|
|
60
86
|
for ext, count in file_counts.items():
|
|
61
|
-
|
|
87
|
+
log("{}: {} files detected".format(ext, count), level="INFO")
|
|
62
88
|
|
|
63
89
|
return consolidated_records, translated_files
|
|
64
90
|
|
|
65
|
-
def display_translated_files(translated_files):
|
|
66
|
-
print("\nTranslated Files Summary:")
|
|
67
|
-
for file in translated_files:
|
|
68
|
-
print(" - {}".format(file))
|
|
69
|
-
|
|
70
|
-
def main():
|
|
71
|
-
parser = argparse.ArgumentParser(description="Process files and convert them to CSV format.")
|
|
72
|
-
parser.add_argument('--config_path', type=str, help='Path to the configuration JSON file', default="json/config.json")
|
|
73
|
-
parser.add_argument('--file_path_pattern', type=str, help='Path pattern or directory for files to process.', default=None)
|
|
74
|
-
args = parser.parse_args()
|
|
75
|
-
|
|
76
|
-
config, _ = load_configuration(args.config_path)
|
|
77
|
-
local_storage_path = config['MediLink_Config']['local_storage_path']
|
|
78
|
-
output_directory = os.path.join(local_storage_path, "translated_csvs")
|
|
79
|
-
|
|
80
|
-
# If a file path pattern is provided, process those files directly
|
|
81
|
-
if args.file_path_pattern:
|
|
82
|
-
files = find_files(args.file_path_pattern)
|
|
83
|
-
if files:
|
|
84
|
-
files_str = ', '.join(files)
|
|
85
|
-
log("Translating files: {}".format(files_str), level="INFO")
|
|
86
|
-
consolidated_records, translated_files = translate_files(files, output_directory)
|
|
87
|
-
log("Translation completed.", level="INFO")
|
|
88
|
-
if consolidated_records:
|
|
89
|
-
display_consolidated_records(consolidated_records)
|
|
90
|
-
prompt_csv_export(consolidated_records, output_directory)
|
|
91
|
-
return
|
|
92
|
-
else:
|
|
93
|
-
log("No files found matching: {}".format(args.file_path_pattern), level="WARNING")
|
|
94
|
-
return
|
|
95
|
-
|
|
96
|
-
# Handle downloading files via WinSCP
|
|
97
|
-
endpoint_key = 'AVAILITY'
|
|
98
|
-
if endpoint_key not in config['MediLink_Config']['endpoints']:
|
|
99
|
-
log("Endpoint '{}' not found in configuration. Using default 'AVAILITY'.".format(endpoint_key), level="WARNING")
|
|
100
|
-
endpoint_key = 'AVAILITY'
|
|
101
|
-
|
|
102
|
-
endpoint_configs = [config['MediLink_Config']['endpoints'][key] for key in config['MediLink_Config']['endpoints']]
|
|
103
|
-
downloaded_files = []
|
|
104
|
-
|
|
105
|
-
for endpoint_config in endpoint_configs:
|
|
106
|
-
downloaded_files += operate_winscp("download", None, endpoint_config, local_storage_path, config)
|
|
107
|
-
|
|
108
|
-
move_downloaded_files(local_storage_path, config)
|
|
109
|
-
|
|
110
|
-
consolidated_records, translated_files = translate_files(downloaded_files, output_directory)
|
|
111
|
-
if consolidated_records:
|
|
112
|
-
display_consolidated_records(consolidated_records)
|
|
113
|
-
prompt_csv_export(consolidated_records, output_directory)
|
|
114
|
-
|
|
115
|
-
def display_consolidated_records(records):
|
|
116
|
-
# Define the new fieldnames and their respective widths
|
|
117
|
-
new_fieldnames = ['Claim #', 'Status', 'Patient', 'Proc.', 'Serv.', 'Allowed', 'Paid', 'Pt Resp', 'Charged']
|
|
118
|
-
col_widths = {field: len(field) for field in new_fieldnames}
|
|
119
|
-
|
|
120
|
-
# Update column widths based on records
|
|
121
|
-
for record in records:
|
|
122
|
-
for field in new_fieldnames:
|
|
123
|
-
col_widths[field] = max(col_widths[field], len(str(record.get(field, ''))))
|
|
124
|
-
|
|
125
|
-
# Create table header
|
|
126
|
-
header = " | ".join("{:<{}}".format(field, col_widths[field]) for field in new_fieldnames)
|
|
127
|
-
print(header)
|
|
128
|
-
print("-" * len(header))
|
|
129
|
-
|
|
130
|
-
# Create table rows
|
|
131
|
-
for record in records:
|
|
132
|
-
row = " | ".join("{:<{}}".format(str(record.get(field, '')), col_widths[field]) for field in new_fieldnames)
|
|
133
|
-
print(row)
|
|
134
|
-
|
|
135
91
|
def prompt_csv_export(records, output_directory):
|
|
92
|
+
"""
|
|
93
|
+
Prompts the user to export consolidated records to a CSV file.
|
|
94
|
+
"""
|
|
136
95
|
if records:
|
|
137
96
|
user_input = input("Do you want to export the consolidated records to a CSV file? (y/n): ")
|
|
138
97
|
if user_input.lower() == 'y':
|
|
@@ -142,13 +101,48 @@ def prompt_csv_export(records, output_directory):
|
|
|
142
101
|
else:
|
|
143
102
|
log("CSV export skipped by user.", level="INFO")
|
|
144
103
|
|
|
145
|
-
def
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
104
|
+
def main(desired_endpoint=None):
|
|
105
|
+
"""
|
|
106
|
+
Main function for running MediLink_Down as a standalone script.
|
|
107
|
+
Simplified to handle only CLI operations and delegate the actual processing to the high-level function.
|
|
108
|
+
"""
|
|
109
|
+
log("Running MediLink_Down.main with desired_endpoint={}".format(desired_endpoint))
|
|
110
|
+
|
|
111
|
+
if not desired_endpoint:
|
|
112
|
+
log("No specific endpoint provided. Aborting operation.", level="ERROR")
|
|
113
|
+
return None, None
|
|
114
|
+
|
|
115
|
+
try:
|
|
116
|
+
config, _ = load_configuration()
|
|
117
|
+
endpoint_config = config['MediLink_Config']['endpoints'].get(desired_endpoint)
|
|
118
|
+
if not endpoint_config or 'remote_directory_down' not in endpoint_config:
|
|
119
|
+
log("Configuration for endpoint '{}' is incomplete or missing 'remote_directory_down'.".format(desired_endpoint), level="ERROR")
|
|
120
|
+
return None, None
|
|
121
|
+
|
|
122
|
+
local_storage_path = config['MediLink_Config']['local_storage_path']
|
|
123
|
+
log("Local storage path set to {}".format(local_storage_path))
|
|
124
|
+
|
|
125
|
+
downloaded_files = operate_winscp("download", None, endpoint_config, local_storage_path, config)
|
|
126
|
+
|
|
127
|
+
if downloaded_files:
|
|
128
|
+
log("From main(), WinSCP Downloaded the following files: \n{}".format(downloaded_files))
|
|
129
|
+
consolidated_records, translated_files = handle_files(local_storage_path, downloaded_files)
|
|
130
|
+
|
|
131
|
+
# Convert UnifiedRecord instances to dictionaries before displaying
|
|
132
|
+
dict_consolidated_records = [record.to_dict() for record in consolidated_records]
|
|
133
|
+
display_consolidated_records(dict_consolidated_records)
|
|
134
|
+
|
|
135
|
+
# Prompt for CSV export
|
|
136
|
+
prompt_csv_export(consolidated_records, local_storage_path)
|
|
137
|
+
|
|
138
|
+
return consolidated_records, translated_files
|
|
139
|
+
else:
|
|
140
|
+
log("No files were downloaded for endpoint: {}. Exiting...".format(desired_endpoint), level="WARNING")
|
|
141
|
+
return None, None
|
|
142
|
+
|
|
143
|
+
except Exception as e:
|
|
144
|
+
log("An error occurred in MediLink_Down.main: {}".format(e), level="ERROR")
|
|
145
|
+
return None, None
|
|
152
146
|
|
|
153
147
|
if __name__ == "__main__":
|
|
154
|
-
main()
|
|
148
|
+
main()
|
MediLink/MediLink_Gmail.py
CHANGED
|
@@ -1,17 +1,8 @@
|
|
|
1
|
-
|
|
2
|
-
import os
|
|
3
|
-
import subprocess
|
|
4
|
-
import time
|
|
5
|
-
import webbrowser
|
|
1
|
+
# MediLink_Gmail.py
|
|
2
|
+
import sys, os, subprocess, time, webbrowser, requests, json, ssl, signal
|
|
6
3
|
from MediLink_ConfigLoader import log, load_configuration
|
|
7
|
-
|
|
8
|
-
import requests
|
|
9
|
-
import json
|
|
10
4
|
from http.server import BaseHTTPRequestHandler, HTTPServer
|
|
11
|
-
import ssl
|
|
12
|
-
import signal
|
|
13
5
|
from threading import Thread, Event
|
|
14
|
-
|
|
15
6
|
import platform
|
|
16
7
|
|
|
17
8
|
config, _ = load_configuration()
|
MediLink/MediLink_Parser.py
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
# MediLink_Parser.py
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
import re
|
|
4
|
+
|
|
5
|
+
def parse_era_content(content, debug=False):
|
|
4
6
|
extracted_data = []
|
|
5
7
|
normalized_content = content.replace('~\n', '~')
|
|
6
8
|
lines = normalized_content.split('~')
|
|
@@ -74,13 +76,14 @@ def parse_era_content(content):
|
|
|
74
76
|
})
|
|
75
77
|
extracted_data.append(record)
|
|
76
78
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
79
|
+
if debug:
|
|
80
|
+
print("Parsed ERA Content:")
|
|
81
|
+
for data in extracted_data:
|
|
82
|
+
print(data)
|
|
80
83
|
|
|
81
84
|
return extracted_data
|
|
82
85
|
|
|
83
|
-
def parse_277_content(content):
|
|
86
|
+
def parse_277_content(content, debug=False):
|
|
84
87
|
segments = content.split('~')
|
|
85
88
|
records = []
|
|
86
89
|
current_record = {}
|
|
@@ -115,19 +118,20 @@ def parse_277_content(content):
|
|
|
115
118
|
if current_record:
|
|
116
119
|
records.append(current_record)
|
|
117
120
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
+
if debug:
|
|
122
|
+
print("Parsed 277 Content:")
|
|
123
|
+
for record in records:
|
|
124
|
+
print(record)
|
|
121
125
|
|
|
122
126
|
return records
|
|
123
127
|
|
|
124
|
-
def parse_277IBR_content(content):
|
|
125
|
-
return parse_277_content(content)
|
|
128
|
+
def parse_277IBR_content(content, debug=False):
|
|
129
|
+
return parse_277_content(content, debug)
|
|
126
130
|
|
|
127
|
-
def parse_277EBR_content(content):
|
|
128
|
-
return parse_277_content(content)
|
|
131
|
+
def parse_277EBR_content(content, debug=False):
|
|
132
|
+
return parse_277_content(content, debug)
|
|
129
133
|
|
|
130
|
-
def parse_dpt_content(content):
|
|
134
|
+
def parse_dpt_content(content, debug=False):
|
|
131
135
|
extracted_data = []
|
|
132
136
|
lines = content.splitlines()
|
|
133
137
|
record = {}
|
|
@@ -143,34 +147,56 @@ def parse_dpt_content(content):
|
|
|
143
147
|
if record:
|
|
144
148
|
extracted_data.append(record)
|
|
145
149
|
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
150
|
+
if debug:
|
|
151
|
+
print("Parsed DPT Content:")
|
|
152
|
+
for data in extracted_data:
|
|
153
|
+
print(data)
|
|
149
154
|
|
|
150
155
|
return extracted_data
|
|
151
156
|
|
|
152
|
-
def parse_ebt_content(content):
|
|
153
|
-
extracted_data = []
|
|
154
|
-
lines = content.splitlines()
|
|
155
|
-
record = {}
|
|
157
|
+
def parse_ebt_content(content, debug=False):
|
|
158
|
+
extracted_data = [] # List to hold all extracted records
|
|
159
|
+
lines = content.splitlines() # Split the content into individual lines
|
|
160
|
+
record = {} # Dictionary to hold the current record being processed
|
|
161
|
+
|
|
162
|
+
# Regular expression pattern to match key-value pairs in the format "Key: Value"
|
|
163
|
+
key_value_pattern = re.compile(r'([^:]+):\s*(.+?)(?=\s{2,}[^:]+?:|$)')
|
|
164
|
+
|
|
156
165
|
for line in lines:
|
|
166
|
+
# Check for the start of a new record based on the presence of 'Patient Name'
|
|
157
167
|
if 'Patient Name:' in line and record:
|
|
158
|
-
|
|
159
|
-
record
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
168
|
+
ebt_post_processor(record) # Process the current record before adding it to the list
|
|
169
|
+
extracted_data.append(record) # Add the completed record to the list
|
|
170
|
+
record = {} # Reset the record for the next entry
|
|
171
|
+
|
|
172
|
+
# Find all key-value pairs in the current line
|
|
173
|
+
matches = key_value_pattern.findall(line)
|
|
174
|
+
for key, value in matches:
|
|
175
|
+
key = key.strip() # Remove leading/trailing whitespace from the key
|
|
176
|
+
value = value.strip() # Remove leading/trailing whitespace from the value
|
|
177
|
+
record[key] = value # Add the key-value pair to the current record
|
|
178
|
+
|
|
179
|
+
# Process and add the last record if it exists
|
|
164
180
|
if record:
|
|
165
|
-
|
|
181
|
+
ebt_post_processor(record) # Final processing of the last record
|
|
182
|
+
extracted_data.append(record) # Add the last record to the list
|
|
166
183
|
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
print(
|
|
184
|
+
# Debug output to show parsed data if debugging is enabled
|
|
185
|
+
if debug:
|
|
186
|
+
print("Parsed EBT Content:")
|
|
187
|
+
for data in extracted_data:
|
|
188
|
+
print(data)
|
|
170
189
|
|
|
171
|
-
return extracted_data
|
|
190
|
+
return extracted_data # Return the list of extracted records
|
|
191
|
+
|
|
192
|
+
def ebt_post_processor(record):
|
|
193
|
+
# Process the 'Message Initiator' field to separate it from 'Message Type'
|
|
194
|
+
if 'Message Initiator' in record and 'Message Type:' in record['Message Initiator']:
|
|
195
|
+
parts = record['Message Initiator'].split('Message Type:') # Split the string into parts
|
|
196
|
+
record['Message Initiator'] = parts[0].strip() # Clean up the 'Message Initiator'
|
|
197
|
+
record['Message Type'] = parts[1].strip() # Clean up the 'Message Type'
|
|
172
198
|
|
|
173
|
-
def parse_ibt_content(content):
|
|
199
|
+
def parse_ibt_content(content, debug=False):
|
|
174
200
|
extracted_data = []
|
|
175
201
|
lines = content.splitlines()
|
|
176
202
|
record = {}
|
|
@@ -186,8 +212,9 @@ def parse_ibt_content(content):
|
|
|
186
212
|
if record:
|
|
187
213
|
extracted_data.append(record)
|
|
188
214
|
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
215
|
+
if debug:
|
|
216
|
+
print("Parsed IBT Content:")
|
|
217
|
+
for data in extracted_data:
|
|
218
|
+
print(data)
|
|
192
219
|
|
|
193
|
-
return extracted_data
|
|
220
|
+
return extracted_data
|
MediLink/MediLink_UI.py
CHANGED
|
@@ -1,6 +1,15 @@
|
|
|
1
|
+
# MediLink_UI.py
|
|
1
2
|
from datetime import datetime
|
|
2
|
-
import os
|
|
3
|
-
|
|
3
|
+
import os, sys
|
|
4
|
+
|
|
5
|
+
project_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))
|
|
6
|
+
if project_dir not in sys.path:
|
|
7
|
+
sys.path.append(project_dir)
|
|
8
|
+
|
|
9
|
+
try:
|
|
10
|
+
import MediLink_ConfigLoader
|
|
11
|
+
except ImportError:
|
|
12
|
+
from MediLink import MediLink_ConfigLoader
|
|
4
13
|
|
|
5
14
|
def display_welcome():
|
|
6
15
|
print("\n" + "-" * 60)
|
|
@@ -98,13 +107,6 @@ def display_patient_summaries(detailed_patient_data):
|
|
|
98
107
|
print("Summary at index {} is missing key: {}".format(index, e))
|
|
99
108
|
print() # add blank line for improved readability.
|
|
100
109
|
|
|
101
|
-
def ask_for_proceeding_with_endpoints():
|
|
102
|
-
"""
|
|
103
|
-
Asks the user if they want to proceed with all suggested endpoints.
|
|
104
|
-
"""
|
|
105
|
-
proceed = input("Do you want to proceed with all suggested endpoints? (Y/N): ").strip().lower()
|
|
106
|
-
return proceed == 'y'
|
|
107
|
-
|
|
108
110
|
def display_file_summary(index, summary):
|
|
109
111
|
# Ensure surgery_date is converted to a datetime object
|
|
110
112
|
surgery_date = datetime.strptime(summary['surgery_date'], "%m-%d-%y")
|
|
@@ -129,26 +131,37 @@ def display_file_summary(index, summary):
|
|
|
129
131
|
insurance_type[:2],
|
|
130
132
|
summary['suggested_endpoint'][:20])
|
|
131
133
|
)
|
|
132
|
-
|
|
134
|
+
|
|
133
135
|
def user_select_files(file_list):
|
|
134
|
-
|
|
135
|
-
|
|
136
|
+
# Sort files by creation time in descending order
|
|
137
|
+
file_list = sorted(file_list, key=os.path.getctime, reverse=True)[:10] # Limit to max 10 files
|
|
136
138
|
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
# Sort the files by creation time in descending order
|
|
141
|
-
file_list = sorted(file_list, key=os.path.getctime, reverse=True)
|
|
142
|
-
|
|
143
|
-
print("Select claim files to submit from the following list:")
|
|
139
|
+
print("\nSelect the Z-form files to submit from the following list:\n")
|
|
140
|
+
|
|
141
|
+
formatted_files = []
|
|
144
142
|
for i, file in enumerate(file_list):
|
|
145
|
-
|
|
143
|
+
basename = os.path.basename(file)
|
|
144
|
+
parts = basename.split('_')
|
|
145
|
+
|
|
146
|
+
# Try to parse the timestamp from the filename
|
|
147
|
+
if len(parts) > 2:
|
|
148
|
+
try:
|
|
149
|
+
timestamp_str = parts[1] + parts[2].split('.')[0]
|
|
150
|
+
timestamp = datetime.strptime(timestamp_str, '%Y%m%d%H%M%S')
|
|
151
|
+
formatted_date = timestamp.strftime('%m/%d %I:%M %p') # Changed to 12HR format with AM/PM
|
|
152
|
+
except ValueError:
|
|
153
|
+
formatted_date = basename # Fallback to original filename if parsing fails
|
|
154
|
+
else:
|
|
155
|
+
formatted_date = basename # Fallback to original filename if no timestamp
|
|
156
|
+
|
|
157
|
+
formatted_files.append((formatted_date, file))
|
|
158
|
+
print("{}: {}".format(i + 1, formatted_date))
|
|
146
159
|
|
|
147
160
|
selected_indices = input("\nEnter the numbers of the files to process, separated by commas\n(or press Enter to select all): ")
|
|
148
161
|
if not selected_indices:
|
|
149
|
-
return
|
|
162
|
+
return [file for _, file in formatted_files]
|
|
150
163
|
|
|
151
164
|
selected_indices = [int(i.strip()) - 1 for i in selected_indices.split(',')]
|
|
152
|
-
selected_files = [
|
|
165
|
+
selected_files = [formatted_files[i][1] for i in selected_indices]
|
|
153
166
|
|
|
154
|
-
return selected_files
|
|
167
|
+
return selected_files
|