medicafe 0.240419.2__py3-none-any.whl → 0.240613.0__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 +174 -38
- MediBot/MediBot.py +80 -77
- MediBot/MediBot_Charges.py +0 -28
- MediBot/MediBot_Crosswalk_Library.py +281 -0
- MediBot/MediBot_Post.py +0 -0
- MediBot/MediBot_Preprocessor.py +138 -211
- MediBot/MediBot_Preprocessor_lib.py +496 -0
- MediBot/MediBot_UI.py +80 -35
- MediBot/MediBot_dataformat_library.py +79 -35
- MediBot/MediBot_docx_decoder.py +295 -0
- MediBot/update_medicafe.py +46 -8
- MediLink/MediLink.py +207 -108
- MediLink/MediLink_837p_encoder.py +299 -214
- MediLink/MediLink_837p_encoder_library.py +445 -245
- MediLink/MediLink_API_v2.py +174 -0
- MediLink/MediLink_APIs.py +139 -0
- MediLink/MediLink_ConfigLoader.py +44 -32
- MediLink/MediLink_DataMgmt.py +297 -89
- MediLink/MediLink_Decoder.py +63 -0
- MediLink/MediLink_Down.py +73 -102
- MediLink/MediLink_ERA_decoder.py +4 -4
- MediLink/MediLink_Gmail.py +479 -4
- MediLink/MediLink_Mailer.py +0 -0
- MediLink/MediLink_Parser.py +111 -0
- MediLink/MediLink_Scan.py +0 -0
- MediLink/MediLink_Scheduler.py +2 -131
- MediLink/MediLink_StatusCheck.py +0 -4
- MediLink/MediLink_UI.py +87 -27
- MediLink/MediLink_Up.py +301 -45
- MediLink/MediLink_batch.bat +1 -1
- MediLink/test.py +74 -0
- medicafe-0.240613.0.dist-info/METADATA +55 -0
- medicafe-0.240613.0.dist-info/RECORD +43 -0
- {medicafe-0.240419.2.dist-info → medicafe-0.240613.0.dist-info}/WHEEL +5 -5
- medicafe-0.240419.2.dist-info/METADATA +0 -19
- medicafe-0.240419.2.dist-info/RECORD +0 -32
- {medicafe-0.240419.2.dist-info → medicafe-0.240613.0.dist-info}/LICENSE +0 -0
- {medicafe-0.240419.2.dist-info → medicafe-0.240613.0.dist-info}/top_level.txt +0 -0
MediLink/MediLink.py
CHANGED
|
@@ -1,38 +1,51 @@
|
|
|
1
1
|
import os
|
|
2
|
-
import MediLink_ConfigLoader
|
|
3
|
-
import MediLink_837p_encoder
|
|
4
|
-
import logging
|
|
5
2
|
import MediLink_Down
|
|
6
3
|
import MediLink_Up
|
|
4
|
+
import MediLink_ConfigLoader
|
|
5
|
+
import MediLink_837p_encoder
|
|
6
|
+
import MediLink_DataMgmt
|
|
7
7
|
|
|
8
8
|
# For UI Functions
|
|
9
9
|
import os
|
|
10
10
|
import MediLink_UI # Import UI module for handling all user interfaces
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
"""
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
11
|
+
from tqdm import tqdm
|
|
12
|
+
|
|
13
|
+
# Add parent directory of the project to the Python path
|
|
14
|
+
import sys
|
|
15
|
+
project_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))
|
|
16
|
+
sys.path.append(project_dir)
|
|
17
|
+
|
|
18
|
+
from MediBot import MediBot_Preprocessor_lib
|
|
19
|
+
load_insurance_data_from_mains = MediBot_Preprocessor_lib.load_insurance_data_from_mains
|
|
20
|
+
from MediBot import MediBot_Crosswalk_Library
|
|
21
|
+
|
|
22
|
+
# Define insurance options with codes and descriptions.
|
|
23
|
+
# TODO This needs to move to the config file
|
|
24
|
+
insurance_options = {
|
|
25
|
+
"11": "Other Non-Federal Programs",
|
|
26
|
+
"12": "Preferred Provider Organization (PPO)",
|
|
27
|
+
"13": "Point of Service (POS)",
|
|
28
|
+
"14": "Exclusive Provider Organization (EPO)",
|
|
29
|
+
"15": "Indemnity Insurance",
|
|
30
|
+
"16": "Health Maintenance Organization (HMO) Medicare Risk",
|
|
31
|
+
"17": "Dental Maintenance Organization",
|
|
32
|
+
"AM": "Automobile Medical",
|
|
33
|
+
"BL": "Blue Cross/Blue Shield",
|
|
34
|
+
"CH": "Champus",
|
|
35
|
+
"CI": "Commercial Insurance Co.",
|
|
36
|
+
"DS": "Disability",
|
|
37
|
+
"FI": "Federal Employees Program",
|
|
38
|
+
"HM": "Health Maintenance Organization",
|
|
39
|
+
"LM": "Liability Medical",
|
|
40
|
+
"MA": "Medicare Part A",
|
|
41
|
+
"MB": "Medicare Part B",
|
|
42
|
+
"MC": "Medicaid",
|
|
43
|
+
"OF": "Other Federal Program",
|
|
44
|
+
"TV": "Title V",
|
|
45
|
+
"VA": "Veterans Affairs Plan",
|
|
46
|
+
"WC": "Workers Compensation Health Claim",
|
|
47
|
+
"ZZ": "Mutually Defined"
|
|
48
|
+
}
|
|
36
49
|
|
|
37
50
|
def detect_and_display_file_summaries(directory_path, config, crosswalk):
|
|
38
51
|
"""
|
|
@@ -41,35 +54,61 @@ def detect_and_display_file_summaries(directory_path, config, crosswalk):
|
|
|
41
54
|
|
|
42
55
|
:param directory_path: Path to the directory containing files to be detected.
|
|
43
56
|
:param config: Configuration settings loaded from a JSON file.
|
|
57
|
+
:param crosswalk: Crosswalk data for mapping purposes.
|
|
44
58
|
:return: A tuple containing a list of new file paths and the detailed patient data.
|
|
45
59
|
"""
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
60
|
+
try:
|
|
61
|
+
new_files, file_flagged = MediLink_DataMgmt.detect_new_files(directory_path)
|
|
62
|
+
if not new_files:
|
|
63
|
+
print("No new claims detected. Check Medisoft claims output.")
|
|
64
|
+
MediLink_ConfigLoader.log("No new claims detected. Check Medisoft claims output.")
|
|
65
|
+
return False, []
|
|
66
|
+
|
|
67
|
+
if not file_flagged:
|
|
68
|
+
selected_files = MediLink_UI.user_select_files(new_files)
|
|
69
|
+
else:
|
|
70
|
+
# Extract the newest single latest file from the list
|
|
71
|
+
selected_files = [max(new_files, key=os.path.getctime)]
|
|
72
|
+
|
|
73
|
+
detailed_patient_data = [] # Initialize list for detailed patient data
|
|
74
|
+
for file_path in selected_files:
|
|
75
|
+
detailed_data = extract_and_suggest_endpoint(file_path, config, crosswalk)
|
|
76
|
+
detailed_patient_data.extend(detailed_data) # Accumulate detailed data for processing
|
|
77
|
+
|
|
78
|
+
# Enrich the detailed patient data with insurance type
|
|
79
|
+
detailed_patient_data = enrich_with_insurance_type(detailed_patient_data, insurance_options)
|
|
80
|
+
|
|
81
|
+
# Display summaries and provide an option for bulk edit
|
|
82
|
+
MediLink_UI.display_patient_summaries(detailed_patient_data)
|
|
83
|
+
|
|
84
|
+
# Return the list of new files and the enriched detailed patient data
|
|
85
|
+
return selected_files, detailed_patient_data
|
|
86
|
+
except Exception as e:
|
|
87
|
+
MediLink_ConfigLoader.log("Error in detect_and_display_file_summaries: {}".format(e))
|
|
49
88
|
return False, []
|
|
50
89
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
detailed_patient_data.extend(detailed_data) # Accumulate detailed data for processing
|
|
90
|
+
def enrich_with_insurance_type(detailed_patient_data, patient_insurance_type_mapping=None):
|
|
91
|
+
"""
|
|
92
|
+
Enriches the detailed patient data with insurance type based on patient ID.
|
|
55
93
|
|
|
56
|
-
|
|
57
|
-
|
|
94
|
+
Parameters:
|
|
95
|
+
- detailed_patient_data: List of dictionaries containing detailed patient data.
|
|
96
|
+
- patient_insurance_mapping: Dictionary mapping patient IDs to their insurance types.
|
|
58
97
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
Scans the specified directory for new files with a given extension.
|
|
98
|
+
Returns:
|
|
99
|
+
- Enriched detailed patient data with insurance type added.
|
|
62
100
|
|
|
63
|
-
:
|
|
64
|
-
:param file_extension: Extension of the files to detect. Defaults to '.csv'.
|
|
65
|
-
:return: A list of paths to new files detected in the directory.
|
|
101
|
+
TODO: Implement a function to provide `patient_insurance_mapping` from a reliable source.
|
|
66
102
|
"""
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
103
|
+
if patient_insurance_type_mapping is None:
|
|
104
|
+
MediLink_ConfigLoader.log("No Patient:Insurance-Type mapping available.")
|
|
105
|
+
patient_insurance_type_mapping = {}
|
|
106
|
+
|
|
107
|
+
for data in detailed_patient_data:
|
|
108
|
+
patient_id = data.get('PATID') # I think this is the right name?
|
|
109
|
+
insurance_type = patient_insurance_type_mapping.get(patient_id, '12') # Default to '12' (PPO)
|
|
110
|
+
data['insurance_type'] = insurance_type
|
|
111
|
+
return detailed_patient_data
|
|
73
112
|
|
|
74
113
|
def extract_and_suggest_endpoint(file_path, config, crosswalk):
|
|
75
114
|
"""
|
|
@@ -88,15 +127,42 @@ def extract_and_suggest_endpoint(file_path, config, crosswalk):
|
|
|
88
127
|
"""
|
|
89
128
|
detailed_patient_data = []
|
|
90
129
|
|
|
91
|
-
|
|
92
|
-
|
|
130
|
+
# Load insurance data from MAINS to create a mapping from insurance names to their respective IDs
|
|
131
|
+
insurance_to_id = load_insurance_data_from_mains(config)
|
|
132
|
+
MediLink_ConfigLoader.log("Insurance data loaded from MAINS. {} insurance providers found.".format(len(insurance_to_id)))
|
|
133
|
+
|
|
134
|
+
for personal_info, insurance_info, service_info, service_info_2, service_info_3 in MediLink_DataMgmt.read_fixed_width_data(file_path):
|
|
135
|
+
parsed_data = MediLink_DataMgmt.parse_fixed_width_data(personal_info, insurance_info, service_info, service_info_2, service_info_3, config.get('MediLink_Config', config))
|
|
93
136
|
|
|
94
137
|
primary_insurance = parsed_data.get('INAME')
|
|
95
138
|
|
|
96
|
-
#
|
|
97
|
-
|
|
139
|
+
# Retrieve the insurance ID associated with the primary insurance
|
|
140
|
+
insurance_id = insurance_to_id.get(primary_insurance)
|
|
141
|
+
MediLink_ConfigLoader.log("Primary insurance ID retrieved for '{}': {}".format(primary_insurance, insurance_id))
|
|
142
|
+
|
|
143
|
+
# Use insurance ID to retrieve the payer ID(s) associated with the insurance
|
|
144
|
+
payer_ids = []
|
|
145
|
+
if insurance_id:
|
|
146
|
+
for payer_id, payer_data in crosswalk.get('payer_id', {}).items():
|
|
147
|
+
medisoft_ids = [str(id) for id in payer_data.get('medisoft_id', [])]
|
|
148
|
+
# MediLink_ConfigLoader.log("Payer ID: {}, Medisoft IDs: {}".format(payer_id, medisoft_ids))
|
|
149
|
+
if str(insurance_id) in medisoft_ids:
|
|
150
|
+
payer_ids.append(payer_id)
|
|
151
|
+
if payer_ids:
|
|
152
|
+
MediLink_ConfigLoader.log("Payer IDs retrieved for insurance '{}': {}".format(primary_insurance, payer_ids))
|
|
153
|
+
else:
|
|
154
|
+
MediLink_ConfigLoader.log("No payer IDs found for insurance '{}'".format(primary_insurance))
|
|
98
155
|
|
|
99
|
-
#
|
|
156
|
+
# Find the suggested endpoint from the crosswalk based on the payer IDs
|
|
157
|
+
suggested_endpoint = 'AVAILITY' # Default endpoint if no matching payer IDs found
|
|
158
|
+
if payer_ids:
|
|
159
|
+
payer_id = payer_ids[0] # Select the first payer ID
|
|
160
|
+
suggested_endpoint = crosswalk['payer_id'].get(payer_id, {}).get('endpoint', 'AVAILITY')
|
|
161
|
+
MediLink_ConfigLoader.log("Suggested endpoint for payer ID '{}': {}".format(payer_id, suggested_endpoint))
|
|
162
|
+
else:
|
|
163
|
+
MediLink_ConfigLoader.log("No suggested endpoint found for payer IDs: {}".format(payer_ids))
|
|
164
|
+
|
|
165
|
+
# Enrich detailed patient data with additional information and suggested endpoint
|
|
100
166
|
detailed_data = parsed_data.copy() # Copy parsed_data to avoid modifying the original dictionary
|
|
101
167
|
detailed_data.update({
|
|
102
168
|
'file_path': file_path,
|
|
@@ -112,42 +178,53 @@ def extract_and_suggest_endpoint(file_path, config, crosswalk):
|
|
|
112
178
|
# Return only the enriched detailed patient data, eliminating the need for a separate summary list
|
|
113
179
|
return detailed_patient_data
|
|
114
180
|
|
|
115
|
-
def organize_patient_data_by_endpoint(detailed_patient_data):
|
|
116
|
-
"""
|
|
117
|
-
Organizes detailed patient data by their confirmed endpoints.
|
|
118
|
-
This simplifies processing and conversion per endpoint basis, ensuring that claims are generated and submitted
|
|
119
|
-
according to the endpoint-specific requirements.
|
|
120
|
-
|
|
121
|
-
:param detailed_patient_data: A list of dictionaries, each containing detailed patient data including confirmed endpoint.
|
|
122
|
-
:return: A dictionary with endpoints as keys and lists of detailed patient data as values for processing.
|
|
123
|
-
"""
|
|
124
|
-
organized = {}
|
|
125
|
-
for data in detailed_patient_data:
|
|
126
|
-
# Retrieve confirmed endpoint from each patient's data
|
|
127
|
-
endpoint = data['confirmed_endpoint'] if 'confirmed_endpoint' in data else data['suggested_endpoint']
|
|
128
|
-
# Initialize a list for the endpoint if it doesn't exist
|
|
129
|
-
if endpoint not in organized:
|
|
130
|
-
organized[endpoint] = []
|
|
131
|
-
organized[endpoint].append(data)
|
|
132
|
-
return organized
|
|
133
|
-
|
|
134
181
|
def check_for_new_remittances(config):
|
|
135
182
|
print("\nChecking for new files across all endpoints...")
|
|
136
183
|
endpoints = config['MediLink_Config']['endpoints']
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
184
|
+
processed_endpoints = []
|
|
185
|
+
|
|
186
|
+
if isinstance(endpoints, dict): # BUG This check can probably be removed later.
|
|
187
|
+
for endpoint_key, endpoint_info in tqdm(endpoints.items(), desc="Processing endpoints"):
|
|
188
|
+
if 'remote_directory_down' in endpoint_info: # Check if the 'remote_directory_down' key exists
|
|
189
|
+
#print("Processing endpoint: ", endpoint_info['name'])
|
|
190
|
+
# BUG (Debug and verbosity removal) this is really for debug only. Positive statements can be muted.
|
|
191
|
+
try:
|
|
192
|
+
ERA_path = MediLink_Down.main(desired_endpoint=endpoint_key)
|
|
193
|
+
processed_endpoints.append((endpoint_info['name'], ERA_path))
|
|
194
|
+
MediLink_ConfigLoader.log("Results for {} saved to: {}".format(endpoint_info['name'], ERA_path))
|
|
195
|
+
# TODO (Low SFTP - Download side) This needs to check to see if this actually worked maybe winscplog before saying it completed successfully
|
|
196
|
+
# Check if there is commonality with the upload side so we can use the same validation function.
|
|
197
|
+
except Exception as e:
|
|
198
|
+
print("An error occurred while checking remittances for {}: {}".format(endpoint_info['name'], e))
|
|
199
|
+
else:
|
|
200
|
+
MediLink_ConfigLoader.log("Skipping endpoint '{}' as it does not have 'remote_directory_down' configured.".format(endpoint_info['name']))
|
|
201
|
+
else:
|
|
202
|
+
print("Error: Endpoint config is not a 'dictionary' as expected.")
|
|
203
|
+
# Check if all ERA paths are the same
|
|
204
|
+
unique_era_paths = set(path for _, path in processed_endpoints)
|
|
205
|
+
if len(unique_era_paths) == 1:
|
|
206
|
+
common_era_path = unique_era_paths.pop() # Get the common ERA path
|
|
207
|
+
endpoints_list = ", ".join(endpoint for endpoint, _ in processed_endpoints)
|
|
208
|
+
print("\nProcessed Endpoints: {}".format(endpoints_list))
|
|
209
|
+
print("File located at: {}\n".format(common_era_path))
|
|
210
|
+
# TODO (MediPost) These prints will eventually be logs when MediPost is made.
|
|
211
|
+
|
|
212
|
+
else:
|
|
213
|
+
if processed_endpoints:
|
|
214
|
+
print("\nProcessed Endpoints:")
|
|
215
|
+
for endpoint, path in processed_endpoints:
|
|
216
|
+
print("Endpoint: {}, ERA Path: {}".format(endpoint, path))
|
|
217
|
+
else:
|
|
218
|
+
print("No endpoints were processed.")
|
|
146
219
|
|
|
147
220
|
def user_decision_on_suggestions(detailed_patient_data, config):
|
|
148
221
|
"""
|
|
149
222
|
Presents the user with all patient summaries and suggested endpoints,
|
|
150
223
|
then asks for confirmation to proceed with all or specify adjustments manually.
|
|
224
|
+
|
|
225
|
+
BUG (Med suggested_endpoint) The display summary suggested_endpoint key isn't updating per the user's decision
|
|
226
|
+
although the user decision is persisting. Possibly consider making the current/suggested/confirmed endpoint
|
|
227
|
+
part of a class that the user can interact with via these menus? Probably better handling that way.
|
|
151
228
|
"""
|
|
152
229
|
# Display summaries of patient details and endpoints.
|
|
153
230
|
MediLink_UI.display_patient_summaries(detailed_patient_data)
|
|
@@ -157,32 +234,27 @@ def user_decision_on_suggestions(detailed_patient_data, config):
|
|
|
157
234
|
|
|
158
235
|
# If the user agrees to proceed with all suggested endpoints, confirm them.
|
|
159
236
|
if proceed:
|
|
160
|
-
return confirm_all_suggested_endpoints(detailed_patient_data)
|
|
237
|
+
return MediLink_DataMgmt.confirm_all_suggested_endpoints(detailed_patient_data)
|
|
161
238
|
# Otherwise, allow the user to adjust the endpoints manually.
|
|
162
239
|
else:
|
|
163
240
|
return select_and_adjust_files(detailed_patient_data, config)
|
|
164
|
-
|
|
165
|
-
def confirm_all_suggested_endpoints(detailed_patient_data):
|
|
166
|
-
"""
|
|
167
|
-
Confirms all suggested endpoints for each patient's detailed data.
|
|
168
|
-
"""
|
|
169
|
-
for data in detailed_patient_data:
|
|
170
|
-
if 'confirmed_endpoint' not in data:
|
|
171
|
-
data['confirmed_endpoint'] = data['suggested_endpoint']
|
|
172
|
-
return detailed_patient_data
|
|
173
|
-
|
|
241
|
+
|
|
174
242
|
def select_and_adjust_files(detailed_patient_data, config):
|
|
175
243
|
"""
|
|
176
244
|
Allows users to select patients and adjust their endpoints by interfacing with UI functions.
|
|
245
|
+
|
|
246
|
+
BUG (Med suggested_endpoint) After the user is done making their selection (probably via a class?),
|
|
247
|
+
Then suggested_endpoint should update to persist the user selection as priority over its original suggestion.
|
|
248
|
+
Which means the crosswalk should persist the change in the endpoint as well.
|
|
177
249
|
"""
|
|
178
250
|
# Display options for patients
|
|
179
251
|
MediLink_UI.display_patient_options(detailed_patient_data)
|
|
180
252
|
|
|
181
253
|
# Get user-selected indices for adjustment
|
|
182
254
|
selected_indices = MediLink_UI.get_selected_indices(len(detailed_patient_data))
|
|
183
|
-
|
|
184
|
-
#
|
|
185
|
-
|
|
255
|
+
|
|
256
|
+
# Get an ordered list of endpoint keys
|
|
257
|
+
endpoint_keys = list(config['MediLink_Config']['endpoints'].keys())
|
|
186
258
|
|
|
187
259
|
# Iterate over each selected index and process endpoint changes
|
|
188
260
|
for i in selected_indices:
|
|
@@ -190,20 +262,20 @@ def select_and_adjust_files(detailed_patient_data, config):
|
|
|
190
262
|
MediLink_UI.display_patient_for_adjustment(data['patient_name'], data.get('suggested_endpoint', 'N/A'))
|
|
191
263
|
|
|
192
264
|
endpoint_change = MediLink_UI.get_endpoint_decision()
|
|
193
|
-
|
|
194
265
|
if endpoint_change == 'y':
|
|
195
|
-
MediLink_UI.display_endpoint_options(
|
|
196
|
-
|
|
266
|
+
MediLink_UI.display_endpoint_options(config['MediLink_Config']['endpoints'])
|
|
267
|
+
endpoint_index = int(MediLink_UI.get_new_endpoint_choice()) - 1 # Adjusting for zero-based index
|
|
197
268
|
|
|
198
|
-
if
|
|
199
|
-
|
|
200
|
-
|
|
269
|
+
if 0 <= endpoint_index < len(endpoint_keys):
|
|
270
|
+
selected_endpoint_key = endpoint_keys[endpoint_index]
|
|
271
|
+
data['confirmed_endpoint'] = selected_endpoint_key
|
|
272
|
+
print("Endpoint changed to {0} for patient {1}.".format(config['MediLink_Config']['endpoints'][selected_endpoint_key]['name'], data['patient_name']))
|
|
273
|
+
# BUG (Med, Crosswalk & suggested_endpoint) Probably update crosswalk and suggested endpoint here???
|
|
201
274
|
else:
|
|
202
275
|
print("Invalid selection. Keeping the suggested endpoint.")
|
|
203
276
|
else:
|
|
204
277
|
data['confirmed_endpoint'] = data.get('suggested_endpoint', 'N/A')
|
|
205
278
|
|
|
206
|
-
# Return the updated data
|
|
207
279
|
return detailed_patient_data
|
|
208
280
|
|
|
209
281
|
def main_menu():
|
|
@@ -212,7 +284,14 @@ def main_menu():
|
|
|
212
284
|
including loading configurations and managing user input for menu selections.
|
|
213
285
|
"""
|
|
214
286
|
# Load configuration settings and display the initial welcome message.
|
|
215
|
-
config, crosswalk = MediLink_ConfigLoader.load_configuration()
|
|
287
|
+
config, crosswalk = MediLink_ConfigLoader.load_configuration()
|
|
288
|
+
|
|
289
|
+
# Check to make sure payer_id key is available in crosswalk, otherwise, go through that crosswalk initialization flow
|
|
290
|
+
MediBot_Crosswalk_Library.check_and_initialize_crosswalk(config)
|
|
291
|
+
|
|
292
|
+
# Check if the application is in test mode
|
|
293
|
+
if config.get("MediLink_Config", {}).get("TestMode", False):
|
|
294
|
+
print("\n--- MEDILINK TEST MODE --- \nTo enable full functionality, please update the config file \nand set 'TestMode' to 'false'.")
|
|
216
295
|
|
|
217
296
|
# Display Welcome Message
|
|
218
297
|
MediLink_UI.display_welcome()
|
|
@@ -222,6 +301,9 @@ def main_menu():
|
|
|
222
301
|
|
|
223
302
|
# Detect new files and collect detailed patient data if available.
|
|
224
303
|
new_files, detailed_patient_data = detect_and_display_file_summaries(directory_path, config, crosswalk)
|
|
304
|
+
|
|
305
|
+
if new_files:
|
|
306
|
+
handle_submission(detailed_patient_data, config)
|
|
225
307
|
|
|
226
308
|
while True:
|
|
227
309
|
# Define the menu options. Base options include checking remittances and exiting the program.
|
|
@@ -240,7 +322,7 @@ def main_menu():
|
|
|
240
322
|
check_for_new_remittances(config)
|
|
241
323
|
elif choice == '2' and new_files:
|
|
242
324
|
# Handle the claims submission flow if new files are present.
|
|
243
|
-
handle_submission(detailed_patient_data, config)
|
|
325
|
+
handle_submission(detailed_patient_data, config) # Since we have the bulk edit, we should actually go there first
|
|
244
326
|
elif choice == '3' or (choice == '2' and not new_files):
|
|
245
327
|
# Exit the program if the user chooses to exit or if no new files are present.
|
|
246
328
|
MediLink_UI.display_exit_message()
|
|
@@ -254,18 +336,35 @@ def handle_submission(detailed_patient_data, config):
|
|
|
254
336
|
Handles the submission process for claims based on detailed patient data.
|
|
255
337
|
This function orchestrates the flow from user decision on endpoint suggestions to the actual submission of claims.
|
|
256
338
|
"""
|
|
339
|
+
# TODO If we get here via a user decline we end up not displaying the patient summary data, but this doesn't happen in the first round. Can be de-tangled later.
|
|
340
|
+
|
|
341
|
+
# Ask the user if they want to edit insurance types
|
|
342
|
+
edit_insurance = input("Do you want to edit insurance types? (y/n): ").strip().lower()
|
|
343
|
+
if edit_insurance in ['y', 'yes', '']:
|
|
344
|
+
while True:
|
|
345
|
+
# Bulk edit insurance types
|
|
346
|
+
MediLink_DataMgmt.bulk_edit_insurance_types(detailed_patient_data, insurance_options)
|
|
347
|
+
|
|
348
|
+
# Review and confirm changes
|
|
349
|
+
if MediLink_DataMgmt.review_and_confirm_changes(detailed_patient_data, insurance_options):
|
|
350
|
+
break # Exit the loop if changes are confirmed
|
|
351
|
+
else:
|
|
352
|
+
print("Returning to bulk edit insurance types.")
|
|
353
|
+
|
|
257
354
|
# Initiate user interaction to confirm or adjust suggested endpoints.
|
|
258
355
|
adjusted_data = user_decision_on_suggestions(detailed_patient_data, config)
|
|
356
|
+
|
|
259
357
|
# Confirm all remaining suggested endpoints.
|
|
260
|
-
confirmed_data = confirm_all_suggested_endpoints(adjusted_data)
|
|
358
|
+
confirmed_data = MediLink_DataMgmt.confirm_all_suggested_endpoints(adjusted_data)
|
|
261
359
|
if confirmed_data: # Proceed if there are confirmed data entries.
|
|
262
360
|
# Organize data by confirmed endpoints for submission.
|
|
263
|
-
organized_data = organize_patient_data_by_endpoint(confirmed_data)
|
|
361
|
+
organized_data = MediLink_DataMgmt.organize_patient_data_by_endpoint(confirmed_data)
|
|
264
362
|
# Confirm transmission with the user and check for internet connectivity.
|
|
265
363
|
if MediLink_Up.confirm_transmission(organized_data):
|
|
266
364
|
if MediLink_Up.check_internet_connection():
|
|
267
365
|
# Submit claims if internet connectivity is confirmed.
|
|
268
|
-
MediLink_Up.submit_claims(organized_data, config)
|
|
366
|
+
_ = MediLink_Up.submit_claims(organized_data, config)
|
|
367
|
+
# TODO submit_claims will have a receipt return in the future.
|
|
269
368
|
else:
|
|
270
369
|
# Notify the user of an internet connection error.
|
|
271
370
|
print("Internet connection error. Please ensure you're connected and try again.")
|