medicafe 0.240517.0__py3-none-any.whl → 0.240716.2__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 +46 -6
- MediBot/MediBot.py +9 -36
- MediBot/MediBot_Charges.py +0 -28
- MediBot/MediBot_Crosswalk_Library.py +16 -8
- MediBot/MediBot_Post.py +0 -0
- MediBot/MediBot_Preprocessor.py +26 -63
- MediBot/MediBot_Preprocessor_lib.py +182 -43
- MediBot/MediBot_UI.py +2 -7
- MediBot/MediBot_dataformat_library.py +0 -9
- MediBot/MediBot_docx_decoder.py +283 -60
- MediLink/MediLink.py +80 -120
- MediLink/MediLink_837p_encoder.py +3 -28
- MediLink/MediLink_837p_encoder_library.py +19 -53
- MediLink/MediLink_API_Generator.py +246 -0
- MediLink/MediLink_API_v2.py +2 -0
- MediLink/MediLink_API_v3.py +325 -0
- MediLink/MediLink_APIs.py +2 -0
- MediLink/MediLink_ClaimStatus.py +144 -0
- MediLink/MediLink_ConfigLoader.py +13 -7
- MediLink/MediLink_DataMgmt.py +224 -68
- MediLink/MediLink_Decoder.py +165 -0
- MediLink/MediLink_Deductible.py +203 -0
- MediLink/MediLink_Down.py +122 -96
- MediLink/MediLink_Gmail.py +453 -74
- MediLink/MediLink_Mailer.py +0 -7
- MediLink/MediLink_Parser.py +193 -0
- MediLink/MediLink_Scan.py +0 -0
- MediLink/MediLink_Scheduler.py +2 -172
- MediLink/MediLink_StatusCheck.py +0 -4
- MediLink/MediLink_UI.py +54 -18
- MediLink/MediLink_Up.py +6 -15
- {medicafe-0.240517.0.dist-info → medicafe-0.240716.2.dist-info}/METADATA +4 -1
- medicafe-0.240716.2.dist-info/RECORD +47 -0
- {medicafe-0.240517.0.dist-info → medicafe-0.240716.2.dist-info}/WHEEL +1 -1
- medicafe-0.240517.0.dist-info/RECORD +0 -39
- {medicafe-0.240517.0.dist-info → medicafe-0.240716.2.dist-info}/LICENSE +0 -0
- {medicafe-0.240517.0.dist-info → medicafe-0.240716.2.dist-info}/top_level.txt +0 -0
MediBot/MediBot.bat
CHANGED
|
@@ -11,6 +11,8 @@ set "medicafe_package=medicafe"
|
|
|
11
11
|
set "upgrade_medicafe=F:\Medibot\update_medicafe.py"
|
|
12
12
|
set "temp_file=F:\Medibot\last_update_timestamp.txt"
|
|
13
13
|
set "firefox_path=C:\Program Files\Mozilla Firefox\firefox.exe"
|
|
14
|
+
set "claims_status_script=..\MediLink\MediLink_ClaimStatus.py"
|
|
15
|
+
set "deductible_script=..\MediLink\MediLink_Deductible.py"
|
|
14
16
|
set "package_version="
|
|
15
17
|
set PYTHONWARNINGS=ignore
|
|
16
18
|
|
|
@@ -99,14 +101,18 @@ if "!internet_available!"=="1" (
|
|
|
99
101
|
echo 1. Check for MediCafe Package Updates
|
|
100
102
|
echo 2. Download Email de Carol
|
|
101
103
|
echo 3. MediLink Claims
|
|
104
|
+
echo 4. United Claims Status
|
|
105
|
+
echo 5. United Deductible
|
|
102
106
|
)
|
|
103
|
-
echo
|
|
104
|
-
echo
|
|
107
|
+
echo 6. Run MediBot
|
|
108
|
+
echo 7. Exit
|
|
105
109
|
echo.
|
|
106
110
|
set /p choice=Enter your choice:
|
|
107
111
|
|
|
108
|
-
if "!choice!"=="
|
|
109
|
-
if "!choice!"=="
|
|
112
|
+
if "!choice!"=="7" goto end_script
|
|
113
|
+
if "!choice!"=="6" goto medibot_flow
|
|
114
|
+
if "!choice!"=="5" goto united_deductible
|
|
115
|
+
if "!choice!"=="4" goto united_claims_status
|
|
110
116
|
if "!choice!"=="3" goto medilink_flow
|
|
111
117
|
if "!choice!"=="2" goto download_emails
|
|
112
118
|
if "!choice!"=="1" goto check_updates
|
|
@@ -133,6 +139,7 @@ if "!internet_available!"=="0" (
|
|
|
133
139
|
goto main_menu
|
|
134
140
|
)
|
|
135
141
|
echo Downloading emails...
|
|
142
|
+
:: move this path.
|
|
136
143
|
py "../MediLink/MediLink_Gmail.py" "%firefox_path%"
|
|
137
144
|
if errorlevel 1 (
|
|
138
145
|
echo Failed to download emails.
|
|
@@ -161,11 +168,38 @@ if "!internet_available!"=="0" (
|
|
|
161
168
|
)
|
|
162
169
|
call :process_csvs
|
|
163
170
|
cls
|
|
171
|
+
:: move this path.
|
|
164
172
|
py "C:\Python34\Lib\site-packages\MediLink\MediLink.py"
|
|
165
173
|
if errorlevel 1 echo MediLink failed to execute.
|
|
166
174
|
pause
|
|
167
175
|
goto main_menu
|
|
168
176
|
|
|
177
|
+
:: United Claims Status
|
|
178
|
+
:united_claims_status
|
|
179
|
+
if "!internet_available!"=="0" (
|
|
180
|
+
echo No internet connection available.
|
|
181
|
+
goto main_menu
|
|
182
|
+
)
|
|
183
|
+
cls
|
|
184
|
+
echo Checking United Claims Status...
|
|
185
|
+
py "%claims_status_script%"
|
|
186
|
+
if errorlevel 1 echo Failed to check United Claims Status.
|
|
187
|
+
pause
|
|
188
|
+
goto main_menu
|
|
189
|
+
|
|
190
|
+
:: United Deductible
|
|
191
|
+
:united_deductible
|
|
192
|
+
if "!internet_available!"=="0" (
|
|
193
|
+
echo No internet connection available.
|
|
194
|
+
goto main_menu
|
|
195
|
+
)
|
|
196
|
+
cls
|
|
197
|
+
echo Checking United Deductible...
|
|
198
|
+
py "%deductible_script%"
|
|
199
|
+
if errorlevel 1 echo Failed to check United Deductible.
|
|
200
|
+
pause
|
|
201
|
+
goto main_menu
|
|
202
|
+
|
|
169
203
|
:: Process CSV Files
|
|
170
204
|
:process_csvs
|
|
171
205
|
for /f "tokens=1-5 delims=/: " %%a in ('echo %time%') do (
|
|
@@ -173,7 +207,13 @@ for /f "tokens=1-5 delims=/: " %%a in ('echo %time%') do (
|
|
|
173
207
|
set "minute=%%b"
|
|
174
208
|
set "second=%%c"
|
|
175
209
|
)
|
|
176
|
-
|
|
210
|
+
for /f "tokens=2-4 delims=/ " %%a in ('echo %date%') do (
|
|
211
|
+
set "day=%%a"
|
|
212
|
+
set "month=%%b"
|
|
213
|
+
set "year=%%c"
|
|
214
|
+
)
|
|
215
|
+
set "timestamp=!year!!month!!day!_!hour!!minute!"
|
|
216
|
+
|
|
177
217
|
set "latest_csv="
|
|
178
218
|
for /f "delims=" %%a in ('dir /b /a-d /o-d "%source_folder%\*.csv" 2^>nul') do (
|
|
179
219
|
set "latest_csv=%%a"
|
|
@@ -195,4 +235,4 @@ goto :eof
|
|
|
195
235
|
:end_script
|
|
196
236
|
echo Exiting MediCafe.
|
|
197
237
|
pause
|
|
198
|
-
exit /b
|
|
238
|
+
exit /b
|
MediBot/MediBot.py
CHANGED
|
@@ -22,41 +22,6 @@ except ImportError:
|
|
|
22
22
|
from MediBot import MediBot_Crosswalk_Library
|
|
23
23
|
crosswalk_update = MediBot_Crosswalk_Library.crosswalk_update
|
|
24
24
|
|
|
25
|
-
"""
|
|
26
|
-
# Development Task List for MediBot
|
|
27
|
-
|
|
28
|
-
Error Handling Improvements
|
|
29
|
-
- [ ] Its really difficult to get out of the main menu if you go open MediBot by accident
|
|
30
|
-
- [ ] Develop a centralized error handling and logging mechanism for improved troubleshooting.
|
|
31
|
-
- [ ] Implement validation checks during patient data entry to prevent submission of incomplete or incorrect records.
|
|
32
|
-
|
|
33
|
-
Insurance Mode Adjustments
|
|
34
|
-
- [ ] Integrate a comprehensive list of insurance company codes for automatic selection.
|
|
35
|
-
- [ ] Automate insurance-specific data entry adjustments, such as character replacements specific to Medicare.
|
|
36
|
-
|
|
37
|
-
Diagnosis Entry
|
|
38
|
-
- [ ] Automate data extraction from Surgery Schedule to import to CSV a column indicating diagnosis code per px.
|
|
39
|
-
|
|
40
|
-
Script Efficiency and Reliability
|
|
41
|
-
- [ ] Ensure robust handling of Medisoft's field navigation quirks, particularly for fields that are skipped or require special access.
|
|
42
|
-
|
|
43
|
-
Documentation and Support
|
|
44
|
-
- [ ] Create detailed documentation for setup, configuration, and usage of the script.
|
|
45
|
-
- [ ] Establish a support channel for users to report issues or request features.
|
|
46
|
-
|
|
47
|
-
Future Directions
|
|
48
|
-
- [ ] Consider developing a graphical user interface (GUI) for non-technical users for easier script management and execution.
|
|
49
|
-
|
|
50
|
-
Medisoft Field Navigation:
|
|
51
|
-
Investigate and optimize navigation for fields that Medisoft skips or requires backward navigation to access.
|
|
52
|
-
|
|
53
|
-
Insurance Mode Features:
|
|
54
|
-
Evaluate the feasibility and implement the use of the F6 search for insurance address verification, enhancing user verification processes.
|
|
55
|
-
|
|
56
|
-
Error Handling and Logging:
|
|
57
|
-
Implement a check for AHK script execution status, providing feedback or troubleshooting steps if the script encounters issues.
|
|
58
|
-
"""
|
|
59
|
-
|
|
60
25
|
def identify_field(header, field_mapping):
|
|
61
26
|
for medisoft_field, patterns in field_mapping.items():
|
|
62
27
|
for pattern in patterns:
|
|
@@ -223,7 +188,7 @@ class ExecutionState:
|
|
|
223
188
|
MediLink_ConfigLoader.log("Constants initialized...")
|
|
224
189
|
|
|
225
190
|
except Exception as e:
|
|
226
|
-
print("Failed to load or update configuration: {}".format(e))
|
|
191
|
+
print("MediBot: Failed to load or update configuration: {}".format(e))
|
|
227
192
|
raise # Re-throwing the exception or using a more sophisticated error handling mechanism might be needed
|
|
228
193
|
# Handle the exception somehow (e.g., retry, halt, log)??
|
|
229
194
|
|
|
@@ -261,6 +226,7 @@ if __name__ == "__main__":
|
|
|
261
226
|
MediLink_ConfigLoader.log("Pre-processing CSV Data...", level="INFO")
|
|
262
227
|
MediBot_Preprocessor.preprocess_csv_data(csv_data, e_state.crosswalk)
|
|
263
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.
|
|
264
230
|
|
|
265
231
|
print("Performing Intake Scan...")
|
|
266
232
|
MediLink_ConfigLoader.log("Performing Intake Scan...", level="INFO")
|
|
@@ -294,9 +260,12 @@ if __name__ == "__main__":
|
|
|
294
260
|
|
|
295
261
|
if existing_patients:
|
|
296
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.
|
|
297
265
|
for patient_id, patient_name in existing_patients:
|
|
298
266
|
print("(ID: {0}) {1}".format(patient_id, patient_name))
|
|
299
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.
|
|
300
269
|
csv_data = [row for row in csv_data if row[reverse_mapping['Patient ID #2']] in patients_to_process]
|
|
301
270
|
else:
|
|
302
271
|
print("\nSelected patient(s) are NEW patients and will be processed.")
|
|
@@ -306,6 +275,10 @@ if __name__ == "__main__":
|
|
|
306
275
|
else:
|
|
307
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']
|
|
308
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
|
+
|
|
309
282
|
if proceed:
|
|
310
283
|
|
|
311
284
|
# Would be nice to have some kind of self-test here.
|
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
|
-
"""
|
|
@@ -14,10 +14,10 @@ except ImportError:
|
|
|
14
14
|
from MediLink import MediLink_ConfigLoader
|
|
15
15
|
|
|
16
16
|
try:
|
|
17
|
-
from
|
|
17
|
+
from MediLink_API_v3 import fetch_payer_name_from_api
|
|
18
18
|
except ImportError:
|
|
19
|
-
from MediLink import
|
|
20
|
-
fetch_payer_name_from_api =
|
|
19
|
+
from MediLink import MediLink_API_v3
|
|
20
|
+
fetch_payer_name_from_api = MediLink_API_v3.fetch_payer_name_from_api
|
|
21
21
|
|
|
22
22
|
try:
|
|
23
23
|
from MediBot import MediBot_Preprocessor_lib
|
|
@@ -127,7 +127,7 @@ def initialize_crosswalk_from_mapat():
|
|
|
127
127
|
validate_and_correct_payer_ids(crosswalk, config)
|
|
128
128
|
|
|
129
129
|
# Save the initial crosswalk
|
|
130
|
-
if save_crosswalk(config
|
|
130
|
+
if save_crosswalk(config, crosswalk):
|
|
131
131
|
message = "Crosswalk initialized with mappings for {} payers.".format(len(crosswalk.get('payer_id', {})))
|
|
132
132
|
print(message)
|
|
133
133
|
MediLink_ConfigLoader.log(message, config, level="INFO")
|
|
@@ -167,6 +167,7 @@ def crosswalk_update(config, crosswalk):
|
|
|
167
167
|
|
|
168
168
|
# Load incremental mapping data from Z.dat (Patient ID to Insurance Name)
|
|
169
169
|
# TODO This may be a redundant approach?
|
|
170
|
+
# This is a singular path. This is fine though because any time we process a Z.DAT we'd have the crosswalk incremented.
|
|
170
171
|
patient_id_to_insurance_name = MediBot_Preprocessor_lib.parse_z_dat(config['MediLink_Config']['Z_DAT_PATH'], config['MediLink_Config'])
|
|
171
172
|
MediLink_ConfigLoader.log("Parsed Z data...")
|
|
172
173
|
|
|
@@ -196,7 +197,7 @@ def crosswalk_update(config, crosswalk):
|
|
|
196
197
|
crosswalk['payer_id'][payer_id]['medisoft_medicare_id'] = list(crosswalk['payer_id'][payer_id]['medisoft_medicare_id'])
|
|
197
198
|
|
|
198
199
|
# Save the updated crosswalk to the specified file
|
|
199
|
-
return save_crosswalk(config
|
|
200
|
+
return save_crosswalk(config, crosswalk)
|
|
200
201
|
|
|
201
202
|
def update_crosswalk_with_corrected_payer_id(old_payer_id, corrected_payer_id, config, crosswalk):
|
|
202
203
|
"""Updates the crosswalk with the corrected payer ID."""
|
|
@@ -215,7 +216,7 @@ def update_crosswalk_with_corrected_payer_id(old_payer_id, corrected_payer_id, c
|
|
|
215
216
|
MediLink_ConfigLoader.log("Crosswalk csv_replacements updated: added {} -> {}".format(old_payer_id, corrected_payer_id), config, level="INFO")
|
|
216
217
|
|
|
217
218
|
# Save the updated crosswalk
|
|
218
|
-
return save_crosswalk(config
|
|
219
|
+
return save_crosswalk(config, crosswalk)
|
|
219
220
|
|
|
220
221
|
def update_crosswalk_with_new_payer_id(insurance_name, payer_id, config):
|
|
221
222
|
"""Updates the crosswalk with a new payer ID."""
|
|
@@ -228,14 +229,14 @@ def update_crosswalk_with_new_payer_id(insurance_name, payer_id, config):
|
|
|
228
229
|
crosswalk['payer_id'][payer_id] = {"medisoft_id": [medisoft_id_str], "medisoft_medicare_id": []}
|
|
229
230
|
else:
|
|
230
231
|
crosswalk['payer_id'][payer_id]['medisoft_id'].append(medisoft_id_str)
|
|
231
|
-
save_crosswalk(config
|
|
232
|
+
save_crosswalk(config, crosswalk)
|
|
232
233
|
MediLink_ConfigLoader.log("Updated crosswalk with new payer ID {} for insurance name {}".format(payer_id, insurance_name), config, level="INFO")
|
|
233
234
|
else:
|
|
234
235
|
message = "Failed to update crosswalk: Medisoft ID not found for insurance name {}".format(insurance_name)
|
|
235
236
|
print(message)
|
|
236
237
|
MediLink_ConfigLoader.log(message, config, level="ERROR")
|
|
237
238
|
|
|
238
|
-
def save_crosswalk(
|
|
239
|
+
def save_crosswalk(config, crosswalk):
|
|
239
240
|
"""
|
|
240
241
|
Saves the updated crosswalk to a JSON file.
|
|
241
242
|
Args:
|
|
@@ -244,6 +245,13 @@ def save_crosswalk(crosswalk_path, crosswalk):
|
|
|
244
245
|
Returns:
|
|
245
246
|
bool: True if the file was successfully saved, False otherwise.
|
|
246
247
|
"""
|
|
248
|
+
# Attempt to fetch crosswalkPath from MediLink_Config
|
|
249
|
+
try:
|
|
250
|
+
crosswalk_path = config['MediLink_Config']['crosswalkPath']
|
|
251
|
+
except KeyError:
|
|
252
|
+
# If KeyError occurs, fall back to fetching crosswalkPath directly
|
|
253
|
+
crosswalk_path = config.get('crosswalkPath', None) # Replace None with a default value if needed
|
|
254
|
+
|
|
247
255
|
try:
|
|
248
256
|
# Initialize 'payer_id' key if not present
|
|
249
257
|
if 'payer_id' not in crosswalk:
|
MediBot/MediBot_Post.py
ADDED
|
File without changes
|
MediBot/MediBot_Preprocessor.py
CHANGED
|
@@ -20,61 +20,6 @@ try:
|
|
|
20
20
|
except ImportError:
|
|
21
21
|
from MediBot import MediBot_Preprocessor_lib
|
|
22
22
|
|
|
23
|
-
"""
|
|
24
|
-
Preprocessing Enhancements
|
|
25
|
-
- [X] Preprocess Insurance Policy Numbers and Group Numbers to replace '-' with ''.
|
|
26
|
-
- [X] De-duplicate entries in the CSV and only entering the px once even if they show up twice in the file.
|
|
27
|
-
- [ ] Implement dynamic field combination in CSV pre-processing for flexibility with various CSV formats.
|
|
28
|
-
- [ ] Enhance SSN cleaning logic to handle more variations of sensitive data masking.
|
|
29
|
-
- [ ] Optimize script startup and CSV loading to reduce initial latency.
|
|
30
|
-
|
|
31
|
-
Data Integrity and Validation
|
|
32
|
-
- [ ] Conduct a thorough CSV integrity check before processing to flag potential issues upfront.
|
|
33
|
-
- [ ] Implement a mechanism to confirm the accuracy of entered data, potentially through a verification step or summary report.
|
|
34
|
-
- [ ] Explore the possibility of integrating direct database queries for existing patient checks to streamline the process.
|
|
35
|
-
- [ ] Automate the replacement of spaces with underscores ('_') in last names for Medicare entries.
|
|
36
|
-
- [ ] Enhance CSV integrity checks to identify and report potential issues with data format, especially concerning insurance policy numbers and special character handling.
|
|
37
|
-
|
|
38
|
-
Known Issues and Bugs
|
|
39
|
-
- [ ] Address the handling of '.' and other special characters that may disrupt parsing, especially under Windows XP.
|
|
40
|
-
- [ ] Investigate the issue with Excel modifying long policy numbers in the CSV and provide guidance or a workaround.
|
|
41
|
-
|
|
42
|
-
Future Work
|
|
43
|
-
- [X] Check for PatientID number in La Forma Z to link back to Carol's table for mapping Medisoft insurance name to payerID and payer name and address.
|
|
44
|
-
- [X] Check for PatientID to Medisoft custom insurance name mapping in MAPAT.
|
|
45
|
-
- [X] Middle Names should all be single letters. Make sure it gets truncated before submitting.
|
|
46
|
-
- [ ] Consolidate data from multiple sources (Provider_Notes.csv, Surgery_Schedule.csv, and Carols_CSV.csv) into a single table with Patient ID as the key, ensuring all data elements are aligned and duplicate entries are minimized.
|
|
47
|
-
- [ ] Implement logic to verify and match Patient IDs across different files to ensure data integrity before consolidation. (Catching errors between source data)
|
|
48
|
-
- [ ] Optimize the preprocessing of surgery dates and diagnosis codes for use in patient billing and scheduling systems.
|
|
49
|
-
- [ ] Read Surgery Schedule doc and parse out a Patient ID : Diagnosis Code table.
|
|
50
|
-
- [ ] The Minutes & Cancellation data with logic to consolidate into one table in memory.
|
|
51
|
-
- [ ] Dynamically list the endpoint for a new Payer ID via API or user interaction to update the crosswalk.json efficiently.
|
|
52
|
-
- [ ] Pull listed addresses of insurance from the CSV. (Not really necessary)
|
|
53
|
-
- [ ] Retroactively learn Medisoft insurance name and payerID from the provided data sources.
|
|
54
|
-
|
|
55
|
-
Development Roadmap for crosswalk_update():
|
|
56
|
-
- [X] Automation required for updating the crosswalk.json when new Medisoft insurance is discovered.
|
|
57
|
-
- [X] New Medisoft insurances are identified based on the payer ID number.
|
|
58
|
-
- [X] Check the existence of the payer ID in crosswalk.json under existing endpoints.
|
|
59
|
-
- [X] Facilitate grouping of IDs for insurances like CIGNA with multiple addresses but few payer IDs.
|
|
60
|
-
- [X] Retroactive learning based on selected insurances in Medisoft
|
|
61
|
-
- [ ] Prompt user via endpoint APIs to add new payer ID to an endpoint if it does not exist.
|
|
62
|
-
- [ ] Retain payer IDs without Insurance ID for future assignments.
|
|
63
|
-
- [ ] Check for free payer IDs and determine the appropriate endpoint for assignment.
|
|
64
|
-
- [ ] Present unrecognized payer IDs with Carol's Insurance Name to users for assignment to Insurance ID. (Try API Call)
|
|
65
|
-
- [ ] Integrate API checks to verify payer ID availability and related information.
|
|
66
|
-
- [ ] Implement "Fax/Mail or Other" endpoint for unavailable payer IDs.
|
|
67
|
-
- [ ] Present user with a list of top insurances for selection based on fuzzy search scores.
|
|
68
|
-
- [ ] Establish payer ID to insurance ID relationship based on user selection.
|
|
69
|
-
- [ ] Implicitly establish payer ID to endpoint mapping based on user selection.
|
|
70
|
-
- [ ] Implement validation mechanisms to prevent incorrect mappings and ensure data integrity.
|
|
71
|
-
- [ ] Considerations for extracting insurance addresses (if necessary)
|
|
72
|
-
- [ ] Handle better the case where a payer_id doesn't exist (When Carol's CSV doesn't bring the Payer ID).
|
|
73
|
-
Maybe ask the user what the payer ID is for that patient? I dont know.
|
|
74
|
-
- [ ] TODO (MED) Crosswalk (both initializing and updating) needs to pull AFTER the Preprocessor for Carol's CSV because
|
|
75
|
-
all that data lives in-memory and then gets corrections or replacements before being used so we need
|
|
76
|
-
the post-correction data to be used to build and update the crosswalk.
|
|
77
|
-
"""
|
|
78
23
|
# Load configuration
|
|
79
24
|
# Should this also take args? Path for ./MediLink needed to be added for this to resolve
|
|
80
25
|
config, crosswalk = MediLink_ConfigLoader.load_configuration()
|
|
@@ -82,10 +27,11 @@ config, crosswalk = MediLink_ConfigLoader.load_configuration()
|
|
|
82
27
|
# CSV Preprocessor built for Carol
|
|
83
28
|
def preprocess_csv_data(csv_data, crosswalk):
|
|
84
29
|
try:
|
|
85
|
-
# Add the "Ins1 Insurance ID"
|
|
86
|
-
# This initializes the
|
|
87
|
-
|
|
88
|
-
|
|
30
|
+
# Add the "Ins1 Insurance ID" and "Default Diagnosis #1" columns to the CSV data.
|
|
31
|
+
# This initializes the columns with empty values for each row.
|
|
32
|
+
columns_to_add = ['Ins1 Insurance ID', 'Default Diagnosis #1', 'Procedure Code', 'Minutes', 'Amount']
|
|
33
|
+
MediLink_ConfigLoader.log("CSV Pre-processor: Initializing empty columns to the CSV data...", level="INFO")
|
|
34
|
+
MediBot_Preprocessor_lib.add_columns(csv_data, columns_to_add)
|
|
89
35
|
|
|
90
36
|
# Filter out rows without a Patient ID and rows where the Primary Insurance
|
|
91
37
|
# is 'AETNA', 'AETNA MEDICARE', or 'HUMANA MED HMO'.
|
|
@@ -93,13 +39,20 @@ def preprocess_csv_data(csv_data, crosswalk):
|
|
|
93
39
|
MediBot_Preprocessor_lib.filter_rows(csv_data)
|
|
94
40
|
|
|
95
41
|
# Convert 'Surgery Date' from string format to datetime objects for sorting purposes.
|
|
96
|
-
|
|
97
|
-
|
|
42
|
+
MediBot_Preprocessor_lib.convert_surgery_date(csv_data)
|
|
43
|
+
|
|
98
44
|
# Update the CSV data to include only unique patient records.
|
|
99
45
|
# Re-sort the CSV data after deduplication to ensure the correct order.
|
|
46
|
+
# Sort the patients by 'Surgery Date' and then by 'Patient Last' name alphabetically.
|
|
47
|
+
# Deduplicate patient records based on Patient ID, keeping the entry with the earliest surgery date.
|
|
100
48
|
MediLink_ConfigLoader.log("CSV Pre-processor: Sorting and de-duplicating patient records...", level="INFO")
|
|
101
|
-
MediBot_Preprocessor_lib.
|
|
102
|
-
|
|
49
|
+
MediBot_Preprocessor_lib.sort_and_deduplicate(csv_data)
|
|
50
|
+
# TODO This eventually needs to be handled differently because now we're wanting to handle both surgery dates.
|
|
51
|
+
# Instead of deleting, maybe we need to make a secondary dataset or some kind of flag or isolate here where
|
|
52
|
+
# MediBot knows to skip it when entering the patient data but is ready to put Charges for the second surgery date.
|
|
53
|
+
# MediLink_Scheduler will have a dictionary persist somewhere that would tell us which patients were billed
|
|
54
|
+
# and which haven't been yet. So, if the patient 'exists' in the system, the next quetion is about claims/billing status.
|
|
55
|
+
# Eventually, we really want to get out of Medisoft...
|
|
103
56
|
|
|
104
57
|
# Convert 'Surgery Date' back to string format if needed for further processing.
|
|
105
58
|
# Combine 'Patient First', 'Patient Middle', and 'Patient Last' into a single 'Patient Name' field.
|
|
@@ -117,6 +70,16 @@ def preprocess_csv_data(csv_data, crosswalk):
|
|
|
117
70
|
# If the Payer ID is not found in the crosswalk, create a placeholder entry in the crosswalk and mark the row for review.
|
|
118
71
|
MediLink_ConfigLoader.log("CSV Pre-processor: Populating 'Ins1 Insurance ID' based on Crosswalk...", level="INFO")
|
|
119
72
|
MediBot_Preprocessor_lib.update_insurance_ids(csv_data, crosswalk)
|
|
73
|
+
|
|
74
|
+
# Enrich the "Default Diagnosis #1" column based on the parsed docx for each row.
|
|
75
|
+
# This needs to handle the different patient dates correctly so we get the right diagnosis code assigned to the right patient on the right date of service.
|
|
76
|
+
# Currently, we've deleted all the second date entries for patients. As long as they exist in the system, they're just deleted.
|
|
77
|
+
MediLink_ConfigLoader.log("CSV Pre-processor: Populating 'Default Diagnosis #1' based on Surgery Schedule and Crosswalk...", level="INFO")
|
|
78
|
+
MediBot_Preprocessor_lib.update_diagnosis_codes(csv_data)
|
|
79
|
+
|
|
80
|
+
# Enrich the procedure code column based on the diagnosis code for each patient.
|
|
81
|
+
MediLink_ConfigLoader.log("CSV Pre-processor: Populating 'Procedure Code' based on Crosswalk...", level="INFO")
|
|
82
|
+
MediBot_Preprocessor_lib.update_procedure_codes(csv_data)
|
|
120
83
|
|
|
121
84
|
except Exception as e:
|
|
122
85
|
message = "An error occurred while pre-processing CSV data. Please repair the CSV directly and try again: {}".format(e)
|