medicafe 0.240419.2__py3-none-any.whl → 0.240517.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 +166 -38
- MediBot/MediBot.py +74 -44
- MediBot/MediBot_Crosswalk_Library.py +280 -0
- MediBot/MediBot_Preprocessor.py +155 -191
- MediBot/MediBot_Preprocessor_lib.py +357 -0
- MediBot/MediBot_UI.py +80 -30
- MediBot/MediBot_dataformat_library.py +88 -35
- MediBot/MediBot_docx_decoder.py +80 -0
- MediBot/update_medicafe.py +46 -8
- MediLink/MediLink.py +138 -34
- MediLink/MediLink_837p_encoder.py +319 -209
- MediLink/MediLink_837p_encoder_library.py +453 -242
- MediLink/MediLink_API_v2.py +174 -0
- MediLink/MediLink_APIs.py +137 -0
- MediLink/MediLink_ConfigLoader.py +44 -32
- MediLink/MediLink_DataMgmt.py +85 -33
- MediLink/MediLink_Down.py +12 -35
- MediLink/MediLink_ERA_decoder.py +4 -4
- MediLink/MediLink_Gmail.py +99 -3
- MediLink/MediLink_Mailer.py +7 -0
- MediLink/MediLink_Scheduler.py +41 -0
- MediLink/MediLink_UI.py +19 -17
- MediLink/MediLink_Up.py +297 -31
- MediLink/MediLink_batch.bat +1 -1
- MediLink/test.py +74 -0
- medicafe-0.240517.0.dist-info/METADATA +53 -0
- medicafe-0.240517.0.dist-info/RECORD +39 -0
- {medicafe-0.240419.2.dist-info → medicafe-0.240517.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.240517.0.dist-info}/LICENSE +0 -0
- {medicafe-0.240419.2.dist-info → medicafe-0.240517.0.dist-info}/top_level.txt +0 -0
MediLink/MediLink_Down.py
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import os
|
|
2
|
-
import logging
|
|
3
2
|
import argparse
|
|
4
3
|
import shutil
|
|
5
4
|
from datetime import datetime
|
|
@@ -20,28 +19,6 @@ We need to make another function that figures out claim rejections and tries to
|
|
|
20
19
|
7. Configuration Key Accuracy: Audit the script to correct any inaccuracies in configuration key references, ensuring seamless configuration data retrieval.
|
|
21
20
|
"""
|
|
22
21
|
|
|
23
|
-
# Setup basic logging
|
|
24
|
-
def setup_logger(local_storage_path):
|
|
25
|
-
# Define a reasonable name for the log file, e.g., "MediLink_Down_Process.log"
|
|
26
|
-
log_filename = datetime.now().strftime("MediLink_Down_Process_%m%d%Y.log")
|
|
27
|
-
log_filepath = os.path.join(local_storage_path, log_filename)
|
|
28
|
-
|
|
29
|
-
for handler in logging.root.handlers[:]:
|
|
30
|
-
logging.root.removeHandler(handler)
|
|
31
|
-
|
|
32
|
-
# Setup logging to file
|
|
33
|
-
logging.basicConfig(level=logging.INFO,
|
|
34
|
-
format='%(asctime)s - %(levelname)s - %(message)s',
|
|
35
|
-
filename=log_filepath, # Direct logging to a file in local_storage_path
|
|
36
|
-
filemode='a') # Append mode
|
|
37
|
-
|
|
38
|
-
# If you also want to see the logs in the console, add a StreamHandler
|
|
39
|
-
#console_handler = logging.StreamHandler()
|
|
40
|
-
#console_handler.setLevel(logging.INFO)
|
|
41
|
-
#formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')
|
|
42
|
-
#console_handler.setFormatter(formatter)
|
|
43
|
-
#logging.getLogger('').addHandler(console_handler)
|
|
44
|
-
|
|
45
22
|
# Because I can't figure out how to get it to work directly in the WinSCP command.
|
|
46
23
|
# And on the Windows XP machine apparently the default path is C:\\ ...
|
|
47
24
|
# This needs to get fixed. Ugh.
|
|
@@ -62,7 +39,7 @@ def move_downloaded_files(local_storage_path):
|
|
|
62
39
|
# source_path = os.path.join('.', file) for the XP machine? -- This whole thing needs repaired.
|
|
63
40
|
destination_path = os.path.join(local_response_directory, file)
|
|
64
41
|
shutil.move(source_path, destination_path)
|
|
65
|
-
|
|
42
|
+
MediLink_ConfigLoader.log("Moved '{}' to '{}'".format(file, local_response_directory))
|
|
66
43
|
|
|
67
44
|
def find_era_files(era_file_path):
|
|
68
45
|
"""
|
|
@@ -92,7 +69,6 @@ def main(desired_endpoint='AVAILITY'):
|
|
|
92
69
|
# Setup Logger, Load configuration and output directory
|
|
93
70
|
config, _ = MediLink_ConfigLoader.load_configuration(args.config_path)
|
|
94
71
|
local_storage_path = config['MediLink_Config']['local_storage_path']
|
|
95
|
-
setup_logger(local_storage_path)
|
|
96
72
|
output_directory = os.path.join(local_storage_path, "translated_csvs")
|
|
97
73
|
|
|
98
74
|
# Direct ERA file translation if a file path is provided
|
|
@@ -100,24 +76,25 @@ def main(desired_endpoint='AVAILITY'):
|
|
|
100
76
|
era_files = find_era_files(args.era_file_path)
|
|
101
77
|
if era_files:
|
|
102
78
|
era_files_str = ', '.join(era_files)
|
|
103
|
-
|
|
79
|
+
MediLink_ConfigLoader.log("Translating ERA files: {}".format(era_files_str))
|
|
104
80
|
MediLink_ERA_decoder.translate_era_to_csv(era_files, output_directory)
|
|
105
81
|
# Instead of returning a single CSV file path, consolidate here
|
|
106
82
|
consolidate_csv_path = MediLink_ERA_decoder.consolidate_csvs(output_directory)
|
|
107
|
-
|
|
83
|
+
MediLink_ConfigLoader.log("Translation and consolidation completed.")
|
|
108
84
|
return consolidate_csv_path
|
|
109
85
|
else:
|
|
110
|
-
|
|
86
|
+
MediLink_ConfigLoader.log("No ERA files found matching: {}".format(args.era_file_path))
|
|
111
87
|
return
|
|
112
88
|
|
|
113
|
-
# TODO This probably needs to be built into a loop that cycles through all 3 endpoints.
|
|
89
|
+
# TODO (Low Remit) This probably needs to be built into a loop that cycles through all 3 endpoints.
|
|
90
|
+
# I think the uploader has something like this implemented already since it sends to all the endpoints.
|
|
114
91
|
# The loop should use the tdqa or whatever the progress bar is called.
|
|
115
|
-
print("Please wait...\n")
|
|
92
|
+
# print("Please wait...\n")
|
|
116
93
|
|
|
117
94
|
# Validate endpoint key
|
|
118
95
|
endpoint_key = args.desired_endpoint
|
|
119
96
|
if endpoint_key not in config['MediLink_Config']['endpoints']:
|
|
120
|
-
|
|
97
|
+
MediLink_ConfigLoader.log("Endpoint '{}' not found in configuration. Using default 'AVAILITY'.".format(endpoint_key))
|
|
121
98
|
endpoint_key = 'AVAILITY'
|
|
122
99
|
|
|
123
100
|
# Retrieve endpoint configuration and local storage path
|
|
@@ -125,17 +102,17 @@ def main(desired_endpoint='AVAILITY'):
|
|
|
125
102
|
local_storage_path = config['MediLink_Config']['local_storage_path']
|
|
126
103
|
|
|
127
104
|
# Download ERA files from the configured endpoint
|
|
128
|
-
downloaded_files = operate_winscp("download", None, endpoint_config, local_storage_path)
|
|
129
|
-
|
|
105
|
+
downloaded_files = operate_winscp("download", None, endpoint_config, local_storage_path, config)
|
|
106
|
+
|
|
130
107
|
# Translate downloaded ERA files to CSV format
|
|
131
108
|
translated_csv_paths = []
|
|
132
109
|
for file in downloaded_files:
|
|
133
|
-
# TODO This needs to add functionality for differentiating between ERA
|
|
110
|
+
# TODO (Low Remit) This needs to add functionality for differentiating between ERA, 277, IBT or
|
|
134
111
|
# whatever else might be included in the download folders.
|
|
135
112
|
MediLink_ERA_decoder.translate_era_to_csv([file], output_directory)
|
|
136
113
|
csv_file_path = os.path.join(output_directory, os.path.basename(file) + '.csv')
|
|
137
114
|
translated_csv_paths.append(csv_file_path)
|
|
138
|
-
|
|
115
|
+
MediLink_ConfigLoader.log("Translated ERA to CSV: {}".format(csv_file_path))
|
|
139
116
|
|
|
140
117
|
# Consolidate new CSVs
|
|
141
118
|
consolidate_csv_path = MediLink_ERA_decoder.consolidate_csvs(output_directory)
|
MediLink/MediLink_ERA_decoder.py
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import os
|
|
2
|
-
import logging
|
|
3
2
|
import sys
|
|
4
|
-
|
|
3
|
+
import csv
|
|
4
|
+
from MediLink_ConfigLoader import load_configuration, log
|
|
5
5
|
from MediLink_DataMgmt import consolidate_csvs
|
|
6
6
|
|
|
7
|
+
|
|
7
8
|
"""
|
|
8
9
|
1. ERA File Processing: Implement robust mechanisms for reading and parsing ERA files, addressing potential file integrity issues and accommodating scenarios with multiple payer addresses within a single ERA.
|
|
9
10
|
2. Wildcard File Processing: Enable effective batch processing of ERA files using wildcard patterns in the `--era_file_path` argument, resulting in a unified CSV output.
|
|
@@ -170,7 +171,6 @@ if __name__ == "__main__":
|
|
|
170
171
|
|
|
171
172
|
# Setup logger
|
|
172
173
|
local_storage_path = config['MediLink_Config']['local_storage_path']
|
|
173
|
-
setup_logger(local_storage_path)
|
|
174
174
|
|
|
175
175
|
# Define output directory
|
|
176
176
|
output_directory = os.path.join(local_storage_path, "translated_csvs")
|
|
@@ -178,7 +178,7 @@ if __name__ == "__main__":
|
|
|
178
178
|
# Retrieve ERA files from command line arguments
|
|
179
179
|
files = sys.argv[1:] # Exclude the script name
|
|
180
180
|
if not files:
|
|
181
|
-
|
|
181
|
+
log("No ERA files provided as arguments.")
|
|
182
182
|
sys.exit(1)
|
|
183
183
|
|
|
184
184
|
# Translate ERA files to CSV format
|
MediLink/MediLink_Gmail.py
CHANGED
|
@@ -1,4 +1,100 @@
|
|
|
1
1
|
"""
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
2
|
+
This documentation outlines the current functionality and development insights of a Google Apps Script and associated
|
|
3
|
+
client-side Python script designed to facilitate the automated retrieval of secured content from emails. The system
|
|
4
|
+
enables users to extract links and one-time passwords (OTPs) from emails, initiating and managing secure email interactions
|
|
5
|
+
without manual intervention.
|
|
6
|
+
|
|
7
|
+
**Current Functionality:**
|
|
8
|
+
1. **Google Apps Script (Server-side)**:
|
|
9
|
+
- Handles HTTP GET requests, routing them based on the 'action' parameter to perform tasks like retrieving stored
|
|
10
|
+
OTPs, extracting links from emails, and retrieving email subjects for user selection.
|
|
11
|
+
- Utilizes Gmail search queries to find relevant emails based on sender and date criteria, then extracts data like
|
|
12
|
+
subjects or specific links contained within these emails.
|
|
13
|
+
- Supports interactive selection of emails via a web app, allowing users to choose an email from a list and extract
|
|
14
|
+
a specific link.
|
|
15
|
+
- Employs properties service to store and retrieve data like links and OTPs securely.
|
|
16
|
+
|
|
17
|
+
2. **HTML Client (Server-side)**:
|
|
18
|
+
- Provides a user interface for selecting emails from a list, triggered by server-side scripts.
|
|
19
|
+
- Includes JavaScript to handle client-server communication and user interactions, such as selecting an email and
|
|
20
|
+
extracting a link.
|
|
21
|
+
|
|
22
|
+
3. **Python Script (Client-side)**:
|
|
23
|
+
- Interfaces with the server-side web app to initiate processes like link retrieval.
|
|
24
|
+
- Manages opening URLs in the user's browser, allowing for interaction with the web app directly from the client-side
|
|
25
|
+
environment.
|
|
26
|
+
|
|
27
|
+
**Future Work:**
|
|
28
|
+
- [ ] Consider disabling OTP triggers for now since we don't really use it for the present implementation. The phone solution works.
|
|
29
|
+
- [ ] Implement and troubleshoot the OTP extraction and validation system to fully automate the secured content retrieval process.
|
|
30
|
+
- [X] Gmail Server-side Authentication flow & Webapp build
|
|
31
|
+
- [X] Upgrade to handle multiple possible emails selection
|
|
32
|
+
- [ ] Augment to detect Surgery Schedule emails with doc attachments that don't require OTP.
|
|
33
|
+
- [X] Upgrade Gmail query to only get emails with the protected links.
|
|
34
|
+
- [ ] Something that goes here that I forgot.
|
|
35
|
+
|
|
36
|
+
**Technical Challenges and Solutions:**
|
|
37
|
+
1. **Authentication Limitations on XP Systems:**
|
|
38
|
+
- **Challenge:** The XP operating system could not perform authentication natively outside a browser, and available
|
|
39
|
+
libraries were not capable of handling dynamic authentication.
|
|
40
|
+
- **Solution:** We centralized all user interactions within an HTML page served by Google Apps Script, thereby
|
|
41
|
+
eliminating the need for complex client-side operations. The client-side script was simplified to merely opening URLs, reducing the complexity and potential for errors.
|
|
42
|
+
|
|
43
|
+
2. **Secure Data Handling:**
|
|
44
|
+
- **Challenge:** Initially, handling sensitive data such as OTPs and integrating with O365 protected emails was complex
|
|
45
|
+
due to security requirements and the transient nature of such data. The solution had to accommodate the specific
|
|
46
|
+
security protocols of Microsoft's environment without direct interaction.
|
|
47
|
+
- **Solution:** Utilizing Google Apps Script’s property service to store OTPs temporarily and securely. Additionally,
|
|
48
|
+
we addressed O365 integration by ensuring the browser handled email links directly, respecting Microsoft's security
|
|
49
|
+
constraints like x-frame options, thus maintaining functionality without compromising security.
|
|
50
|
+
|
|
51
|
+
3. **User Interaction and Workflow Streamlining:**
|
|
52
|
+
- **Challenge:** Managing the workflow from email selection to secure content access required multiple steps that could
|
|
53
|
+
potentially confuse the user. The application also had to be efficient under low-bandwidth constraints, and initially,
|
|
54
|
+
XP could not download attachments directly, requiring manual user intervention.
|
|
55
|
+
- **Solution:** The introduction of an interactive web app interface enabled users to select emails directly through a
|
|
56
|
+
user-friendly list, significantly simplifying the workflow and minimizing user errors. This method also streamlined
|
|
57
|
+
the process, making it suitable for low-bandwidth environments and circumventing the need for full email client loads.
|
|
58
|
+
"""
|
|
59
|
+
import sys
|
|
60
|
+
import subprocess
|
|
61
|
+
import webbrowser
|
|
62
|
+
from MediLink_ConfigLoader import log
|
|
63
|
+
|
|
64
|
+
def open_browser_with_executable(url, browser_path=None):
|
|
65
|
+
"""
|
|
66
|
+
Opens a browser with the specified URL using a provided browser executable path or the default browser.
|
|
67
|
+
"""
|
|
68
|
+
try:
|
|
69
|
+
if browser_path:
|
|
70
|
+
log("Attempting to open URL with provided executable: {} {}".format(browser_path, url))
|
|
71
|
+
# Try to open the browser using subprocess.Popen
|
|
72
|
+
process = subprocess.Popen([browser_path, url], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
|
73
|
+
stdout, stderr = process.communicate()
|
|
74
|
+
if process.returncode == 0:
|
|
75
|
+
log("Browser opened with provided executable path using subprocess.Popen.")
|
|
76
|
+
else:
|
|
77
|
+
log("Browser failed to open using subprocess.Popen. Return code: {}. Stderr: {}".format(process.returncode, stderr))
|
|
78
|
+
else:
|
|
79
|
+
# Fall back to the default browser if no specific path is provided
|
|
80
|
+
log("No browser path provided. Attempting to open URL with default browser: {}".format(url))
|
|
81
|
+
webbrowser.open(url)
|
|
82
|
+
log("Default browser opened.")
|
|
83
|
+
except Exception as e:
|
|
84
|
+
log("Failed to open browser: {}".format(e))
|
|
85
|
+
|
|
86
|
+
def initiate_link_retrieval():
|
|
87
|
+
"""
|
|
88
|
+
Opens the web application through a direct URL that includes the action parameter.
|
|
89
|
+
"""
|
|
90
|
+
log("Initiating link retrieval process.")
|
|
91
|
+
# Direct URL that includes the action parameter to load the HTML content directly
|
|
92
|
+
url = "https://script.google.com/macros/s/AKfycbzlq8d32mDlLdtFxgL_zvLJernlGPB64ftyxyH8F1nNlr3P-VBH6Yd0NGa1pbBc5AozvQ/exec?action=get_link"
|
|
93
|
+
try:
|
|
94
|
+
browser_path = sys.argv[1] if len(sys.argv) > 1 else None
|
|
95
|
+
open_browser_with_executable(url, browser_path)
|
|
96
|
+
except Exception as e:
|
|
97
|
+
log("Error during link retrieval initiation: {}".format(e))
|
|
98
|
+
|
|
99
|
+
if __name__ == "__main__":
|
|
100
|
+
initiate_link_retrieval()
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
"""
|
|
2
|
+
This is the tool that is going to pull from Medisoft the "REFUND TO PATIENT" amounts and addresses and whatever
|
|
3
|
+
and talk to either Bill.com or a BOA BillPay for Business service or CheckIssuing or something to send automated
|
|
4
|
+
refund checks to patients.
|
|
5
|
+
|
|
6
|
+
Also, this tool should be able to do mailed invoicing for "BILL TO PATIENT" to bill a patient as well.
|
|
7
|
+
"""
|
MediLink/MediLink_Scheduler.py
CHANGED
|
@@ -62,6 +62,47 @@ Database Management:
|
|
|
62
62
|
- Stays on the local machine in a defined secure location per config, ensuring HIPAA compliance without the need for data encryption at rest.
|
|
63
63
|
|
|
64
64
|
Note: Potential for data corruption or synchronization issues due to system limitations; backup and manual verification measures are advised.
|
|
65
|
+
|
|
66
|
+
Crosswalk Example:
|
|
67
|
+
"payer_id": {
|
|
68
|
+
"87726": {
|
|
69
|
+
"medisoft_medicare_id": [],
|
|
70
|
+
"medisoft_id": [
|
|
71
|
+
"320"
|
|
72
|
+
],
|
|
73
|
+
"endpoint": "OPTUMEDI"
|
|
74
|
+
},
|
|
75
|
+
"60054": {
|
|
76
|
+
"medisoft_medicare_id": [],
|
|
77
|
+
"medisoft_id": [
|
|
78
|
+
"369"
|
|
79
|
+
],
|
|
80
|
+
"endpoint": "OPTUMEDI"
|
|
81
|
+
},
|
|
82
|
+
"00590": {
|
|
83
|
+
"medisoft_medicare_id": [],
|
|
84
|
+
"medisoft_id": [
|
|
85
|
+
"317"
|
|
86
|
+
],
|
|
87
|
+
"endpoint": "OPTUMEDI"
|
|
88
|
+
},
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
Crosswalk add:
|
|
92
|
+
- submit_buffer_maria per payer_id
|
|
93
|
+
- submit_limit_days per payer_id
|
|
94
|
+
- deductible_max = $2500.
|
|
95
|
+
- submit limit buffer = 15 days before final.
|
|
96
|
+
|
|
97
|
+
MediLink_Scheduler logic to produce dates of submission:
|
|
98
|
+
deductible slows it until a max limit ($2500), then send anyway.
|
|
99
|
+
after maria buffer, before submit (-15?) limit day.
|
|
100
|
+
Maria collects pre-payment, this is a factor, needs to be somehow accounted for in the process where a quantity gets pre-assigned to a patient so we know when to submit the claim.
|
|
101
|
+
|
|
102
|
+
Date last reviewed, Insurance Type, In network, Annual Deductable Remaining, Recieved pre-payment amount, Check# or 'Cash'.
|
|
103
|
+
|
|
104
|
+
In the future those pre-payments should be either eCheck, Zelle or by CC + 5% surcharge.
|
|
105
|
+
|
|
65
106
|
"""
|
|
66
107
|
|
|
67
108
|
|
MediLink/MediLink_UI.py
CHANGED
|
@@ -1,20 +1,21 @@
|
|
|
1
|
-
import datetime
|
|
2
|
-
import sys
|
|
1
|
+
from datetime import datetime
|
|
3
2
|
|
|
4
3
|
"""
|
|
5
4
|
Development Tasks for User Interface (UI) Enhancement in MediSoft Claims Submittal (MediLink) Script:
|
|
6
5
|
|
|
7
|
-
Streamline user interaction for endpoint selection and patient adjustments with automated endpoint validation.
|
|
8
|
-
Strengthen error handling in file conversion, transmission, and user inputs with actionable user feedback.
|
|
9
|
-
Expand logging levels and develop a user notification system for process milestones and errors.
|
|
10
|
-
Focus workflow on patient details for endpoint adjustments, facilitating patient-centric file submissions.
|
|
11
|
-
Implement internet connectivity checks with retry options for submissions and offer pause/resume capabilities.
|
|
12
|
-
Include final review and confirmation steps before submission, allowing for endpoint adjustments per patient.
|
|
6
|
+
- [ ] Streamline user interaction for endpoint selection and patient adjustments with automated endpoint validation.
|
|
7
|
+
- [ ] Strengthen error handling in file conversion, transmission, and user inputs with actionable user feedback.
|
|
8
|
+
- [ ] Expand logging levels and develop a user notification system for process milestones and errors.
|
|
9
|
+
- [ ] Focus workflow on patient details for endpoint adjustments, facilitating patient-centric file submissions.
|
|
10
|
+
- [ ] Implement internet connectivity checks with retry options for submissions and offer pause/resume capabilities.
|
|
11
|
+
- [ ] Include final review and confirmation steps before submission, allowing for endpoint adjustments per patient.
|
|
12
|
+
- [ ] TODO Need to resolve suggested endpoint issues/refresh/quasi-persist (this is partially implemented, careful)
|
|
13
|
+
- [ ] TODO Augment the menu for displaying the insurance type information before submittal.
|
|
13
14
|
"""
|
|
14
15
|
|
|
15
16
|
def display_welcome():
|
|
16
17
|
print("\n" + "-" * 60)
|
|
17
|
-
print("
|
|
18
|
+
print(" *~^~*: Welcome to MediLink! :*~^~*")
|
|
18
19
|
print("-" * 60 + "\n")
|
|
19
20
|
|
|
20
21
|
def display_menu(options):
|
|
@@ -35,7 +36,7 @@ def display_patient_options(detailed_patient_data):
|
|
|
35
36
|
"""
|
|
36
37
|
Displays a list of patients with their current suggested endpoints, prompting for selections to adjust.
|
|
37
38
|
"""
|
|
38
|
-
print("\nPlease select the patients
|
|
39
|
+
print("\nPlease select the patients to adjust by entering their numbers separated by commas\n(e.g., 1,3,5):")
|
|
39
40
|
# Can disable this extra print for now because the px list would already be on-screen.
|
|
40
41
|
#for i, data in enumerate(detailed_patient_data, start=1):
|
|
41
42
|
# patient_info = "{0} ({1}) - {2}".format(data['patient_name'], data['patient_id'], data['surgery_date'])
|
|
@@ -62,26 +63,27 @@ def get_endpoint_decision():
|
|
|
62
63
|
"""
|
|
63
64
|
return input("Change endpoint? (Y/N): ").strip().lower()
|
|
64
65
|
|
|
65
|
-
def display_endpoint_options(
|
|
66
|
+
def display_endpoint_options(endpoints_config):
|
|
66
67
|
"""
|
|
67
68
|
Displays the endpoint options to the user based on the provided mapping.
|
|
68
69
|
|
|
69
70
|
Args:
|
|
70
|
-
|
|
71
|
-
|
|
71
|
+
endpoints_config (dict): A dictionary mapping endpoint keys to their properties,
|
|
72
|
+
where each property includes a 'name' key for the user-friendly name.
|
|
73
|
+
Example: {'Availity': {'name': 'Availity'}, 'OptumEDI': {'name': 'OptumEDI'}, ...}
|
|
72
74
|
|
|
73
75
|
Returns:
|
|
74
76
|
None
|
|
75
77
|
"""
|
|
76
78
|
print("Select the new endpoint for the patient:")
|
|
77
|
-
for
|
|
78
|
-
print("{0}. {1}".format(
|
|
79
|
+
for index, (key, details) in enumerate(endpoints_config.items(), 1):
|
|
80
|
+
print("{0}. {1}".format(index, details['name']))
|
|
79
81
|
|
|
80
82
|
def get_new_endpoint_choice():
|
|
81
83
|
"""
|
|
82
84
|
Gets the user's choice for a new endpoint.
|
|
83
85
|
"""
|
|
84
|
-
return input("Select
|
|
86
|
+
return input("Select desired endpoint (e.g. 1, 2): ").strip()
|
|
85
87
|
|
|
86
88
|
def display_patient_summaries(detailed_patient_data):
|
|
87
89
|
"""
|
|
@@ -103,7 +105,7 @@ def ask_for_proceeding_with_endpoints():
|
|
|
103
105
|
|
|
104
106
|
def display_file_summary(index, summary):
|
|
105
107
|
# Ensure surgery_date is converted to a datetime object
|
|
106
|
-
surgery_date = datetime.
|
|
108
|
+
surgery_date = datetime.strptime(summary['surgery_date'], "%m-%d-%y")
|
|
107
109
|
|
|
108
110
|
# Displays the summary of a file.
|
|
109
111
|
print("{:02d}. {:5} (ID: {:<8}) {:20} {:15} Suggested Endpoint: {}".format(
|