medicafe 0.250725.8__tar.gz → 0.250725.10__tar.gz
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.
- {medicafe-0.250725.8 → medicafe-0.250725.10}/MediBot/MediBot.py +1 -35
- {medicafe-0.250725.8 → medicafe-0.250725.10}/MediBot/MediBot_UI.py +326 -408
- {medicafe-0.250725.8 → medicafe-0.250725.10}/PKG-INFO +1 -1
- {medicafe-0.250725.8 → medicafe-0.250725.10}/medicafe.egg-info/PKG-INFO +1 -1
- {medicafe-0.250725.8 → medicafe-0.250725.10}/setup.py +1 -1
- {medicafe-0.250725.8 → medicafe-0.250725.10}/LICENSE +0 -0
- {medicafe-0.250725.8 → medicafe-0.250725.10}/MANIFEST.in +0 -0
- {medicafe-0.250725.8 → medicafe-0.250725.10}/MediBot/MediBot.bat +0 -0
- {medicafe-0.250725.8 → medicafe-0.250725.10}/MediBot/MediBot_Charges.py +0 -0
- {medicafe-0.250725.8 → medicafe-0.250725.10}/MediBot/MediBot_Crosswalk_Library.py +0 -0
- {medicafe-0.250725.8 → medicafe-0.250725.10}/MediBot/MediBot_Post.py +0 -0
- {medicafe-0.250725.8 → medicafe-0.250725.10}/MediBot/MediBot_Preprocessor.py +0 -0
- {medicafe-0.250725.8 → medicafe-0.250725.10}/MediBot/MediBot_Preprocessor_lib.py +0 -0
- {medicafe-0.250725.8 → medicafe-0.250725.10}/MediBot/MediBot_dataformat_library.py +0 -0
- {medicafe-0.250725.8 → medicafe-0.250725.10}/MediBot/MediBot_docx_decoder.py +0 -0
- {medicafe-0.250725.8 → medicafe-0.250725.10}/MediBot/PDF_to_CSV_Cleaner.py +0 -0
- {medicafe-0.250725.8 → medicafe-0.250725.10}/MediBot/__init__.py +0 -0
- {medicafe-0.250725.8 → medicafe-0.250725.10}/MediBot/update_json.py +0 -0
- {medicafe-0.250725.8 → medicafe-0.250725.10}/MediBot/update_medicafe.py +0 -0
- {medicafe-0.250725.8 → medicafe-0.250725.10}/MediLink/MediLink.py +0 -0
- {medicafe-0.250725.8 → medicafe-0.250725.10}/MediLink/MediLink_837p_cob_library.py +0 -0
- {medicafe-0.250725.8 → medicafe-0.250725.10}/MediLink/MediLink_837p_encoder.py +0 -0
- {medicafe-0.250725.8 → medicafe-0.250725.10}/MediLink/MediLink_837p_encoder_library.py +0 -0
- {medicafe-0.250725.8 → medicafe-0.250725.10}/MediLink/MediLink_837p_utilities.py +0 -0
- {medicafe-0.250725.8 → medicafe-0.250725.10}/MediLink/MediLink_API_Generator.py +0 -0
- {medicafe-0.250725.8 → medicafe-0.250725.10}/MediLink/MediLink_API_v2.py +0 -0
- {medicafe-0.250725.8 → medicafe-0.250725.10}/MediLink/MediLink_API_v3.py +0 -0
- {medicafe-0.250725.8 → medicafe-0.250725.10}/MediLink/MediLink_APIs.py +0 -0
- {medicafe-0.250725.8 → medicafe-0.250725.10}/MediLink/MediLink_Azure.py +0 -0
- {medicafe-0.250725.8 → medicafe-0.250725.10}/MediLink/MediLink_ClaimStatus.py +0 -0
- {medicafe-0.250725.8 → medicafe-0.250725.10}/MediLink/MediLink_ConfigLoader.py +0 -0
- {medicafe-0.250725.8 → medicafe-0.250725.10}/MediLink/MediLink_DataMgmt.py +0 -0
- {medicafe-0.250725.8 → medicafe-0.250725.10}/MediLink/MediLink_Decoder.py +0 -0
- {medicafe-0.250725.8 → medicafe-0.250725.10}/MediLink/MediLink_Deductible.py +0 -0
- {medicafe-0.250725.8 → medicafe-0.250725.10}/MediLink/MediLink_Deductible_Validator.py +0 -0
- {medicafe-0.250725.8 → medicafe-0.250725.10}/MediLink/MediLink_Down.py +0 -0
- {medicafe-0.250725.8 → medicafe-0.250725.10}/MediLink/MediLink_Gmail.py +0 -0
- {medicafe-0.250725.8 → medicafe-0.250725.10}/MediLink/MediLink_GraphQL.py +0 -0
- {medicafe-0.250725.8 → medicafe-0.250725.10}/MediLink/MediLink_Mailer.py +0 -0
- {medicafe-0.250725.8 → medicafe-0.250725.10}/MediLink/MediLink_Parser.py +0 -0
- {medicafe-0.250725.8 → medicafe-0.250725.10}/MediLink/MediLink_Scan.py +0 -0
- {medicafe-0.250725.8 → medicafe-0.250725.10}/MediLink/MediLink_Scheduler.py +0 -0
- {medicafe-0.250725.8 → medicafe-0.250725.10}/MediLink/MediLink_UI.py +0 -0
- {medicafe-0.250725.8 → medicafe-0.250725.10}/MediLink/MediLink_Up.py +0 -0
- {medicafe-0.250725.8 → medicafe-0.250725.10}/MediLink/MediLink_batch.bat +0 -0
- {medicafe-0.250725.8 → medicafe-0.250725.10}/MediLink/Soumit_api.py +0 -0
- {medicafe-0.250725.8 → medicafe-0.250725.10}/MediLink/__init__.py +0 -0
- {medicafe-0.250725.8 → medicafe-0.250725.10}/MediLink/openssl.cnf +0 -0
- {medicafe-0.250725.8 → medicafe-0.250725.10}/MediLink/test.py +0 -0
- {medicafe-0.250725.8 → medicafe-0.250725.10}/MediLink/test_cob_library.py +0 -0
- {medicafe-0.250725.8 → medicafe-0.250725.10}/MediLink/test_validation.py +0 -0
- {medicafe-0.250725.8 → medicafe-0.250725.10}/MediLink/webapp.html +0 -0
- {medicafe-0.250725.8 → medicafe-0.250725.10}/README.md +0 -0
- {medicafe-0.250725.8 → medicafe-0.250725.10}/medicafe.egg-info/SOURCES.txt +0 -0
- {medicafe-0.250725.8 → medicafe-0.250725.10}/medicafe.egg-info/dependency_links.txt +0 -0
- {medicafe-0.250725.8 → medicafe-0.250725.10}/medicafe.egg-info/not-zip-safe +0 -0
- {medicafe-0.250725.8 → medicafe-0.250725.10}/medicafe.egg-info/requires.txt +0 -0
- {medicafe-0.250725.8 → medicafe-0.250725.10}/medicafe.egg-info/top_level.txt +0 -0
- {medicafe-0.250725.8 → medicafe-0.250725.10}/setup.cfg +0 -0
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#MediBot.py
|
|
2
|
-
import subprocess, os, tempfile, traceback, re, sys, time
|
|
2
|
+
import subprocess, os, tempfile, traceback, re, sys, time
|
|
3
3
|
from collections import OrderedDict
|
|
4
4
|
import MediBot_dataformat_library
|
|
5
5
|
import MediBot_Preprocessor
|
|
@@ -12,35 +12,7 @@ sys.path.append(project_dir)
|
|
|
12
12
|
|
|
13
13
|
from MediLink import MediLink_ConfigLoader
|
|
14
14
|
|
|
15
|
-
def flush_console_input_buffer():
|
|
16
|
-
"""
|
|
17
|
-
Remove any keystrokes already sitting in the console input buffer.
|
|
18
|
-
Necessary on Windows XP where a stray CR/LF can remain after the
|
|
19
|
-
script is launched.
|
|
20
|
-
"""
|
|
21
|
-
if sys.platform != "win32":
|
|
22
|
-
return # no-op on non-Windows
|
|
23
15
|
|
|
24
|
-
try:
|
|
25
|
-
kernel32 = ctypes.WinDLL('kernel32', use_last_error=True)
|
|
26
|
-
STD_INPUT_HANDLE = -10
|
|
27
|
-
h_stdin = kernel32.GetStdHandle(STD_INPUT_HANDLE)
|
|
28
|
-
kernel32.FlushConsoleInputBuffer(h_stdin)
|
|
29
|
-
except Exception:
|
|
30
|
-
# Fallback: drain any leading newlines manually
|
|
31
|
-
while msvcrt.kbhit():
|
|
32
|
-
msvcrt.getch()
|
|
33
|
-
|
|
34
|
-
def discard_leading_blank():
|
|
35
|
-
"""
|
|
36
|
-
Alternative fallback that uses non-blocking msvcrt to drain any available input.
|
|
37
|
-
"""
|
|
38
|
-
if sys.platform != "win32":
|
|
39
|
-
return # no-op on non-Windows
|
|
40
|
-
|
|
41
|
-
# Use non-blocking msvcrt approach to drain any available input
|
|
42
|
-
while msvcrt.kbhit():
|
|
43
|
-
msvcrt.getch()
|
|
44
16
|
|
|
45
17
|
try:
|
|
46
18
|
from MediBot_Crosswalk_Library import crosswalk_update
|
|
@@ -430,9 +402,6 @@ if __name__ == "__main__":
|
|
|
430
402
|
sys.stdout.flush()
|
|
431
403
|
time.sleep(0.2) # Increased delay for Windows XP
|
|
432
404
|
|
|
433
|
-
# Flush console input buffer to remove any stray CR/LF
|
|
434
|
-
flush_console_input_buffer()
|
|
435
|
-
|
|
436
405
|
# Use input() for more reliable input on Windows XP
|
|
437
406
|
proceed = input().lower().strip() in ['yes', 'y']
|
|
438
407
|
else:
|
|
@@ -441,9 +410,6 @@ if __name__ == "__main__":
|
|
|
441
410
|
sys.stdout.flush()
|
|
442
411
|
time.sleep(0.2) # Increased delay for Windows XP
|
|
443
412
|
|
|
444
|
-
# Flush console input buffer to remove any stray CR/LF
|
|
445
|
-
flush_console_input_buffer()
|
|
446
|
-
|
|
447
413
|
# Use input() for more reliable input on Windows XP
|
|
448
414
|
proceed = input().lower().strip() in ['yes', 'y']
|
|
449
415
|
|
|
@@ -1,409 +1,327 @@
|
|
|
1
|
-
#MediBot_UI.py
|
|
2
|
-
import ctypes, time, re, os, sys, msvcrt
|
|
3
|
-
from ctypes import wintypes
|
|
4
|
-
from sys import exit
|
|
5
|
-
project_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))
|
|
6
|
-
if project_dir not in sys.path:
|
|
7
|
-
sys.path.append(project_dir)
|
|
8
|
-
|
|
9
|
-
try:
|
|
10
|
-
from MediLink import MediLink_ConfigLoader
|
|
11
|
-
except ImportError:
|
|
12
|
-
import MediLink_ConfigLoader
|
|
13
|
-
|
|
14
|
-
# Load configuration
|
|
15
|
-
config, crosswalk = MediLink_ConfigLoader.load_configuration()
|
|
16
|
-
|
|
17
|
-
# Function to check if a specific key is pressed
|
|
18
|
-
VK_END = int(config.get('VK_END', ""), 16) # Try F12 (7B). Virtual key code for 'End' (23)
|
|
19
|
-
VK_PAUSE = int(config.get('VK_PAUSE', ""), 16) # Try F11 (7A). Virtual-key code for 'Home' (24)
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
"""
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
if
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
#
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
# Menu options with improved context
|
|
329
|
-
print("1: Retry last entry")
|
|
330
|
-
print("2: Skip to next patient and continue")
|
|
331
|
-
print("3: Go back two patients and redo")
|
|
332
|
-
print("4: Exit script")
|
|
333
|
-
print("-" * 60)
|
|
334
|
-
print("Enter your choice (1/2/3/4): ", end='', flush=True)
|
|
335
|
-
# Force flush and wait for Windows XP console buffer synchronization
|
|
336
|
-
sys.stdout.flush()
|
|
337
|
-
time.sleep(0.2) # Increased delay for Windows XP
|
|
338
|
-
|
|
339
|
-
# Flush console input buffer to remove any stray CR/LF
|
|
340
|
-
flush_console_input_buffer()
|
|
341
|
-
|
|
342
|
-
# Use input() for more reliable input on Windows XP
|
|
343
|
-
choice = input().strip()
|
|
344
|
-
|
|
345
|
-
if choice == '1':
|
|
346
|
-
print("Selected: 'Retry last entry'. Please press 'F12' to continue.")
|
|
347
|
-
return -1
|
|
348
|
-
elif choice == '2':
|
|
349
|
-
print("Selected: 'Skip to next patient and continue'. Please press 'F12' to continue.")
|
|
350
|
-
return 1
|
|
351
|
-
elif choice == '3':
|
|
352
|
-
print("Selected: 'Go back two patients and redo'. Please press 'F12' to continue.")
|
|
353
|
-
# Returning a specific value to indicate the action of going back two patients
|
|
354
|
-
# but we might run into a problem if we stop mid-run on the first row?
|
|
355
|
-
return -2
|
|
356
|
-
elif choice == '4':
|
|
357
|
-
print("Exiting the script.")
|
|
358
|
-
exit()
|
|
359
|
-
else:
|
|
360
|
-
print("Invalid choice. Please enter a valid number.")
|
|
361
|
-
|
|
362
|
-
def user_interaction(csv_data, interaction_mode, error_message, reverse_mapping):
|
|
363
|
-
global app_control # Use the instance of AppControl
|
|
364
|
-
selected_patient_ids = []
|
|
365
|
-
selected_indices = []
|
|
366
|
-
|
|
367
|
-
if interaction_mode == 'triage':
|
|
368
|
-
display_menu_header(" =(^.^)= Welcome to MediBot! =(^.^)=")
|
|
369
|
-
|
|
370
|
-
# Force flush for Windows XP compatibility
|
|
371
|
-
sys.stdout.flush()
|
|
372
|
-
|
|
373
|
-
# Flush console input buffer to remove any stray CR/LF from script launch
|
|
374
|
-
flush_console_input_buffer()
|
|
375
|
-
|
|
376
|
-
while True:
|
|
377
|
-
try:
|
|
378
|
-
print("DEBUG_MAIN: About to call robust_input() - waiting for user...")
|
|
379
|
-
# Use robust_input() for more reliable input on Windows XP
|
|
380
|
-
response = robust_input("\nAm I processing Medicare patients? (yes/no): ").lower()
|
|
381
|
-
|
|
382
|
-
# Debug: Print what we actually got
|
|
383
|
-
print("DEBUG_MAIN: Final response: '{}' (length: {})".format(response, len(response)))
|
|
384
|
-
print("DEBUG_MAIN: Response type: {}, repr: {}".format(type(response), repr(response)))
|
|
385
|
-
|
|
386
|
-
if response:
|
|
387
|
-
if response in ['yes', 'y']:
|
|
388
|
-
app_control.load_paths_from_config(medicare=True)
|
|
389
|
-
break
|
|
390
|
-
elif response in ['no', 'n']:
|
|
391
|
-
app_control.load_paths_from_config(medicare=False)
|
|
392
|
-
break
|
|
393
|
-
else:
|
|
394
|
-
print("Invalid entry. Please enter 'yes' or 'no'.")
|
|
395
|
-
else:
|
|
396
|
-
print("A response is required. Please try again.")
|
|
397
|
-
except KeyboardInterrupt:
|
|
398
|
-
print("\nOperation cancelled by user. Exiting script.")
|
|
399
|
-
exit()
|
|
400
|
-
|
|
401
|
-
fixed_values = config.get('fixed_values', {}) # Get fixed values from config json
|
|
402
|
-
if response in ['yes', 'y']:
|
|
403
|
-
medicare_added_fixed_values = config.get('medicare_added_fixed_values', {})
|
|
404
|
-
fixed_values.update(medicare_added_fixed_values) # Add any medicare-specific fixed values from config
|
|
405
|
-
|
|
406
|
-
proceed, selected_patient_ids, selected_indices = display_patient_selection_menu(csv_data, reverse_mapping, response in ['yes', 'y'])
|
|
407
|
-
return proceed, selected_patient_ids, selected_indices, fixed_values
|
|
408
|
-
|
|
1
|
+
#MediBot_UI.py
|
|
2
|
+
import ctypes, time, re, os, sys, msvcrt
|
|
3
|
+
from ctypes import wintypes
|
|
4
|
+
from sys import exit
|
|
5
|
+
project_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))
|
|
6
|
+
if project_dir not in sys.path:
|
|
7
|
+
sys.path.append(project_dir)
|
|
8
|
+
|
|
9
|
+
try:
|
|
10
|
+
from MediLink import MediLink_ConfigLoader
|
|
11
|
+
except ImportError:
|
|
12
|
+
import MediLink_ConfigLoader
|
|
13
|
+
|
|
14
|
+
# Load configuration
|
|
15
|
+
config, crosswalk = MediLink_ConfigLoader.load_configuration()
|
|
16
|
+
|
|
17
|
+
# Function to check if a specific key is pressed
|
|
18
|
+
VK_END = int(config.get('VK_END', ""), 16) # Try F12 (7B). Virtual key code for 'End' (23)
|
|
19
|
+
VK_PAUSE = int(config.get('VK_PAUSE', ""), 16) # Try F11 (7A). Virtual-key code for 'Home' (24)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def robust_input(prompt="", max_retries=3):
|
|
24
|
+
"""
|
|
25
|
+
Simple input function with retry logic for Windows XP console issues.
|
|
26
|
+
"""
|
|
27
|
+
for attempt in range(max_retries):
|
|
28
|
+
if attempt > 0:
|
|
29
|
+
# Clear any leftover input on retry
|
|
30
|
+
while msvcrt.kbhit():
|
|
31
|
+
msvcrt.getch()
|
|
32
|
+
|
|
33
|
+
response = input(prompt if attempt == 0 else "").strip()
|
|
34
|
+
|
|
35
|
+
if response:
|
|
36
|
+
return response
|
|
37
|
+
|
|
38
|
+
return ""
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
class AppControl:
|
|
43
|
+
def __init__(self):
|
|
44
|
+
self.script_paused = False
|
|
45
|
+
self.mapat_med_path = ''
|
|
46
|
+
self.medisoft_shortcut = ''
|
|
47
|
+
# PERFORMANCE FIX: Add configuration caching to reduce lookup overhead
|
|
48
|
+
self._config_cache = {} # Cache for Medicare vs Private configuration lookups
|
|
49
|
+
# Load initial paths from config when instance is created
|
|
50
|
+
self.load_paths_from_config()
|
|
51
|
+
|
|
52
|
+
def get_pause_status(self):
|
|
53
|
+
return self.script_paused
|
|
54
|
+
|
|
55
|
+
def set_pause_status(self, status):
|
|
56
|
+
self.script_paused = status
|
|
57
|
+
|
|
58
|
+
def get_mapat_med_path(self):
|
|
59
|
+
return self.mapat_med_path
|
|
60
|
+
|
|
61
|
+
def set_mapat_med_path(self, path):
|
|
62
|
+
self.mapat_med_path = path
|
|
63
|
+
|
|
64
|
+
def get_medisoft_shortcut(self):
|
|
65
|
+
return self.medisoft_shortcut
|
|
66
|
+
|
|
67
|
+
def set_medisoft_shortcut(self, path):
|
|
68
|
+
self.medisoft_shortcut = path
|
|
69
|
+
|
|
70
|
+
def load_paths_from_config(self, medicare=False):
|
|
71
|
+
# Assuming `config` is a module or a globally accessible configuration dictionary
|
|
72
|
+
# TODO Is this where the MAINS paths should also be set?
|
|
73
|
+
|
|
74
|
+
# PERFORMANCE FIX: Cache configuration lookups to reduce Medicare vs Private overhead
|
|
75
|
+
cache_key = 'medicare' if medicare else 'private'
|
|
76
|
+
|
|
77
|
+
if cache_key not in self._config_cache:
|
|
78
|
+
# Build cache entry for this configuration type
|
|
79
|
+
if medicare:
|
|
80
|
+
cached_config = {
|
|
81
|
+
'mapat_path': config.get('MEDICARE_MAPAT_MED_PATH', ""),
|
|
82
|
+
'shortcut': config.get('MEDICARE_SHORTCUT', "")
|
|
83
|
+
}
|
|
84
|
+
else:
|
|
85
|
+
cached_config = {
|
|
86
|
+
'mapat_path': config.get('MAPAT_MED_PATH', ""),
|
|
87
|
+
'shortcut': config.get('PRIVATE_SHORTCUT', "")
|
|
88
|
+
}
|
|
89
|
+
self._config_cache[cache_key] = cached_config
|
|
90
|
+
|
|
91
|
+
# Use cached values to avoid repeated config lookups
|
|
92
|
+
cached = self._config_cache[cache_key]
|
|
93
|
+
self.mapat_med_path = cached['mapat_path']
|
|
94
|
+
self.medisoft_shortcut = cached['shortcut']
|
|
95
|
+
|
|
96
|
+
app_control = AppControl()
|
|
97
|
+
|
|
98
|
+
def is_key_pressed(key_code):
|
|
99
|
+
user32 = ctypes.WinDLL('user32', use_last_error=True)
|
|
100
|
+
user32.GetAsyncKeyState.restype = wintypes.SHORT
|
|
101
|
+
user32.GetAsyncKeyState.argtypes = [wintypes.INT]
|
|
102
|
+
return user32.GetAsyncKeyState(key_code) & 0x8000 != 0
|
|
103
|
+
|
|
104
|
+
def manage_script_pause(csv_data, error_message, reverse_mapping):
|
|
105
|
+
user_action = 0 # initialize as 'continue'
|
|
106
|
+
|
|
107
|
+
if not app_control.get_pause_status() and is_key_pressed(VK_PAUSE):
|
|
108
|
+
app_control.set_pause_status(True)
|
|
109
|
+
print("Script paused. Opening menu...")
|
|
110
|
+
interaction_mode = 'normal' # Assuming normal interaction mode for script pause
|
|
111
|
+
user_action = user_interaction(csv_data, interaction_mode, error_message, reverse_mapping)
|
|
112
|
+
|
|
113
|
+
while app_control.get_pause_status():
|
|
114
|
+
if is_key_pressed(VK_END):
|
|
115
|
+
app_control.set_pause_status(False)
|
|
116
|
+
print("Continuing...")
|
|
117
|
+
elif is_key_pressed(VK_PAUSE):
|
|
118
|
+
user_action = user_interaction(csv_data, 'normal', error_message, reverse_mapping)
|
|
119
|
+
time.sleep(0.1)
|
|
120
|
+
|
|
121
|
+
return user_action
|
|
122
|
+
|
|
123
|
+
# Menu Display & User Interaction
|
|
124
|
+
def display_patient_selection_menu(csv_data, reverse_mapping, proceed_as_medicare):
|
|
125
|
+
selected_patient_ids = []
|
|
126
|
+
selected_indices = []
|
|
127
|
+
|
|
128
|
+
def display_menu_header(title):
|
|
129
|
+
print("\n" + "-" * 60)
|
|
130
|
+
print(title)
|
|
131
|
+
print("-" * 60)
|
|
132
|
+
|
|
133
|
+
def display_patient_list(csv_data, reverse_mapping, medicare_filter=False, exclude_medicare=False):
|
|
134
|
+
medicare_policy_pattern = r"^[a-zA-Z0-9]{11}$" # Regex pattern for 11 alpha-numeric characters
|
|
135
|
+
primary_policy_number_header = reverse_mapping.get('Primary Policy Number', 'Primary Policy Number')
|
|
136
|
+
primary_insurance_header = reverse_mapping.get('Primary Insurance', 'Primary Insurance') # Adjust field name as needed
|
|
137
|
+
|
|
138
|
+
displayed_indices = []
|
|
139
|
+
displayed_patient_ids = []
|
|
140
|
+
|
|
141
|
+
for index, row in enumerate(csv_data):
|
|
142
|
+
policy_number = row.get(primary_policy_number_header, "")
|
|
143
|
+
primary_insurance = row.get(primary_insurance_header, "").upper()
|
|
144
|
+
|
|
145
|
+
if medicare_filter and (not re.match(medicare_policy_pattern, policy_number) or "MEDICARE" not in primary_insurance):
|
|
146
|
+
continue
|
|
147
|
+
if exclude_medicare and re.match(medicare_policy_pattern, policy_number) and "MEDICARE" in primary_insurance:
|
|
148
|
+
continue
|
|
149
|
+
|
|
150
|
+
patient_id_header = reverse_mapping['Patient ID #2']
|
|
151
|
+
patient_name_header = reverse_mapping['Patient Name']
|
|
152
|
+
patient_id = row.get(patient_id_header, "N/A")
|
|
153
|
+
patient_name = row.get(patient_name_header, "Unknown")
|
|
154
|
+
surgery_date = row.get('Surgery Date', "Unknown Date") # Access 'Surgery Date' as string directly from the row
|
|
155
|
+
|
|
156
|
+
print("{0:03d}: {3:%m-%d} (ID: {2}) {1} ".format(index+1, patient_name, patient_id, surgery_date))
|
|
157
|
+
|
|
158
|
+
displayed_indices.append(index)
|
|
159
|
+
displayed_patient_ids.append(patient_id)
|
|
160
|
+
|
|
161
|
+
return displayed_indices, displayed_patient_ids
|
|
162
|
+
|
|
163
|
+
if proceed_as_medicare:
|
|
164
|
+
display_menu_header("MEDICARE Patient Selection for Today's Data Entry")
|
|
165
|
+
selected_indices, selected_patient_ids = display_patient_list(csv_data, reverse_mapping, medicare_filter=True)
|
|
166
|
+
else:
|
|
167
|
+
display_menu_header("PRIVATE Patient Selection for Today's Data Entry")
|
|
168
|
+
selected_indices, selected_patient_ids = display_patient_list(csv_data, reverse_mapping, exclude_medicare=True)
|
|
169
|
+
|
|
170
|
+
print("-" * 60)
|
|
171
|
+
print("\nDo you want to proceed with the selected patients? (yes/no): ", end='', flush=True)
|
|
172
|
+
# Force flush and wait for Windows XP console buffer synchronization
|
|
173
|
+
sys.stdout.flush()
|
|
174
|
+
time.sleep(0.2) # Increased delay for Windows XP
|
|
175
|
+
|
|
176
|
+
# Use input() for more reliable input on Windows XP
|
|
177
|
+
proceed = input().lower().strip() in ['yes', 'y']
|
|
178
|
+
|
|
179
|
+
if not proceed:
|
|
180
|
+
display_menu_header("Patient Selection for Today's Data Entry")
|
|
181
|
+
selected_indices, selected_patient_ids = display_patient_list(csv_data, reverse_mapping)
|
|
182
|
+
print("-" * 60)
|
|
183
|
+
|
|
184
|
+
while True:
|
|
185
|
+
while True:
|
|
186
|
+
print("\nEnter the number(s) of the patients you wish to proceed with \n(e.g., 1,3,5): ", end='', flush=True)
|
|
187
|
+
# Force flush and wait for Windows XP console buffer synchronization
|
|
188
|
+
sys.stdout.flush()
|
|
189
|
+
time.sleep(0.2) # Increased delay for Windows XP
|
|
190
|
+
|
|
191
|
+
# Use input() for more reliable input on Windows XP
|
|
192
|
+
selection = input().strip()
|
|
193
|
+
if not selection:
|
|
194
|
+
print("Invalid entry. Please provide at least one number.")
|
|
195
|
+
continue
|
|
196
|
+
|
|
197
|
+
selection = selection.replace('.', ',') # Replace '.' with ',' in the user input just in case
|
|
198
|
+
selected_indices = [int(x.strip()) - 1 for x in selection.split(',') if x.strip().isdigit()]
|
|
199
|
+
|
|
200
|
+
if not selected_indices:
|
|
201
|
+
print("Invalid entry. Please provide at least one integer.")
|
|
202
|
+
continue
|
|
203
|
+
|
|
204
|
+
proceed = True
|
|
205
|
+
break
|
|
206
|
+
|
|
207
|
+
if not selection:
|
|
208
|
+
print("Invalid entry. Please provide at least one number.")
|
|
209
|
+
continue
|
|
210
|
+
|
|
211
|
+
selection = selection.replace('.', ',') # Replace '.' with ',' in the user input just in case
|
|
212
|
+
selected_indices = [int(x.strip()) - 1 for x in selection.split(',') if x.strip().isdigit()]
|
|
213
|
+
|
|
214
|
+
if not selected_indices:
|
|
215
|
+
print("Invalid entry. Please provide at least one integer.")
|
|
216
|
+
continue
|
|
217
|
+
|
|
218
|
+
proceed = True
|
|
219
|
+
break
|
|
220
|
+
|
|
221
|
+
patient_id_header = reverse_mapping['Patient ID #2']
|
|
222
|
+
selected_patient_ids = [csv_data[i][patient_id_header] for i in selected_indices if i < len(csv_data)]
|
|
223
|
+
|
|
224
|
+
return proceed, selected_patient_ids, selected_indices
|
|
225
|
+
|
|
226
|
+
def display_menu_header(title):
|
|
227
|
+
print("\n" + "-" * 60)
|
|
228
|
+
print(title)
|
|
229
|
+
print("-" * 60)
|
|
230
|
+
# Force flush for Windows XP compatibility
|
|
231
|
+
sys.stdout.flush()
|
|
232
|
+
|
|
233
|
+
def handle_user_interaction(interaction_mode, error_message):
|
|
234
|
+
# Import here to avoid circular imports
|
|
235
|
+
try:
|
|
236
|
+
from MediBot import current_patient_context
|
|
237
|
+
except ImportError:
|
|
238
|
+
current_patient_context = None
|
|
239
|
+
|
|
240
|
+
while True:
|
|
241
|
+
# If interaction_mode is neither 'triage' nor 'error', then it's normal mode.
|
|
242
|
+
title = "Error Occurred" if interaction_mode == 'error' else "Data Entry Options"
|
|
243
|
+
display_menu_header(title)
|
|
244
|
+
|
|
245
|
+
if interaction_mode == 'error':
|
|
246
|
+
print("\nERROR: ", error_message)
|
|
247
|
+
|
|
248
|
+
# PERFORMANCE FIX: Display patient context to address "won't be obvious anymore" issue
|
|
249
|
+
# Show user which patient and field they're working with for better F11 menu usability
|
|
250
|
+
if current_patient_context:
|
|
251
|
+
patient_name = current_patient_context.get('patient_name', 'Unknown Patient')
|
|
252
|
+
surgery_date = current_patient_context.get('surgery_date', 'Unknown Date')
|
|
253
|
+
last_field = current_patient_context.get('last_field', 'Unknown Field')
|
|
254
|
+
print("\nCurrent Context:")
|
|
255
|
+
print(" Patient: {}".format(patient_name))
|
|
256
|
+
print(" Surgery Date: {}".format(surgery_date))
|
|
257
|
+
print(" Last Field: {}".format(last_field))
|
|
258
|
+
print("")
|
|
259
|
+
|
|
260
|
+
# Menu options with improved context
|
|
261
|
+
print("1: Retry last entry")
|
|
262
|
+
print("2: Skip to next patient and continue")
|
|
263
|
+
print("3: Go back two patients and redo")
|
|
264
|
+
print("4: Exit script")
|
|
265
|
+
print("-" * 60)
|
|
266
|
+
print("Enter your choice (1/2/3/4): ", end='', flush=True)
|
|
267
|
+
# Force flush and wait for Windows XP console buffer synchronization
|
|
268
|
+
sys.stdout.flush()
|
|
269
|
+
time.sleep(0.2) # Increased delay for Windows XP
|
|
270
|
+
|
|
271
|
+
# Use input() for more reliable input on Windows XP
|
|
272
|
+
choice = input().strip()
|
|
273
|
+
|
|
274
|
+
if choice == '1':
|
|
275
|
+
print("Selected: 'Retry last entry'. Please press 'F12' to continue.")
|
|
276
|
+
return -1
|
|
277
|
+
elif choice == '2':
|
|
278
|
+
print("Selected: 'Skip to next patient and continue'. Please press 'F12' to continue.")
|
|
279
|
+
return 1
|
|
280
|
+
elif choice == '3':
|
|
281
|
+
print("Selected: 'Go back two patients and redo'. Please press 'F12' to continue.")
|
|
282
|
+
# Returning a specific value to indicate the action of going back two patients
|
|
283
|
+
# but we might run into a problem if we stop mid-run on the first row?
|
|
284
|
+
return -2
|
|
285
|
+
elif choice == '4':
|
|
286
|
+
print("Exiting the script.")
|
|
287
|
+
exit()
|
|
288
|
+
else:
|
|
289
|
+
print("Invalid choice. Please enter a valid number.")
|
|
290
|
+
|
|
291
|
+
def user_interaction(csv_data, interaction_mode, error_message, reverse_mapping):
|
|
292
|
+
global app_control # Use the instance of AppControl
|
|
293
|
+
selected_patient_ids = []
|
|
294
|
+
selected_indices = []
|
|
295
|
+
|
|
296
|
+
if interaction_mode == 'triage':
|
|
297
|
+
display_menu_header(" =(^.^)= Welcome to MediBot! =(^.^)=")
|
|
298
|
+
|
|
299
|
+
# Force flush for Windows XP compatibility
|
|
300
|
+
sys.stdout.flush()
|
|
301
|
+
|
|
302
|
+
while True:
|
|
303
|
+
try:
|
|
304
|
+
response = robust_input("\nAm I processing Medicare patients? (yes/no): ").lower()
|
|
305
|
+
|
|
306
|
+
if response in ['yes', 'y']:
|
|
307
|
+
app_control.load_paths_from_config(medicare=True)
|
|
308
|
+
break
|
|
309
|
+
elif response in ['no', 'n']:
|
|
310
|
+
app_control.load_paths_from_config(medicare=False)
|
|
311
|
+
break
|
|
312
|
+
else:
|
|
313
|
+
print("Invalid entry. Please enter 'yes' or 'no'.")
|
|
314
|
+
except KeyboardInterrupt:
|
|
315
|
+
print("\nOperation cancelled by user. Exiting script.")
|
|
316
|
+
exit()
|
|
317
|
+
|
|
318
|
+
|
|
319
|
+
fixed_values = config.get('fixed_values', {}) # Get fixed values from config json
|
|
320
|
+
if response in ['yes', 'y']:
|
|
321
|
+
medicare_added_fixed_values = config.get('medicare_added_fixed_values', {})
|
|
322
|
+
fixed_values.update(medicare_added_fixed_values) # Add any medicare-specific fixed values from config
|
|
323
|
+
|
|
324
|
+
proceed, selected_patient_ids, selected_indices = display_patient_selection_menu(csv_data, reverse_mapping, response in ['yes', 'y'])
|
|
325
|
+
return proceed, selected_patient_ids, selected_indices, fixed_values
|
|
326
|
+
|
|
409
327
|
return handle_user_interaction(interaction_mode, error_message)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|