medicafe 0.240809.0__py3-none-any.whl → 0.241015.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 +73 -16
- MediBot/MediBot.py +90 -79
- MediBot/MediBot_Crosswalk_Library.py +496 -194
- MediBot/MediBot_Preprocessor.py +22 -14
- MediBot/MediBot_Preprocessor_lib.py +299 -153
- 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 +93 -51
- MediLink/MediLink_837p_encoder.py +23 -23
- MediLink/MediLink_837p_encoder_library.py +141 -96
- MediLink/MediLink_API_Generator.py +1 -7
- MediLink/MediLink_API_v3.py +241 -59
- MediLink/MediLink_APIs.py +1 -2
- MediLink/MediLink_ClaimStatus.py +21 -6
- MediLink/MediLink_ConfigLoader.py +8 -8
- MediLink/MediLink_DataMgmt.py +321 -100
- MediLink/MediLink_Decoder.py +249 -87
- MediLink/MediLink_Deductible.py +7 -8
- MediLink/MediLink_Down.py +115 -120
- MediLink/MediLink_Gmail.py +7 -16
- MediLink/MediLink_Parser.py +63 -36
- MediLink/MediLink_UI.py +29 -24
- MediLink/MediLink_Up.py +12 -8
- {medicafe-0.240809.0.dist-info → medicafe-0.241015.0.dist-info}/METADATA +1 -1
- medicafe-0.241015.0.dist-info/RECORD +47 -0
- {medicafe-0.240809.0.dist-info → medicafe-0.241015.0.dist-info}/WHEEL +1 -1
- medicafe-0.240809.0.dist-info/RECORD +0 -47
- {medicafe-0.240809.0.dist-info → medicafe-0.241015.0.dist-info}/LICENSE +0 -0
- {medicafe-0.240809.0.dist-info → medicafe-0.241015.0.dist-info}/top_level.txt +0 -0
MediBot/MediBot.bat
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
|
+
::MediBot.bat
|
|
1
2
|
@echo off
|
|
2
3
|
setlocal enabledelayedexpansion
|
|
3
4
|
|
|
4
5
|
:: Define paths
|
|
5
6
|
set "source_folder=C:\MEDIANSI\MediCare"
|
|
7
|
+
set "local_storage_path=F:\Medibot\DOWNLOADS"
|
|
6
8
|
set "target_folder=C:\MEDIANSI\MediCare\CSV"
|
|
7
9
|
set "config_file=F:\Medibot\json\config.json"
|
|
8
10
|
set "python_script=C:\Python34\Lib\site-packages\MediBot\update_json.py"
|
|
@@ -64,17 +66,17 @@ if not exist "%config_file%" (
|
|
|
64
66
|
|
|
65
67
|
:: Check if the file exists and attempt to move it
|
|
66
68
|
:: Implementing a check with copy as a fallback if move fails
|
|
67
|
-
echo Checking for the
|
|
68
|
-
if exist "C:\Python34\Lib\site-packages\MediBot\
|
|
69
|
-
echo Found
|
|
70
|
-
move "C:\Python34\Lib\site-packages\MediBot\
|
|
69
|
+
echo Checking for the update script...
|
|
70
|
+
if exist "C:\Python34\Lib\site-packages\MediBot\update_medicafe.py" (
|
|
71
|
+
echo Found update_medicafe.py. Attempting to move...
|
|
72
|
+
move "C:\Python34\Lib\site-packages\MediBot\update_medicafe.py" "F:\Medibot\update_medicafe.py" >nul 2>&1
|
|
71
73
|
if %errorlevel% neq 0 (
|
|
72
74
|
echo Move failed. Attempting copy and delete as fallback...
|
|
73
|
-
copy "C:\Python34\Lib\site-packages\MediBot\
|
|
75
|
+
copy "C:\Python34\Lib\site-packages\MediBot\update_medicafe.py" "F:\Medibot\update_medicafe.py" >nul 2>&1
|
|
74
76
|
if %errorlevel% neq 0 (
|
|
75
77
|
echo Copy failed. Error Level: %errorlevel%
|
|
76
78
|
) else (
|
|
77
|
-
del "C:\Python34\Lib\site-packages\MediBot\
|
|
79
|
+
del "C:\Python34\Lib\site-packages\MediBot\update_medicafe.py" >nul 2>&1
|
|
78
80
|
if %errorlevel% neq 0 (
|
|
79
81
|
echo Delete failed. Manual cleanup may be required.
|
|
80
82
|
) else (
|
|
@@ -85,26 +87,38 @@ if exist "C:\Python34\Lib\site-packages\MediBot\upgrade_medicafe.py" (
|
|
|
85
87
|
echo File moved successfully.
|
|
86
88
|
)
|
|
87
89
|
) else (
|
|
88
|
-
echo
|
|
90
|
+
echo update_medicafe.py not detected. Checking for existing update_medicafe.py in F:\Medibot...
|
|
91
|
+
if exist "F:\Medibot\update_medicafe.py" (
|
|
92
|
+
echo update_medicafe.py already exists in F:\Medibot. No action needed.
|
|
93
|
+
) else (
|
|
94
|
+
echo update_medicafe.py not detected in either location. Check path and filename.
|
|
95
|
+
)
|
|
89
96
|
)
|
|
90
97
|
|
|
91
98
|
:: Main menu
|
|
92
99
|
:main_menu
|
|
93
100
|
cls
|
|
94
|
-
echo
|
|
101
|
+
echo Version: %medicafe_version%
|
|
95
102
|
echo --------------------------------------------------------------
|
|
96
103
|
echo .//* Welcome to MediCafe *\\.
|
|
97
104
|
echo --------------------------------------------------------------
|
|
98
105
|
echo.
|
|
99
106
|
echo Please select an option:
|
|
107
|
+
echo.
|
|
100
108
|
if "!internet_available!"=="1" (
|
|
101
|
-
echo 1.
|
|
109
|
+
echo 1. Update MediCafe
|
|
110
|
+
echo.
|
|
102
111
|
echo 2. Download Email de Carol
|
|
112
|
+
echo.
|
|
103
113
|
echo 3. MediLink Claims
|
|
104
|
-
echo
|
|
105
|
-
echo
|
|
114
|
+
echo.
|
|
115
|
+
echo 4. ^[United^] Claims Status
|
|
116
|
+
echo.
|
|
117
|
+
echo 5. ^[United^] Deductible
|
|
118
|
+
echo.
|
|
106
119
|
)
|
|
107
120
|
echo 6. Run MediBot
|
|
121
|
+
echo.
|
|
108
122
|
echo 7. Exit
|
|
109
123
|
echo.
|
|
110
124
|
set /p choice=Enter your choice:
|
|
@@ -124,11 +138,12 @@ if "!internet_available!"=="0" (
|
|
|
124
138
|
goto main_menu
|
|
125
139
|
)
|
|
126
140
|
echo Checking for MediCafe package updates. Please wait...
|
|
127
|
-
start cmd /c py "%upgrade_medicafe%" > upgrade_log.txt 2>&1 && (
|
|
141
|
+
start "Medicafe Update" cmd /c py "%upgrade_medicafe%" %package_version% > upgrade_log.txt 2>&1 && (
|
|
128
142
|
echo %DATE% %TIME% Upgrade initiated. >> "%temp_file%"
|
|
129
143
|
echo Exiting batch to complete the upgrade.
|
|
130
144
|
) || (
|
|
131
145
|
echo %DATE% %TIME% Update failed. Check logs. >> upgrade_log.txt
|
|
146
|
+
echo Upgrade failed. Check upgrade_log.txt for details.
|
|
132
147
|
)
|
|
133
148
|
exit /b
|
|
134
149
|
|
|
@@ -200,8 +215,23 @@ if errorlevel 1 echo Failed to check United Deductible.
|
|
|
200
215
|
pause
|
|
201
216
|
goto main_menu
|
|
202
217
|
|
|
203
|
-
:: Process CSV Files
|
|
218
|
+
:: Process CSV Files and Validate Against Config
|
|
204
219
|
:process_csvs
|
|
220
|
+
|
|
221
|
+
:: Move CSV files from local_storage_path to source_folder in case AK sends it unencrypted by accident.
|
|
222
|
+
echo Checking for new CSV files in local storage...
|
|
223
|
+
for %%f in ("%local_storage_path%\*.csv") do (
|
|
224
|
+
echo WARNING: Found unencrypted CSV files!
|
|
225
|
+
echo Moving %%f to %source_folder%...
|
|
226
|
+
move "%%f" "%source_folder%" >nul 2>&1
|
|
227
|
+
if errorlevel 1 (
|
|
228
|
+
echo Failed to move %%f. Check permissions or path.
|
|
229
|
+
) else (
|
|
230
|
+
echo Moved %%f successfully.
|
|
231
|
+
)
|
|
232
|
+
)
|
|
233
|
+
|
|
234
|
+
:: Retrieve the current time and date to create a timestamp
|
|
205
235
|
for /f "tokens=1-5 delims=/: " %%a in ('echo %time%') do (
|
|
206
236
|
set "hour=%%a"
|
|
207
237
|
set "minute=%%b"
|
|
@@ -214,19 +244,46 @@ for /f "tokens=2-4 delims=/ " %%a in ('echo %date%') do (
|
|
|
214
244
|
)
|
|
215
245
|
set "timestamp=!year!!month!!day!_!hour!!minute!"
|
|
216
246
|
|
|
247
|
+
:: Search for the most recent CSV file in source folder
|
|
217
248
|
set "latest_csv="
|
|
218
249
|
for /f "delims=" %%a in ('dir /b /a-d /o-d "%source_folder%\*.csv" 2^>nul') do (
|
|
219
250
|
set "latest_csv=%%a"
|
|
220
251
|
echo Found New CSV Files...
|
|
221
252
|
goto process_found_csv
|
|
222
253
|
)
|
|
223
|
-
::echo CSV Check Complete.
|
|
224
254
|
goto :eof
|
|
225
255
|
|
|
226
256
|
:process_found_csv
|
|
227
|
-
echo
|
|
257
|
+
echo Validating latest CSV with config file...
|
|
258
|
+
:: Run Python script to get current CSV path from JSON
|
|
259
|
+
for /f "delims=" %%a in ('python "%python_script%" "%config_file%"') do (
|
|
260
|
+
set "current_csv=%%a"
|
|
261
|
+
)
|
|
262
|
+
|
|
263
|
+
:: Extract filenames from paths
|
|
264
|
+
for %%f in ("!current_csv!") do set "current_csv_name=%%~nxf"
|
|
265
|
+
for %%f in ("%target_folder%\!latest_csv!") do set "latest_csv_name=%%~nxf"
|
|
266
|
+
|
|
267
|
+
:: Compare the paths and prompt user if necessary
|
|
268
|
+
if not "!current_csv_name!"=="!latest_csv_name!" (
|
|
269
|
+
echo ALERT: Config file CSV path differs from the latest CSV. This can happen if a new CSV is downloaded.
|
|
270
|
+
echo Current CSV: !current_csv_name!
|
|
271
|
+
echo Latest CSV: !latest_csv_name!
|
|
272
|
+
set /p update_choice="Do you want to update to the latest CSV? (Y/N): "
|
|
273
|
+
if /i "!update_choice!"=="Y" (
|
|
274
|
+
echo Updating config file with latest CSV...
|
|
275
|
+
py "%python_script%" "%config_file%" "%target_folder%\!latest_csv!"
|
|
276
|
+
echo Config file updated.
|
|
277
|
+
) else (
|
|
278
|
+
echo Using existing CSV path from config.
|
|
279
|
+
)
|
|
280
|
+
) else (
|
|
281
|
+
echo CSV path in config matches the latest CSV.
|
|
282
|
+
)
|
|
283
|
+
|
|
228
284
|
move "%source_folder%\!latest_csv!" "%target_folder%\SX_CSV_!timestamp!.csv"
|
|
229
285
|
set "new_csv_path=%target_folder%\SX_CSV_!timestamp!.csv"
|
|
286
|
+
echo Processing CSV...
|
|
230
287
|
py "%python_script%" "%config_file%" "!new_csv_path!"
|
|
231
288
|
echo CSV Processor Complete...
|
|
232
289
|
goto :eof
|
|
@@ -235,4 +292,4 @@ goto :eof
|
|
|
235
292
|
:end_script
|
|
236
293
|
echo Exiting MediCafe.
|
|
237
294
|
pause
|
|
238
|
-
exit /b
|
|
295
|
+
exit /b
|
MediBot/MediBot.py
CHANGED
|
@@ -1,8 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
import os
|
|
3
|
-
import tempfile
|
|
4
|
-
import traceback
|
|
5
|
-
import re #for addresses
|
|
1
|
+
#MediBot.py
|
|
2
|
+
import subprocess, os, tempfile, traceback, re, sys
|
|
6
3
|
from collections import OrderedDict
|
|
7
4
|
import MediBot_dataformat_library
|
|
8
5
|
import MediBot_Preprocessor
|
|
@@ -10,7 +7,6 @@ from MediBot_Preprocessor_lib import initialize, AHK_EXECUTABLE, CSV_FILE_PATH,
|
|
|
10
7
|
from MediBot_UI import app_control, manage_script_pause, user_interaction
|
|
11
8
|
|
|
12
9
|
# Add parent directory of the project to the Python path
|
|
13
|
-
import sys
|
|
14
10
|
project_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))
|
|
15
11
|
sys.path.append(project_dir)
|
|
16
12
|
|
|
@@ -22,6 +18,18 @@ except ImportError:
|
|
|
22
18
|
from MediBot import MediBot_Crosswalk_Library
|
|
23
19
|
crosswalk_update = MediBot_Crosswalk_Library.crosswalk_update
|
|
24
20
|
|
|
21
|
+
try:
|
|
22
|
+
from MediLink.MediLink_API_v3 import APIClient
|
|
23
|
+
except ImportError as e:
|
|
24
|
+
raise ImportError("Failed to import APIClient from MediLink.MediLink_API_v3. "
|
|
25
|
+
"Ensure the MediLink_API_v3 module is installed and accessible.") from e
|
|
26
|
+
|
|
27
|
+
# After successful import
|
|
28
|
+
try:
|
|
29
|
+
api_client = APIClient() # Pass necessary arguments if required
|
|
30
|
+
except Exception as e:
|
|
31
|
+
raise RuntimeError("Failed to instantiate APIClient. Ensure correct initialization parameters.") from e
|
|
32
|
+
|
|
25
33
|
def identify_field(header, field_mapping):
|
|
26
34
|
for medisoft_field, patterns in field_mapping.items():
|
|
27
35
|
for pattern in patterns:
|
|
@@ -34,30 +42,29 @@ def identify_field(header, field_mapping):
|
|
|
34
42
|
|
|
35
43
|
# Function to execute an AutoHotkey script
|
|
36
44
|
def run_ahk_script(script_content):
|
|
37
|
-
temp_script_name = None
|
|
45
|
+
temp_script_name = None # Initialize variable to hold the name of the temporary script file
|
|
38
46
|
try:
|
|
39
47
|
# Create a temporary AHK script file
|
|
40
|
-
with tempfile.NamedTemporaryFile(delete=False, suffix='.ahk') as temp_script:
|
|
41
|
-
temp_script_name = temp_script.name
|
|
42
|
-
temp_script.write(script_content
|
|
43
|
-
temp_script.flush()
|
|
48
|
+
with tempfile.NamedTemporaryFile(mode='w', delete=False, suffix='.ahk', encoding='utf-8') as temp_script:
|
|
49
|
+
temp_script_name = temp_script.name # Store the name of the temporary script file
|
|
50
|
+
temp_script.write(script_content) # Write the script content to the temporary file
|
|
51
|
+
temp_script.flush() # Ensure the file is written to disk
|
|
44
52
|
# Attempt to run the AHK script
|
|
45
|
-
subprocess.check_call([AHK_EXECUTABLE, temp_script_name])
|
|
53
|
+
subprocess.check_call([AHK_EXECUTABLE, temp_script_name]) # Execute the AHK script using the AutoHotkey executable
|
|
46
54
|
except subprocess.CalledProcessError as e:
|
|
47
|
-
|
|
48
|
-
print("AHK script
|
|
49
|
-
print("Output from AHK script:", e.output)
|
|
55
|
+
print("AHK script failed with exit status: {}".format(e.returncode)) # Log the exit status of the failed script
|
|
56
|
+
print("Output from AHK script: {}".format(e.output)) # Log the output from the failed script
|
|
50
57
|
except Exception as e:
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
traceback.print_exc() # Print the stack trace of the exception
|
|
58
|
+
print("An unexpected error occurred while running the AHK script: {}".format(e)) # Log any unexpected errors
|
|
59
|
+
traceback.print_exc() # Print the full traceback for debugging purposes
|
|
54
60
|
finally:
|
|
55
61
|
# Delete the temporary script file
|
|
56
62
|
if temp_script_name:
|
|
57
63
|
try:
|
|
58
|
-
os.unlink(temp_script_name)
|
|
64
|
+
os.unlink(temp_script_name) # Attempt to delete the temporary script file
|
|
59
65
|
except OSError as e:
|
|
60
|
-
print("Error deleting temporary script file:"
|
|
66
|
+
print("Error deleting temporary script file: {}".format(e)) # Log any errors encountered while deleting the file
|
|
67
|
+
# Future Improvement: Implement a cleanup mechanism to handle orphaned temporary files
|
|
61
68
|
|
|
62
69
|
# Global variable to store the last processed entry
|
|
63
70
|
last_processed_entry = None
|
|
@@ -68,23 +75,35 @@ def process_field(medisoft_field, csv_row, parsed_address_components, reverse_ma
|
|
|
68
75
|
global last_processed_entry
|
|
69
76
|
|
|
70
77
|
try:
|
|
71
|
-
value
|
|
72
|
-
if medisoft_field in parsed_address_components
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
78
|
+
# Attempt to retrieve the value for the current medisoft_field from parsed_address_components
|
|
79
|
+
value = parsed_address_components.get(medisoft_field, '') if medisoft_field in parsed_address_components else ''
|
|
80
|
+
|
|
81
|
+
# If no value is found, check if there is a fixed value available for this field
|
|
82
|
+
if not value:
|
|
83
|
+
if medisoft_field in fixed_values:
|
|
84
|
+
value = fixed_values[medisoft_field][0] # Use the fixed value if available
|
|
85
|
+
|
|
86
|
+
# If still no value, check if the field is present in the reverse mapping
|
|
87
|
+
if not value and medisoft_field in reverse_mapping:
|
|
88
|
+
# Retrieve the corresponding CSV header from the reverse mapping
|
|
79
89
|
csv_header = reverse_mapping[medisoft_field]
|
|
80
|
-
value = csv_row.get(csv_header, '')
|
|
90
|
+
value = csv_row.get(csv_header, '') # Get the value from the CSV row using the header
|
|
91
|
+
|
|
92
|
+
# Log the detected field and its value after assignment
|
|
93
|
+
MediLink_ConfigLoader.log("Detected {}: {}".format(medisoft_field, value), level="DEBUG")
|
|
81
94
|
|
|
82
|
-
|
|
95
|
+
# Format the value for the AutoHotkey script, or default to sending an Enter key if no value is found
|
|
96
|
+
formatted_value = (MediBot_dataformat_library.format_data(medisoft_field, value, csv_data, reverse_mapping, parsed_address_components)
|
|
97
|
+
if value else 'Send, {Enter}')
|
|
98
|
+
|
|
99
|
+
# Execute the AutoHotkey script with the formatted value
|
|
83
100
|
run_ahk_script(formatted_value)
|
|
84
101
|
|
|
102
|
+
# Update the last processed entry with the current field and its value
|
|
85
103
|
last_processed_entry = (medisoft_field, value)
|
|
86
|
-
return 'continue', last_processed_entry
|
|
104
|
+
return 'continue', last_processed_entry # Indicate to continue processing
|
|
87
105
|
except Exception as e:
|
|
106
|
+
# Handle any exceptions that occur during processing
|
|
88
107
|
return handle_error(e, medisoft_field, last_processed_entry, csv_data)
|
|
89
108
|
|
|
90
109
|
def handle_error(error, medisoft_field, last_processed_entry, csv_data):
|
|
@@ -176,23 +195,38 @@ class ExecutionState:
|
|
|
176
195
|
def __init__(self, config_path, crosswalk_path) -> None:
|
|
177
196
|
try:
|
|
178
197
|
config, crosswalk = MediLink_ConfigLoader.load_configuration(config_path, crosswalk_path)
|
|
198
|
+
MediLink_ConfigLoader.log("Loaded configuration: {}".format(config), level="DEBUG")
|
|
199
|
+
MediLink_ConfigLoader.log("Loaded crosswalk: {}".format(crosswalk), level="DEBUG")
|
|
179
200
|
self.verify_config_type(config)
|
|
180
201
|
self.crosswalk = crosswalk
|
|
181
202
|
self.config = config
|
|
182
203
|
MediLink_ConfigLoader.log("Config loaded successfully...")
|
|
204
|
+
|
|
205
|
+
# Instantiate APIClient
|
|
206
|
+
self.api_client = APIClient() # Pass required arguments if any
|
|
207
|
+
|
|
208
|
+
# Simplified isinstance check
|
|
209
|
+
if not isinstance(self.api_client, APIClient):
|
|
210
|
+
raise TypeError("MediBot Error: api_client must be an instance of APIClient.")
|
|
183
211
|
|
|
184
|
-
crosswalk_update
|
|
185
|
-
MediLink_ConfigLoader.log("
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
212
|
+
# Log before calling crosswalk_update
|
|
213
|
+
MediLink_ConfigLoader.log("Updating crosswalk with client and config...", level="INFO")
|
|
214
|
+
update_successful = crosswalk_update(self.api_client, config, crosswalk) # Ensure crosswalk_update uses the instance. TODO We need an internet-disabled version of this.
|
|
215
|
+
if update_successful:
|
|
216
|
+
MediLink_ConfigLoader.log("Crosswalk update completed successfully.", level="INFO")
|
|
217
|
+
print("Crosswalk update completed successfully.")
|
|
218
|
+
else:
|
|
219
|
+
MediLink_ConfigLoader.log("Crosswalk update failed.", level="ERROR")
|
|
220
|
+
print("Crosswalk update failed.")
|
|
221
|
+
|
|
190
222
|
except Exception as e:
|
|
223
|
+
MediLink_ConfigLoader.log("MediBot: Failed to load or update configuration: {}".format(e), level="ERROR")
|
|
191
224
|
print("MediBot: Failed to load or update configuration: {}".format(e))
|
|
192
|
-
raise
|
|
225
|
+
raise # Re-throwing the exception or using a more sophisticated error handling mechanism might be needed
|
|
193
226
|
# Handle the exception somehow (e.g., retry, halt, log)??
|
|
194
227
|
|
|
195
228
|
def verify_config_type(self, config):
|
|
229
|
+
MediLink_ConfigLoader.log("Verifying configuration type: {}".format(type(config)), level="DEBUG")
|
|
196
230
|
if not isinstance(config, (dict, OrderedDict)):
|
|
197
231
|
raise TypeError("Error: Configuration must be a dictionary or an OrderedDict. Check unpacking.")
|
|
198
232
|
|
|
@@ -201,19 +235,13 @@ if __name__ == "__main__":
|
|
|
201
235
|
e_state = None
|
|
202
236
|
try:
|
|
203
237
|
print("Please wait...")
|
|
204
|
-
# Default paths
|
|
238
|
+
# Default paths for configuration and crosswalk files
|
|
205
239
|
default_config_path = os.path.join(os.path.dirname(__file__), '..', 'json', 'config.json')
|
|
206
240
|
default_crosswalk_path = os.path.join(os.path.dirname(__file__), '..', 'json', 'crosswalk.json')
|
|
207
241
|
|
|
208
|
-
#
|
|
209
|
-
if len(sys.argv) > 1
|
|
210
|
-
|
|
211
|
-
config_path = sys.argv[1]
|
|
212
|
-
crosswalk_path = sys.argv[2] if len(sys.argv) > 2 else default_crosswalk_path
|
|
213
|
-
else:
|
|
214
|
-
# If no arguments are provided, use default paths
|
|
215
|
-
config_path = default_config_path
|
|
216
|
-
crosswalk_path = default_crosswalk_path
|
|
242
|
+
# Determine paths based on command-line arguments or use defaults
|
|
243
|
+
config_path = sys.argv[1] if len(sys.argv) > 1 else default_config_path
|
|
244
|
+
crosswalk_path = sys.argv[2] if len(sys.argv) > 2 else default_crosswalk_path
|
|
217
245
|
|
|
218
246
|
e_state = ExecutionState(config_path, crosswalk_path)
|
|
219
247
|
|
|
@@ -221,37 +249,34 @@ if __name__ == "__main__":
|
|
|
221
249
|
MediLink_ConfigLoader.log("Loading CSV Data...", level="INFO")
|
|
222
250
|
csv_data = load_csv_data(CSV_FILE_PATH)
|
|
223
251
|
|
|
224
|
-
# Pre-process CSV data to add combined fields & crosswalk values
|
|
252
|
+
# Pre-process CSV data to add combined fields & crosswalk values
|
|
225
253
|
print("Pre-Processing CSV...")
|
|
226
254
|
MediLink_ConfigLoader.log("Pre-processing CSV Data...", level="INFO")
|
|
227
255
|
MediBot_Preprocessor.preprocess_csv_data(csv_data, e_state.crosswalk)
|
|
228
|
-
headers = csv_data[0].keys()
|
|
229
|
-
# Patient charges should be added prior to the intake_scan.
|
|
256
|
+
headers = csv_data[0].keys() # Ensure all headers are in place
|
|
230
257
|
|
|
231
258
|
print("Performing Intake Scan...")
|
|
232
259
|
MediLink_ConfigLoader.log("Performing Intake Scan...", level="INFO")
|
|
233
|
-
# identified_fields is an OrderedDict
|
|
234
260
|
identified_fields = MediBot_Preprocessor.intake_scan(headers, field_mapping)
|
|
235
261
|
|
|
236
262
|
# Reverse the identified_fields mapping for lookup
|
|
237
263
|
reverse_mapping = {v: k for k, v in identified_fields.items()}
|
|
238
|
-
|
|
239
|
-
|
|
264
|
+
|
|
240
265
|
# CSV Patient Triage
|
|
241
266
|
interaction_mode = 'triage' # Start in triage mode
|
|
242
267
|
error_message = "" # This will be filled if an error has occurred
|
|
243
|
-
#print("Debug - Identified fields mapping (main): {}".format(identified_fields)) # Debug Line
|
|
244
268
|
|
|
245
269
|
print("Load Complete...")
|
|
270
|
+
MediLink_ConfigLoader.log("Load Complete event triggered. Clearing console. Displaying Menu...", level="INFO")
|
|
246
271
|
_ = os.system('cls')
|
|
247
272
|
|
|
248
273
|
proceed, selected_patient_ids, selected_indices, fixed_values = user_interaction(csv_data, interaction_mode, error_message, reverse_mapping)
|
|
249
274
|
|
|
250
275
|
if proceed:
|
|
251
|
-
# Filter csv_data for selected patients from Triage mode
|
|
276
|
+
# Filter csv_data for selected patients from Triage mode
|
|
252
277
|
csv_data = [row for index, row in enumerate(csv_data) if index in selected_indices]
|
|
253
278
|
|
|
254
|
-
# Check if MAPAT_MED_PATH is missing or
|
|
279
|
+
# Check if MAPAT_MED_PATH is missing or invalid
|
|
255
280
|
if not app_control.get_mapat_med_path() or not os.path.exists(app_control.get_mapat_med_path()):
|
|
256
281
|
print("Warning: MAPAT.MED PATH is missing or invalid. Please check the path configuration.")
|
|
257
282
|
|
|
@@ -260,9 +285,8 @@ if __name__ == "__main__":
|
|
|
260
285
|
|
|
261
286
|
if existing_patients:
|
|
262
287
|
print("\nNOTE: The following patient(s) already EXIST in the system and \n will be excluded from processing:")
|
|
263
|
-
|
|
264
|
-
#
|
|
265
|
-
# Find the corresponding rows in csv_data to get the surgery dates and store them along with patient info
|
|
288
|
+
|
|
289
|
+
# Collect surgery dates and patient info for existing patients
|
|
266
290
|
patient_info = []
|
|
267
291
|
for patient_id, patient_name in existing_patients:
|
|
268
292
|
surgery_date = next((row.get('Surgery Date', 'Unknown Date') for row in csv_data if row.get(reverse_mapping['Patient ID #2']) == patient_id), 'Unknown Date')
|
|
@@ -273,37 +297,25 @@ if __name__ == "__main__":
|
|
|
273
297
|
|
|
274
298
|
# Print the sorted patient info
|
|
275
299
|
for index, (surgery_date, patient_name, patient_id) in enumerate(patient_info):
|
|
276
|
-
print("{
|
|
300
|
+
print("{:03d}: {} (ID: {}) {}".format(index + 1, surgery_date.strftime('%m-%d'), patient_id, patient_name))
|
|
277
301
|
|
|
278
302
|
# Update csv_data to exclude existing patients
|
|
279
|
-
# TODO
|
|
303
|
+
# TODO: Update this logic to handle patients that exist but need new charges added.
|
|
280
304
|
csv_data = [row for row in csv_data if row[reverse_mapping['Patient ID #2']] in patients_to_process]
|
|
281
305
|
else:
|
|
282
306
|
print("\nSelected patient(s) are NEW patients and will be processed.")
|
|
283
307
|
|
|
308
|
+
# Check if there are patients left to process
|
|
284
309
|
if len(patients_to_process) == 0:
|
|
285
310
|
proceed = input("\nAll patients have been processed. Continue anyway?: ").lower().strip() in ['yes', 'y']
|
|
286
311
|
else:
|
|
287
312
|
proceed = input("\nDo you want to proceed with the {} remaining patient(s)? (yes/no): ".format(len(patients_to_process))).lower().strip() in ['yes', 'y']
|
|
288
313
|
|
|
289
|
-
# TODO Here is where we need to add the step where we move to MediBot_Charges.
|
|
290
|
-
# The return is an enriched dataset to be picked up by
|
|
314
|
+
# TODO: Here is where we need to add the step where we move to MediBot_Charges.
|
|
315
|
+
# The return is an enriched dataset to be picked up by MediBot which means we need to return:
|
|
291
316
|
# csv_data, field_mapping, reverse_mapping, and fixed_values.
|
|
292
317
|
|
|
293
318
|
if proceed:
|
|
294
|
-
|
|
295
|
-
# Would be nice to have some kind of self-test here.
|
|
296
|
-
# print("\nDebug - Starting AHK script. Reload AHK if failed...")
|
|
297
|
-
# try:
|
|
298
|
-
# subprocess.call([AHK_EXECUTABLE, r"G:\My Drive\CocoWave\XP typing bot\notepad_test.ahk"])
|
|
299
|
-
# run_ahk_script('MsgBox, Test AHK Script Execution')
|
|
300
|
-
# except subprocess.CalledProcessError as e:
|
|
301
|
-
# print("Error running AHK script. Please reload AHK and try again. Error: {}".format(e))
|
|
302
|
-
# exit(1)
|
|
303
|
-
# except Exception as e:
|
|
304
|
-
# print("An unexpected error occurred while running the AHK script: {}".format(e))
|
|
305
|
-
# exit(1)
|
|
306
|
-
|
|
307
319
|
print("\nRemember, when in Medisoft:")
|
|
308
320
|
print(" Press 'F8' to create a New Patient.")
|
|
309
321
|
print(" Press 'F12' to begin data entry.")
|
|
@@ -321,9 +333,8 @@ if __name__ == "__main__":
|
|
|
321
333
|
if e_state:
|
|
322
334
|
interaction_mode = 'error' # Switch to error mode
|
|
323
335
|
error_message = str(e) # Capture the error message
|
|
324
|
-
print("An error occurred while running MediBot: {
|
|
336
|
+
print("An error occurred while running MediBot: {}".format(e))
|
|
325
337
|
# Handle the error by calling user interaction with the error information
|
|
326
|
-
# Ensure that identified_fields is defined before using it in user interaction
|
|
327
338
|
if 'identified_fields' in locals():
|
|
328
339
|
_ = user_interaction(csv_data, interaction_mode, error_message, reverse_mapping)
|
|
329
340
|
else:
|