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
MediBot/MediBot.bat
CHANGED
|
@@ -8,63 +8,199 @@ set "config_file=F:\Medibot\json\config.json"
|
|
|
8
8
|
set "python_script=C:\Python34\Lib\site-packages\MediBot\update_json.py"
|
|
9
9
|
set "python_script2=C:\Python34\Lib\site-packages\MediBot\Medibot.py"
|
|
10
10
|
set "medicafe_package=medicafe"
|
|
11
|
-
set "upgrade_medicafe=F:\Medibot\
|
|
12
|
-
|
|
13
|
-
|
|
11
|
+
set "upgrade_medicafe=F:\Medibot\update_medicafe.py"
|
|
12
|
+
set "temp_file=F:\Medibot\last_update_timestamp.txt"
|
|
13
|
+
set "firefox_path=C:\Program Files\Mozilla Firefox\firefox.exe"
|
|
14
|
+
set "package_version="
|
|
14
15
|
set PYTHONWARNINGS=ignore
|
|
15
16
|
|
|
16
|
-
::
|
|
17
|
-
|
|
17
|
+
:: Check if Python is installed and the path is correctly set
|
|
18
|
+
python --version >nul 2>&1
|
|
19
|
+
if %errorlevel% neq 0 (
|
|
20
|
+
echo Python is not installed or not added to PATH.
|
|
21
|
+
exit /b
|
|
22
|
+
)
|
|
18
23
|
|
|
19
|
-
:: Check
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
+
:: Check if the MediCafe package is installed and retrieve its version
|
|
25
|
+
echo Checking for installed MediCafe package version...
|
|
26
|
+
python -c "import pkg_resources; print('MediCafe=='+pkg_resources.get_distribution('medicafe').version)" > temp.txt 2>nul
|
|
27
|
+
set /p package_version=<temp.txt
|
|
28
|
+
del temp.txt
|
|
29
|
+
|
|
30
|
+
if not defined package_version (
|
|
31
|
+
echo MediCafe package version not detected or MediCafe not installed. Consider manual re-install.
|
|
32
|
+
exit /b
|
|
24
33
|
)
|
|
25
34
|
|
|
26
|
-
::
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
35
|
+
:: Extract version number and display it
|
|
36
|
+
for /f "tokens=2 delims==" %%a in ("%package_version%") do (
|
|
37
|
+
set "medicafe_version=%%a"
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
if not defined medicafe_version (
|
|
41
|
+
echo Failed to detect MediCafe version.
|
|
42
|
+
) else (
|
|
43
|
+
echo Detected MediCafe version: %medicafe_version%
|
|
32
44
|
)
|
|
33
45
|
|
|
34
|
-
|
|
46
|
+
:: Check for internet connectivity
|
|
47
|
+
ping -n 1 google.com > nul 2>&1
|
|
48
|
+
if %ERRORLEVEL% neq 0 (
|
|
49
|
+
set "internet_available=0"
|
|
50
|
+
echo No internet connection detected.
|
|
51
|
+
) else (
|
|
52
|
+
set "internet_available=1"
|
|
53
|
+
echo Internet connection detected.
|
|
54
|
+
)
|
|
35
55
|
|
|
36
|
-
::
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
56
|
+
:: Common pre-menu setup
|
|
57
|
+
echo Setting up the environment...
|
|
58
|
+
if not exist "%config_file%" (
|
|
59
|
+
echo Configuration file missing.
|
|
60
|
+
goto end_script
|
|
40
61
|
)
|
|
41
62
|
|
|
42
|
-
::
|
|
43
|
-
|
|
63
|
+
:: Check if the file exists and attempt to move it
|
|
64
|
+
:: Implementing a check with copy as a fallback if move fails
|
|
65
|
+
echo Checking for the upgrade script...
|
|
66
|
+
if exist "C:\Python34\Lib\site-packages\MediBot\upgrade_medicafe.py" (
|
|
67
|
+
echo Found upgrade_medicafe.py. Attempting to move...
|
|
68
|
+
move "C:\Python34\Lib\site-packages\MediBot\upgrade_medicafe.py" "F:\Medibot\upgrade_medicafe.py" >nul 2>&1
|
|
69
|
+
if %errorlevel% neq 0 (
|
|
70
|
+
echo Move failed. Attempting copy and delete as fallback...
|
|
71
|
+
copy "C:\Python34\Lib\site-packages\MediBot\upgrade_medicafe.py" "F:\Medibot\upgrade_medicafe.py" >nul 2>&1
|
|
72
|
+
if %errorlevel% neq 0 (
|
|
73
|
+
echo Copy failed. Error Level: %errorlevel%
|
|
74
|
+
) else (
|
|
75
|
+
del "C:\Python34\Lib\site-packages\MediBot\upgrade_medicafe.py" >nul 2>&1
|
|
76
|
+
if %errorlevel% neq 0 (
|
|
77
|
+
echo Delete failed. Manual cleanup may be required.
|
|
78
|
+
) else (
|
|
79
|
+
echo File copied and original deleted successfully.
|
|
80
|
+
)
|
|
81
|
+
)
|
|
82
|
+
) else (
|
|
83
|
+
echo File moved successfully.
|
|
84
|
+
)
|
|
85
|
+
) else (
|
|
86
|
+
echo upgrade_medicafe.py not detected. Check path and filename.
|
|
87
|
+
)
|
|
44
88
|
|
|
45
|
-
::
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
89
|
+
:: Main menu
|
|
90
|
+
:main_menu
|
|
91
|
+
cls
|
|
92
|
+
echo version: %medicafe_version%
|
|
93
|
+
echo --------------------------------------------------------------
|
|
94
|
+
echo .//* Welcome to MediCafe *\\.
|
|
95
|
+
echo --------------------------------------------------------------
|
|
96
|
+
echo.
|
|
97
|
+
echo Please select an option:
|
|
98
|
+
if "!internet_available!"=="1" (
|
|
99
|
+
echo 1. Check for MediCafe Package Updates
|
|
100
|
+
echo 2. Download Email de Carol
|
|
101
|
+
echo 3. MediLink Claims
|
|
102
|
+
)
|
|
103
|
+
echo 4. Run MediBot
|
|
104
|
+
echo 5. Exit
|
|
105
|
+
echo.
|
|
106
|
+
set /p choice=Enter your choice:
|
|
107
|
+
|
|
108
|
+
if "!choice!"=="5" goto end_script
|
|
109
|
+
if "!choice!"=="4" goto medibot_flow
|
|
110
|
+
if "!choice!"=="3" goto medilink_flow
|
|
111
|
+
if "!choice!"=="2" goto download_emails
|
|
112
|
+
if "!choice!"=="1" goto check_updates
|
|
113
|
+
|
|
114
|
+
:: Medicafe Update
|
|
115
|
+
:check_updates
|
|
116
|
+
if "!internet_available!"=="0" (
|
|
117
|
+
echo No internet connection available.
|
|
118
|
+
goto main_menu
|
|
50
119
|
)
|
|
51
|
-
|
|
120
|
+
echo Checking for MediCafe package updates. Please wait...
|
|
121
|
+
start cmd /c py "%upgrade_medicafe%" > upgrade_log.txt 2>&1 && (
|
|
122
|
+
echo %DATE% %TIME% Upgrade initiated. >> "%temp_file%"
|
|
123
|
+
echo Exiting batch to complete the upgrade.
|
|
124
|
+
) || (
|
|
125
|
+
echo %DATE% %TIME% Update failed. Check logs. >> upgrade_log.txt
|
|
126
|
+
)
|
|
127
|
+
exit /b
|
|
52
128
|
|
|
53
|
-
::
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
129
|
+
:: Download Carol's Emails
|
|
130
|
+
:download_emails
|
|
131
|
+
if "!internet_available!"=="0" (
|
|
132
|
+
echo No internet connection available.
|
|
133
|
+
goto main_menu
|
|
134
|
+
)
|
|
135
|
+
echo Downloading emails...
|
|
136
|
+
:: move this path.
|
|
137
|
+
py "../MediLink/MediLink_Gmail.py" "%firefox_path%"
|
|
138
|
+
if errorlevel 1 (
|
|
139
|
+
echo Failed to download emails.
|
|
140
|
+
pause
|
|
57
141
|
) else (
|
|
58
|
-
|
|
142
|
+
echo Calling CSV Processor...
|
|
143
|
+
call :process_csvs
|
|
59
144
|
)
|
|
145
|
+
goto main_menu
|
|
60
146
|
|
|
147
|
+
:: Run MediBot Flow
|
|
148
|
+
:medibot_flow
|
|
149
|
+
call :process_csvs
|
|
150
|
+
cls
|
|
61
151
|
echo Please wait...
|
|
152
|
+
py "%python_script2%" "%config_file%"
|
|
153
|
+
if errorlevel 1 echo Failed to run MediBot.
|
|
154
|
+
pause
|
|
155
|
+
goto main_menu
|
|
62
156
|
|
|
63
|
-
::
|
|
64
|
-
|
|
157
|
+
:: Continue to MediLink
|
|
158
|
+
:medilink_flow
|
|
159
|
+
if "!internet_available!"=="0" (
|
|
160
|
+
echo No internet connection available.
|
|
161
|
+
goto main_menu
|
|
162
|
+
)
|
|
163
|
+
call :process_csvs
|
|
164
|
+
cls
|
|
165
|
+
:: move this path.
|
|
166
|
+
py "C:\Python34\Lib\site-packages\MediLink\MediLink.py"
|
|
167
|
+
if errorlevel 1 echo MediLink failed to execute.
|
|
168
|
+
pause
|
|
169
|
+
goto main_menu
|
|
65
170
|
|
|
66
|
-
::
|
|
67
|
-
|
|
171
|
+
:: Process CSV Files
|
|
172
|
+
:process_csvs
|
|
173
|
+
for /f "tokens=1-5 delims=/: " %%a in ('echo %time%') do (
|
|
174
|
+
set "hour=%%a"
|
|
175
|
+
set "minute=%%b"
|
|
176
|
+
set "second=%%c"
|
|
177
|
+
)
|
|
178
|
+
for /f "tokens=2-4 delims=/ " %%a in ('echo %date%') do (
|
|
179
|
+
set "day=%%a"
|
|
180
|
+
set "month=%%b"
|
|
181
|
+
set "year=%%c"
|
|
182
|
+
)
|
|
183
|
+
set "timestamp=!year!!month!!day!_!hour!!minute!"
|
|
184
|
+
|
|
185
|
+
set "latest_csv="
|
|
186
|
+
for /f "delims=" %%a in ('dir /b /a-d /o-d "%source_folder%\*.csv" 2^>nul') do (
|
|
187
|
+
set "latest_csv=%%a"
|
|
188
|
+
echo Found New CSV Files...
|
|
189
|
+
goto process_found_csv
|
|
190
|
+
)
|
|
191
|
+
::echo CSV Check Complete.
|
|
192
|
+
goto :eof
|
|
193
|
+
|
|
194
|
+
:process_found_csv
|
|
195
|
+
echo Processing CSVs...
|
|
196
|
+
move "%source_folder%\!latest_csv!" "%target_folder%\SX_CSV_!timestamp!.csv"
|
|
197
|
+
set "new_csv_path=%target_folder%\SX_CSV_!timestamp!.csv"
|
|
198
|
+
py "%python_script%" "%config_file%" "!new_csv_path!"
|
|
199
|
+
echo CSV Processor Complete...
|
|
200
|
+
goto :eof
|
|
68
201
|
|
|
202
|
+
:: Exit Script
|
|
69
203
|
:end_script
|
|
204
|
+
echo Exiting MediCafe.
|
|
70
205
|
pause
|
|
206
|
+
exit /b
|
MediBot/MediBot.py
CHANGED
|
@@ -4,10 +4,10 @@ import tempfile
|
|
|
4
4
|
import traceback
|
|
5
5
|
import re #for addresses
|
|
6
6
|
from collections import OrderedDict
|
|
7
|
-
import MediBot_UI
|
|
8
7
|
import MediBot_dataformat_library
|
|
9
8
|
import MediBot_Preprocessor
|
|
10
|
-
from
|
|
9
|
+
from MediBot_Preprocessor_lib import initialize, AHK_EXECUTABLE, CSV_FILE_PATH, field_mapping, load_csv_data
|
|
10
|
+
from MediBot_UI import app_control, manage_script_pause, user_interaction
|
|
11
11
|
|
|
12
12
|
# Add parent directory of the project to the Python path
|
|
13
13
|
import sys
|
|
@@ -16,39 +16,11 @@ sys.path.append(project_dir)
|
|
|
16
16
|
|
|
17
17
|
from MediLink import MediLink_ConfigLoader
|
|
18
18
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
- [ ] Implement validation checks during patient data entry to prevent submission of incomplete or incorrect records.
|
|
25
|
-
|
|
26
|
-
Insurance Mode Adjustments
|
|
27
|
-
- [ ] Integrate a comprehensive list of insurance company codes for automatic selection.
|
|
28
|
-
- [ ] Automate insurance-specific data entry adjustments, such as character replacements specific to Medicare.
|
|
29
|
-
|
|
30
|
-
Diagnosis Entry
|
|
31
|
-
- [ ] Automate data extraction from Surgery Schedule to import to CSV a column indicating diagnosis code per px.
|
|
32
|
-
|
|
33
|
-
Script Efficiency and Reliability
|
|
34
|
-
- [ ] Ensure robust handling of Medisoft's field navigation quirks, particularly for fields that are skipped or require special access.
|
|
35
|
-
|
|
36
|
-
Documentation and Support
|
|
37
|
-
- [ ] Create detailed documentation for setup, configuration, and usage of the script.
|
|
38
|
-
- [ ] Establish a support channel for users to report issues or request features.
|
|
39
|
-
|
|
40
|
-
Future Directions
|
|
41
|
-
- [ ] Consider developing a graphical user interface (GUI) for non-technical users for easier script management and execution.
|
|
42
|
-
|
|
43
|
-
Medisoft Field Navigation:
|
|
44
|
-
Investigate and optimize navigation for fields that Medisoft skips or requires backward navigation to access.
|
|
45
|
-
|
|
46
|
-
Insurance Mode Features:
|
|
47
|
-
Evaluate the feasibility and implement the use of the F6 search for insurance address verification, enhancing user verification processes.
|
|
48
|
-
|
|
49
|
-
Error Handling and Logging:
|
|
50
|
-
Implement a check for AHK script execution status, providing feedback or troubleshooting steps if the script encounters issues.
|
|
51
|
-
"""
|
|
19
|
+
try:
|
|
20
|
+
from MediBot_Crosswalk_Library import crosswalk_update
|
|
21
|
+
except ImportError:
|
|
22
|
+
from MediBot import MediBot_Crosswalk_Library
|
|
23
|
+
crosswalk_update = MediBot_Crosswalk_Library.crosswalk_update
|
|
52
24
|
|
|
53
25
|
def identify_field(header, field_mapping):
|
|
54
26
|
for medisoft_field, patterns in field_mapping.items():
|
|
@@ -102,6 +74,8 @@ def process_field(medisoft_field, csv_row, parsed_address_components, reverse_ma
|
|
|
102
74
|
elif medisoft_field in fixed_values:
|
|
103
75
|
value = fixed_values[medisoft_field][0] # Use the fixed value
|
|
104
76
|
elif medisoft_field in reverse_mapping:
|
|
77
|
+
if medisoft_field == "Ins1 Insurance ID" or reverse_mapping[medisoft_field] == "Primary Insurance Company":
|
|
78
|
+
MediLink_ConfigLoader.log("Detected {} or {}: {}".format(medisoft_field, reverse_mapping[medisoft_field], value))
|
|
105
79
|
csv_header = reverse_mapping[medisoft_field]
|
|
106
80
|
value = csv_row.get(csv_header, '')
|
|
107
81
|
|
|
@@ -114,10 +88,11 @@ def process_field(medisoft_field, csv_row, parsed_address_components, reverse_ma
|
|
|
114
88
|
return handle_error(e, medisoft_field, last_processed_entry, csv_data)
|
|
115
89
|
|
|
116
90
|
def handle_error(error, medisoft_field, last_processed_entry, csv_data):
|
|
91
|
+
MediLink_ConfigLoader.log("Error in process_field: ", e)
|
|
117
92
|
print("An error occurred while processing {0}: {1}".format(medisoft_field, error))
|
|
118
93
|
# Assuming the interaction mode is 'error' in this case
|
|
119
94
|
interaction_mode = 'error'
|
|
120
|
-
response =
|
|
95
|
+
response = user_interaction(csv_data, interaction_mode, error, reverse_mapping)
|
|
121
96
|
return response, last_processed_entry
|
|
122
97
|
|
|
123
98
|
# iterating through each field defined in the field_mapping.
|
|
@@ -125,7 +100,7 @@ def iterate_fields(csv_row, field_mapping, parsed_address_components, reverse_ma
|
|
|
125
100
|
global last_processed_entry
|
|
126
101
|
# Check for user action at the start of each field processing
|
|
127
102
|
for medisoft_field in field_mapping.keys():
|
|
128
|
-
action =
|
|
103
|
+
action = manage_script_pause(csv_data,'',reverse_mapping) # per-field pause availability. Necessary to provide frequent opportunities for the user to pause the script.
|
|
129
104
|
if action != 0: # If action is either 'Retry' (-1) or 'Skip' (1)
|
|
130
105
|
return action # Break out and pass the action up
|
|
131
106
|
|
|
@@ -135,8 +110,8 @@ def iterate_fields(csv_row, field_mapping, parsed_address_components, reverse_ma
|
|
|
135
110
|
return 0 # Default action to continue
|
|
136
111
|
|
|
137
112
|
def data_entry_loop(csv_data, field_mapping, reverse_mapping, fixed_values):
|
|
138
|
-
global last_processed_entry, parsed_address_components
|
|
139
|
-
|
|
113
|
+
global last_processed_entry, parsed_address_components
|
|
114
|
+
# last_processed_entry, parsed_address_components = None, {} // BUG should this just be this line rather than the global line above?
|
|
140
115
|
error_message = '' # Initialize error_message once
|
|
141
116
|
current_row_index = 0
|
|
142
117
|
|
|
@@ -144,10 +119,10 @@ def data_entry_loop(csv_data, field_mapping, reverse_mapping, fixed_values):
|
|
|
144
119
|
row = csv_data[current_row_index]
|
|
145
120
|
|
|
146
121
|
# Handle script pause at the start of each row (patient record).
|
|
147
|
-
|
|
122
|
+
manage_script_pause(csv_data, error_message, reverse_mapping)
|
|
148
123
|
error_message = '' # Clear error message for the next iteration
|
|
149
124
|
|
|
150
|
-
if
|
|
125
|
+
if app_control.get_pause_status():
|
|
151
126
|
continue # Skip processing this row if the script is paused
|
|
152
127
|
|
|
153
128
|
# I feel like this is overwriting what would have already been idenfitied in the mapping.
|
|
@@ -157,12 +132,13 @@ def data_entry_loop(csv_data, field_mapping, reverse_mapping, fixed_values):
|
|
|
157
132
|
|
|
158
133
|
# Process each field in the row
|
|
159
134
|
action = iterate_fields(row, field_mapping, parsed_address_components, reverse_mapping, csv_data, fixed_values)
|
|
160
|
-
# TODO add a feature here where if you accidentally started overwriting a patient that you could go back 2 patients.
|
|
135
|
+
# TODO (Low) add a feature here where if you accidentally started overwriting a patient that you could go back 2 patients.
|
|
161
136
|
# Need to tell the user which patient we're talking about because it won't be obvious anymore.
|
|
162
137
|
if action == -1: # Retry
|
|
163
138
|
continue # Remain on the current row.
|
|
164
139
|
elif action == 1: # Skip
|
|
165
140
|
if current_row_index == len(csv_data) - 1: # If it's the last row
|
|
141
|
+
MediLink_ConfigLoader.log("Reached the end of the patient list.")
|
|
166
142
|
print("Reached the end of the patient list. Looping back to the beginning.")
|
|
167
143
|
current_row_index = 0 # Reset to the first row
|
|
168
144
|
else:
|
|
@@ -173,9 +149,8 @@ def data_entry_loop(csv_data, field_mapping, reverse_mapping, fixed_values):
|
|
|
173
149
|
continue
|
|
174
150
|
|
|
175
151
|
# Code to handle the end of a patient record
|
|
176
|
-
#
|
|
177
|
-
|
|
178
|
-
# Handle script pause at the end of each row (patient record).
|
|
152
|
+
# TODO One day this can just not pause...
|
|
153
|
+
app_control.set_pause_status(True) # Pause at the end of processing each patient record
|
|
179
154
|
current_row_index += 1 # Move to the next row by default
|
|
180
155
|
|
|
181
156
|
def open_medisoft(shortcut_path):
|
|
@@ -198,14 +173,24 @@ def cleanup():
|
|
|
198
173
|
pass
|
|
199
174
|
|
|
200
175
|
class ExecutionState:
|
|
201
|
-
def __init__(self) -> None:
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
176
|
+
def __init__(self, config_path, crosswalk_path) -> None:
|
|
177
|
+
try:
|
|
178
|
+
config, crosswalk = MediLink_ConfigLoader.load_configuration(config_path, crosswalk_path)
|
|
179
|
+
self.verify_config_type(config)
|
|
180
|
+
self.crosswalk = crosswalk
|
|
181
|
+
self.config = config
|
|
182
|
+
MediLink_ConfigLoader.log("Config loaded successfully...")
|
|
183
|
+
|
|
184
|
+
crosswalk_update(config, crosswalk)
|
|
185
|
+
MediLink_ConfigLoader.log("Crosswalk update complete...")
|
|
186
|
+
|
|
187
|
+
initialize(config)
|
|
188
|
+
MediLink_ConfigLoader.log("Constants initialized...")
|
|
189
|
+
|
|
190
|
+
except Exception as e:
|
|
191
|
+
print("MediBot: Failed to load or update configuration: {}".format(e))
|
|
192
|
+
raise # Re-throwing the exception or using a more sophisticated error handling mechanism might be needed
|
|
193
|
+
# Handle the exception somehow (e.g., retry, halt, log)??
|
|
209
194
|
|
|
210
195
|
def verify_config_type(self, config):
|
|
211
196
|
if not isinstance(config, (dict, OrderedDict)):
|
|
@@ -215,7 +200,8 @@ class ExecutionState:
|
|
|
215
200
|
if __name__ == "__main__":
|
|
216
201
|
e_state = None
|
|
217
202
|
try:
|
|
218
|
-
|
|
203
|
+
print("Please wait...")
|
|
204
|
+
# Default paths
|
|
219
205
|
default_config_path = os.path.join(os.path.dirname(__file__), '..', 'json', 'config.json')
|
|
220
206
|
default_crosswalk_path = os.path.join(os.path.dirname(__file__), '..', 'json', 'crosswalk.json')
|
|
221
207
|
|
|
@@ -229,39 +215,57 @@ if __name__ == "__main__":
|
|
|
229
215
|
config_path = default_config_path
|
|
230
216
|
crosswalk_path = default_crosswalk_path
|
|
231
217
|
|
|
232
|
-
e_state = ExecutionState()
|
|
218
|
+
e_state = ExecutionState(config_path, crosswalk_path)
|
|
233
219
|
|
|
234
|
-
|
|
235
|
-
|
|
220
|
+
print("Loading CSV Data...")
|
|
221
|
+
MediLink_ConfigLoader.log("Loading CSV Data...", level="INFO")
|
|
222
|
+
csv_data = load_csv_data(CSV_FILE_PATH)
|
|
236
223
|
|
|
237
|
-
#
|
|
238
|
-
|
|
239
|
-
|
|
224
|
+
# Pre-process CSV data to add combined fields & crosswalk values.
|
|
225
|
+
print("Pre-Processing CSV...")
|
|
226
|
+
MediLink_ConfigLoader.log("Pre-processing CSV Data...", level="INFO")
|
|
227
|
+
MediBot_Preprocessor.preprocess_csv_data(csv_data, e_state.crosswalk)
|
|
228
|
+
headers = csv_data[0].keys() # Make sure all the headers are in place
|
|
229
|
+
# Patient charges should be added prior to the intake_scan.
|
|
240
230
|
|
|
241
|
-
|
|
231
|
+
print("Performing Intake Scan...")
|
|
232
|
+
MediLink_ConfigLoader.log("Performing Intake Scan...", level="INFO")
|
|
242
233
|
# identified_fields is an OrderedDict
|
|
243
234
|
identified_fields = MediBot_Preprocessor.intake_scan(headers, field_mapping)
|
|
244
235
|
|
|
245
236
|
# Reverse the identified_fields mapping for lookup
|
|
246
237
|
reverse_mapping = {v: k for k, v in identified_fields.items()}
|
|
238
|
+
# MediLink_ConfigLoader.log("Reverse Mapping: {}".format(reverse_mapping))
|
|
247
239
|
|
|
248
240
|
# CSV Patient Triage
|
|
249
241
|
interaction_mode = 'triage' # Start in triage mode
|
|
250
242
|
error_message = "" # This will be filled if an error has occurred
|
|
251
243
|
#print("Debug - Identified fields mapping (main): {}".format(identified_fields)) # Debug Line
|
|
252
244
|
|
|
253
|
-
|
|
245
|
+
print("Load Complete...")
|
|
246
|
+
_ = os.system('cls')
|
|
247
|
+
|
|
248
|
+
proceed, selected_patient_ids, selected_indices, fixed_values = user_interaction(csv_data, interaction_mode, error_message, reverse_mapping)
|
|
254
249
|
|
|
255
250
|
if proceed:
|
|
256
251
|
# Filter csv_data for selected patients from Triage mode.
|
|
257
252
|
csv_data = [row for index, row in enumerate(csv_data) if index in selected_indices]
|
|
258
|
-
|
|
253
|
+
|
|
254
|
+
# Check if MAPAT_MED_PATH is missing or blank
|
|
255
|
+
if not app_control.get_mapat_med_path() or not os.path.exists(app_control.get_mapat_med_path()):
|
|
256
|
+
print("Warning: MAPAT.MED PATH is missing or invalid. Please check the path configuration.")
|
|
257
|
+
|
|
258
|
+
# Perform the existing patients check
|
|
259
|
+
existing_patients, patients_to_process = MediBot_Preprocessor.check_existing_patients(selected_patient_ids, app_control.get_mapat_med_path())
|
|
259
260
|
|
|
260
261
|
if existing_patients:
|
|
261
|
-
print("\nNOTE: The following patient(s) already EXIST in the system and \
|
|
262
|
+
print("\nNOTE: The following patient(s) already EXIST in the system and \n will be excluded from processing:")
|
|
263
|
+
# TODO ... not excluded anymore, because charges may need to be added.
|
|
264
|
+
# So at this point in the processing, we should have already processed the surgery schedules and enriched the data with Charges.
|
|
262
265
|
for patient_id, patient_name in existing_patients:
|
|
263
266
|
print("(ID: {0}) {1}".format(patient_id, patient_name))
|
|
264
267
|
# Update csv_data to exclude existing patients
|
|
268
|
+
# TODO This now has to be updated to handle patients that exist but need new charges added.
|
|
265
269
|
csv_data = [row for row in csv_data if row[reverse_mapping['Patient ID #2']] in patients_to_process]
|
|
266
270
|
else:
|
|
267
271
|
print("\nSelected patient(s) are NEW patients and will be processed.")
|
|
@@ -271,6 +275,10 @@ if __name__ == "__main__":
|
|
|
271
275
|
else:
|
|
272
276
|
proceed = input("\nDo you want to proceed with the {} remaining patient(s)? (yes/no): ".format(len(patients_to_process))).lower().strip() in ['yes', 'y']
|
|
273
277
|
|
|
278
|
+
# TODO Here is where we need to add the step where we move to MediBot_Charges.
|
|
279
|
+
# The return is an enriched dataset to be picked up by medibot which means we need to return:
|
|
280
|
+
# csv_data, field_mapping, reverse_mapping, and fixed_values.
|
|
281
|
+
|
|
274
282
|
if proceed:
|
|
275
283
|
|
|
276
284
|
# Would be nice to have some kind of self-test here.
|
|
@@ -290,27 +298,22 @@ if __name__ == "__main__":
|
|
|
290
298
|
print(" Press 'F12' to begin data entry.")
|
|
291
299
|
print(" Press 'F11' at any time to Pause.")
|
|
292
300
|
input("\n*** Press [Enter] when ready to begin! ***\n")
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
301
|
+
MediLink_ConfigLoader.log("Opening Medisoft...")
|
|
302
|
+
open_medisoft(app_control.get_medisoft_shortcut())
|
|
303
|
+
app_control.set_pause_status(True)
|
|
304
|
+
_ = manage_script_pause(csv_data, error_message, reverse_mapping)
|
|
296
305
|
data_entry_loop(csv_data, field_mapping, reverse_mapping, fixed_values)
|
|
297
306
|
cleanup()
|
|
298
307
|
else:
|
|
299
|
-
print("Data entry canceled by user.")
|
|
308
|
+
print("Data entry canceled by user. Exiting MediBot.")
|
|
300
309
|
except Exception as e:
|
|
301
310
|
if e_state:
|
|
302
311
|
interaction_mode = 'error' # Switch to error mode
|
|
303
312
|
error_message = str(e) # Capture the error message
|
|
304
|
-
print("An error occurred: {0}".format(e))
|
|
313
|
+
print("An error occurred while running MediBot: {0}".format(e))
|
|
305
314
|
# Handle the error by calling user interaction with the error information
|
|
306
315
|
# Ensure that identified_fields is defined before using it in user interaction
|
|
307
316
|
if 'identified_fields' in locals():
|
|
308
|
-
_ =
|
|
317
|
+
_ = user_interaction(csv_data, interaction_mode, error_message, reverse_mapping)
|
|
309
318
|
else:
|
|
310
|
-
print("Please ensure CSV headers match expected field names in config file, then re-run Medibot.")
|
|
311
|
-
|
|
312
|
-
# Performance: Process flow (25px - 13 min)
|
|
313
|
-
# 2:00 Internet connect & Email
|
|
314
|
-
# 6:00 6 px medicare
|
|
315
|
-
# 1:00 menu handling for privado
|
|
316
|
-
# 4:00 5 px privado
|
|
319
|
+
print("Please ensure CSV headers match expected field names in config file, then re-run Medibot.")
|
MediBot/MediBot_Charges.py
CHANGED
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
MediBot_Charges.py
|
|
3
|
-
|
|
4
|
-
This module provides a helper function for MediBot.py, specifically designed to handle the charge entry process in Medisoft for patients undergoing cataract surgeries. Each patient typically undergoes procedures on both eyes, treated as separate procedures but often requiring price bundling to address patient preferences for consistent billing across both eyes.
|
|
5
|
-
|
|
6
|
-
Key Features:
|
|
7
|
-
- Handles up to 200 patients in a single batch, with typical usage around 20 patients.
|
|
8
|
-
- Implements price bundling logic to ensure that if a patient has multiple procedures (one for each eye), the charges are balanced such that the total cost is evenly spread across both procedures. This approach aligns with patient expectations of receiving consistent charges for each eye.
|
|
9
|
-
- Integrates pricing schedules from a configuration file for private insurance, which vary based on the duration of the procedure:
|
|
10
|
-
- $450 for 1-15 minutes
|
|
11
|
-
- $480 for 16-22 minutes
|
|
12
|
-
- $510 for 23-27 minutes
|
|
13
|
-
- $540 for 28-37 minutes
|
|
14
|
-
- $580 for 37-59 minutes (59 minutes being the maximum allowed duration)
|
|
15
|
-
- Special handling for Medicare patients, details of which are pending clarification.
|
|
16
|
-
|
|
17
|
-
Limitations:
|
|
18
|
-
- The bundling logic for commercial insurance billing is subject to the fulfillment of deductibles and other conditions, which do not necessarily synchronize with the timing of procedures for both eyes. The exact mechanics of this bundling under various conditions remain partially unspecified.
|
|
19
|
-
|
|
20
|
-
Usage:
|
|
21
|
-
- This module is intended to be used as part of the MediBot system, interfaced through MediBot.py, to automate the data entry and billing process in Medisoft for ophthalmology clinics, specifically those performing cataract surgeries.
|
|
22
|
-
|
|
23
|
-
Note:
|
|
24
|
-
- The exact implementation details for Medicare patients and the full logic for price bundling under all insurance conditions are yet to be finalized and documented.
|
|
25
|
-
|
|
26
|
-
Date:
|
|
27
|
-
- 4/16/24
|
|
28
|
-
"""
|