medicafe 0.250816.0__py3-none-any.whl → 0.250819.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.
- MediBot/MediBot.py +40 -4
- MediBot/MediBot_Crosswalk_Utils.py +1 -4
- MediBot/MediBot_Preprocessor.py +88 -14
- MediBot/MediBot_Preprocessor_lib.py +128 -38
- MediBot/MediBot_UI.py +51 -28
- MediBot/__init__.py +1 -1
- MediBot/update_medicafe.py +202 -727
- MediCafe/__init__.py +1 -1
- MediLink/MediLink_837p_encoder.py +1 -1
- MediLink/MediLink_837p_encoder_library.py +580 -318
- MediLink/MediLink_837p_utilities.py +1 -4
- MediLink/MediLink_API_Generator.py +1 -1
- MediLink/MediLink_DataMgmt.py +2 -2
- MediLink/MediLink_Down.py +1 -1
- MediLink/MediLink_Up.py +45 -4
- MediLink/MediLink_main.py +2 -1
- MediLink/__init__.py +1 -1
- MediLink/gmail_oauth_utils.py +1 -4
- {medicafe-0.250816.0.dist-info → medicafe-0.250819.0.dist-info}/METADATA +1 -1
- {medicafe-0.250816.0.dist-info → medicafe-0.250819.0.dist-info}/RECORD +24 -24
- {medicafe-0.250816.0.dist-info → medicafe-0.250819.0.dist-info}/LICENSE +0 -0
- {medicafe-0.250816.0.dist-info → medicafe-0.250819.0.dist-info}/WHEEL +0 -0
- {medicafe-0.250816.0.dist-info → medicafe-0.250819.0.dist-info}/entry_points.txt +0 -0
- {medicafe-0.250816.0.dist-info → medicafe-0.250819.0.dist-info}/top_level.txt +0 -0
MediBot/MediBot.py
CHANGED
@@ -662,6 +662,34 @@ if __name__ == "__main__":
|
|
662
662
|
# Initialize constants from config
|
663
663
|
MediBot_Preprocessor_lib.initialize(e_state.config)
|
664
664
|
|
665
|
+
# PERFORMANCE OPTIMIZATION: Load both Medicare and Private patient databases during startup
|
666
|
+
# Files are small (10K-20K rows each) so memory usage is minimal (~4MB total)
|
667
|
+
# This eliminates the 1-2 second delay from user workflow entirely
|
668
|
+
print("Loading patient databases...")
|
669
|
+
MediLink_ConfigLoader.log("Loading patient databases...", level="INFO")
|
670
|
+
|
671
|
+
try:
|
672
|
+
medicare_path = e_state.config.get('MEDICARE_MAPAT_MED_PATH', "")
|
673
|
+
private_path = e_state.config.get('MAPAT_MED_PATH', "")
|
674
|
+
|
675
|
+
# Load both databases into separate caches
|
676
|
+
medicare_cache = MediBot_Preprocessor.load_existing_patient_ids(medicare_path) if medicare_path else {}
|
677
|
+
private_cache = MediBot_Preprocessor.load_existing_patient_ids(private_path) if private_path else {}
|
678
|
+
|
679
|
+
# Store both caches for later use
|
680
|
+
MediBot_Preprocessor.set_patient_caches(medicare_cache, private_cache)
|
681
|
+
|
682
|
+
if PERFORMANCE_LOGGING:
|
683
|
+
print("Patient databases loaded: {} Medicare, {} Private patients".format(
|
684
|
+
len(medicare_cache), len(private_cache)))
|
685
|
+
MediLink_ConfigLoader.log("Patient databases loaded: {} Medicare, {} Private patients".format(
|
686
|
+
len(medicare_cache), len(private_cache)), level="INFO")
|
687
|
+
|
688
|
+
except Exception as e:
|
689
|
+
MediLink_ConfigLoader.log("Warning: Could not load patient databases: {}".format(e), level="WARNING")
|
690
|
+
if PERFORMANCE_LOGGING:
|
691
|
+
print("Warning: Could not load patient databases - will load on demand")
|
692
|
+
|
665
693
|
if PERFORMANCE_LOGGING:
|
666
694
|
print("Loading CSV Data...")
|
667
695
|
MediLink_ConfigLoader.log("Loading CSV Data...", level="INFO")
|
@@ -735,7 +763,7 @@ if __name__ == "__main__":
|
|
735
763
|
print(msg)
|
736
764
|
print("-" * 60)
|
737
765
|
|
738
|
-
proceed, selected_patient_ids, selected_indices, fixed_values = user_interaction(csv_data, interaction_mode, error_message, reverse_mapping)
|
766
|
+
proceed, selected_patient_ids, selected_indices, fixed_values, is_medicare = user_interaction(csv_data, interaction_mode, error_message, reverse_mapping)
|
739
767
|
|
740
768
|
if proceed:
|
741
769
|
# Filter csv_data for selected patients from Triage mode
|
@@ -745,7 +773,13 @@ if __name__ == "__main__":
|
|
745
773
|
if (not _ac()) or (not _ac().get_mapat_med_path()) or (not os.path.exists(_ac().get_mapat_med_path())):
|
746
774
|
record_startup_warning("Warning: MAPAT.MED PATH is missing or invalid. Please check the path configuration.")
|
747
775
|
|
748
|
-
#
|
776
|
+
# PERFORMANCE OPTIMIZATION: Select the appropriate pre-loaded patient cache
|
777
|
+
# Both caches were loaded during startup, now we just select the right one
|
778
|
+
MediBot_Preprocessor.select_active_cache(is_medicare)
|
779
|
+
if PERFORMANCE_LOGGING:
|
780
|
+
print("Using {} patient cache for existing patient check".format("Medicare" if is_medicare else "Private"))
|
781
|
+
|
782
|
+
# Perform the existing patients check (now uses cached data)
|
749
783
|
existing_patients, patients_to_process = MediBot_Preprocessor.check_existing_patients(selected_patient_ids, _ac().get_mapat_med_path() if _ac() else '')
|
750
784
|
|
751
785
|
if existing_patients:
|
@@ -767,9 +801,10 @@ if __name__ == "__main__":
|
|
767
801
|
patient_info.append(('Unknown Date', patient_name, patient_id, 'N/A', None)) # Append with 'Unknown Date' if there's an error
|
768
802
|
|
769
803
|
# Display existing patients table using the enhanced display function
|
804
|
+
patient_type = "MEDICARE" if is_medicare else "PRIVATE"
|
770
805
|
MediBot_UI.display_enhanced_patient_table(
|
771
806
|
patient_info,
|
772
|
-
"
|
807
|
+
"{} PATIENTS - EXISTING: The following patient(s) already EXIST in the system but may have new dates of service.\n Their diagnosis codes may need to be updated manually by the user to the following list:".format(patient_type),
|
773
808
|
show_line_numbers=False
|
774
809
|
)
|
775
810
|
|
@@ -787,9 +822,10 @@ if __name__ == "__main__":
|
|
787
822
|
new_patient_info.extend(patient_entries)
|
788
823
|
|
789
824
|
# Display new patients table using the enhanced display function
|
825
|
+
patient_type = "MEDICARE" if is_medicare else "PRIVATE"
|
790
826
|
MediBot_UI.display_enhanced_patient_table(
|
791
827
|
new_patient_info,
|
792
|
-
"
|
828
|
+
"{} PATIENTS - NEW: The following patient(s) will be automatically entered into Medisoft:".format(patient_type),
|
793
829
|
show_line_numbers=True
|
794
830
|
)
|
795
831
|
|
@@ -9,10 +9,7 @@ to improve code organization and maintainability.
|
|
9
9
|
Compatible with Python 3.4.4 and Windows XP environments.
|
10
10
|
"""
|
11
11
|
|
12
|
-
import json
|
13
|
-
import os
|
14
|
-
import sys
|
15
|
-
import threading
|
12
|
+
import json, os, sys
|
16
13
|
|
17
14
|
# Set the project directory to the parent directory of the current file
|
18
15
|
project_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))
|
MediBot/MediBot_Preprocessor.py
CHANGED
@@ -144,30 +144,104 @@ def preprocess_csv_data(csv_data, crosswalk):
|
|
144
144
|
MediLink_ConfigLoader.log(message, level="ERROR")
|
145
145
|
print(message)
|
146
146
|
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
147
|
+
# Global caches for existing patient IDs to avoid repeated file I/O
|
148
|
+
_medicare_patients_cache = None
|
149
|
+
_private_patients_cache = None
|
150
|
+
_current_cache = None # Points to the active cache based on user selection
|
151
151
|
|
152
|
+
def load_existing_patient_ids(MAPAT_MED_PATH):
|
153
|
+
"""
|
154
|
+
Load all existing patient IDs from MAPAT.MED file into memory cache.
|
155
|
+
|
156
|
+
Args:
|
157
|
+
MAPAT_MED_PATH: Path to the MAPAT.MED file
|
158
|
+
|
159
|
+
Returns:
|
160
|
+
dict: {patient_id: patient_name} mapping of all existing patients
|
161
|
+
"""
|
162
|
+
patient_cache = {}
|
163
|
+
|
164
|
+
if not MAPAT_MED_PATH:
|
165
|
+
MediLink_ConfigLoader.log("MAPAT.MED path not provided - returning empty cache", level="WARNING")
|
166
|
+
return patient_cache
|
167
|
+
|
152
168
|
try:
|
169
|
+
MediLink_ConfigLoader.log("Loading patient cache from: {}".format(MAPAT_MED_PATH), level="INFO")
|
153
170
|
with open(MAPAT_MED_PATH, 'r') as file:
|
154
171
|
next(file) # Skip header row
|
155
172
|
for line in file:
|
156
|
-
if line.startswith("0"):
|
173
|
+
if line.startswith("0"): # 1 is a flag for a deleted record so it would need to be re-entered.
|
157
174
|
patient_id = line[194:202].strip() # Extract Patient ID (Columns 195-202)
|
158
175
|
patient_name = line[9:39].strip() # Extract Patient Name (Columns 10-39)
|
159
176
|
|
160
|
-
if patient_id
|
161
|
-
|
162
|
-
|
163
|
-
|
177
|
+
if patient_id: # Only cache non-empty patient IDs
|
178
|
+
patient_cache[patient_id] = patient_name
|
179
|
+
|
180
|
+
MediLink_ConfigLoader.log("Loaded {} patients into cache from {}".format(len(patient_cache), MAPAT_MED_PATH), level="INFO")
|
181
|
+
|
164
182
|
except FileNotFoundError:
|
165
|
-
|
166
|
-
print("MAPAT.med was not found at location
|
167
|
-
print("
|
183
|
+
MediLink_ConfigLoader.log("MAPAT.med was not found at location: {}".format(MAPAT_MED_PATH), level="WARNING")
|
184
|
+
print("MAPAT.med was not found at location: {}".format(MAPAT_MED_PATH))
|
185
|
+
print("Continuing with empty patient cache...")
|
186
|
+
except Exception as e:
|
187
|
+
MediLink_ConfigLoader.log("Error loading patient cache: {}".format(e), level="ERROR")
|
188
|
+
print("Error loading patient cache: {}".format(e))
|
189
|
+
|
190
|
+
return patient_cache
|
191
|
+
|
192
|
+
def set_patient_caches(medicare_cache, private_cache):
|
193
|
+
"""
|
194
|
+
Store both patient caches for later use based on user selection.
|
195
|
+
|
196
|
+
Args:
|
197
|
+
medicare_cache: Dict of Medicare patient IDs and names
|
198
|
+
private_cache: Dict of Private patient IDs and names
|
199
|
+
"""
|
200
|
+
global _medicare_patients_cache, _private_patients_cache
|
201
|
+
_medicare_patients_cache = medicare_cache
|
202
|
+
_private_patients_cache = private_cache
|
203
|
+
|
204
|
+
def select_active_cache(is_medicare):
|
205
|
+
"""
|
206
|
+
Select which patient cache to use based on Medicare selection.
|
207
|
+
|
208
|
+
Args:
|
209
|
+
is_medicare: True for Medicare patients, False for Private patients
|
210
|
+
"""
|
211
|
+
global _current_cache, _medicare_patients_cache, _private_patients_cache
|
212
|
+
_current_cache = _medicare_patients_cache if is_medicare else _private_patients_cache
|
213
|
+
|
214
|
+
def check_existing_patients(selected_patient_ids, MAPAT_MED_PATH):
|
215
|
+
"""
|
216
|
+
Check which selected patients already exist in the system using cached data.
|
217
|
+
This is now much faster as it uses in-memory cache instead of file I/O.
|
218
|
+
|
219
|
+
Args:
|
220
|
+
selected_patient_ids: List of patient IDs to check
|
221
|
+
MAPAT_MED_PATH: Path to MAPAT.MED file (for fallback if cache not available)
|
168
222
|
|
169
|
-
|
170
|
-
|
223
|
+
Returns:
|
224
|
+
tuple: (existing_patients, patients_to_process)
|
225
|
+
"""
|
226
|
+
global _current_cache
|
227
|
+
|
228
|
+
# Use current cache if available, otherwise fallback to loading file
|
229
|
+
if _current_cache is not None:
|
230
|
+
existing_patients_dict = _current_cache
|
231
|
+
else:
|
232
|
+
# Fallback: load from file if cache not available
|
233
|
+
existing_patients_dict = load_existing_patient_ids(MAPAT_MED_PATH)
|
234
|
+
|
235
|
+
existing_patients = []
|
236
|
+
patients_to_process = []
|
237
|
+
|
238
|
+
# Use cached data for O(1) lookups instead of file I/O
|
239
|
+
for patient_id in selected_patient_ids:
|
240
|
+
if patient_id in existing_patients_dict:
|
241
|
+
patient_name = existing_patients_dict[patient_id]
|
242
|
+
existing_patients.append((patient_id, patient_name))
|
243
|
+
else:
|
244
|
+
patients_to_process.append(patient_id)
|
171
245
|
|
172
246
|
return existing_patients, patients_to_process
|
173
247
|
|
@@ -309,6 +309,103 @@ def detect_date_format(date_str):
|
|
309
309
|
|
310
310
|
return None
|
311
311
|
|
312
|
+
class OptimizedDate:
|
313
|
+
"""
|
314
|
+
Optimized date object that pre-computes all common format variations
|
315
|
+
to avoid redundant datetime conversions throughout the application.
|
316
|
+
"""
|
317
|
+
def __init__(self, datetime_obj):
|
318
|
+
self.datetime = datetime_obj
|
319
|
+
# Pre-compute all common format variations
|
320
|
+
self._display_short = datetime_obj.strftime('%m-%d') # For table display
|
321
|
+
self._display_full = datetime_obj.strftime('%m-%d-%Y') # Full format
|
322
|
+
self._medisoft_format = datetime_obj.strftime('%m%d%Y') # For Medisoft entry
|
323
|
+
self._iso_format = datetime_obj.strftime('%Y-%m-%d') # For sorting/comparison
|
324
|
+
|
325
|
+
@property
|
326
|
+
def display_short(self):
|
327
|
+
"""Short display format: MM-DD"""
|
328
|
+
return self._display_short
|
329
|
+
|
330
|
+
@property
|
331
|
+
def display_full(self):
|
332
|
+
"""Full display format: MM-DD-YYYY"""
|
333
|
+
return self._display_full
|
334
|
+
|
335
|
+
@property
|
336
|
+
def medisoft_format(self):
|
337
|
+
"""Medisoft entry format: MMDDYYYY"""
|
338
|
+
return self._medisoft_format
|
339
|
+
|
340
|
+
@property
|
341
|
+
def iso_format(self):
|
342
|
+
"""ISO format for sorting: YYYY-MM-DD"""
|
343
|
+
return self._iso_format
|
344
|
+
|
345
|
+
def __str__(self):
|
346
|
+
return self._display_full
|
347
|
+
|
348
|
+
def __repr__(self):
|
349
|
+
return "OptimizedDate({})".format(self._display_full)
|
350
|
+
|
351
|
+
def __eq__(self, other):
|
352
|
+
if isinstance(other, OptimizedDate):
|
353
|
+
return self.datetime == other.datetime
|
354
|
+
elif hasattr(other, 'strftime'): # datetime object
|
355
|
+
return self.datetime == other
|
356
|
+
return False
|
357
|
+
|
358
|
+
def __lt__(self, other):
|
359
|
+
if isinstance(other, OptimizedDate):
|
360
|
+
return self.datetime < other.datetime
|
361
|
+
elif hasattr(other, 'strftime'): # datetime object
|
362
|
+
return self.datetime < other
|
363
|
+
return NotImplemented
|
364
|
+
|
365
|
+
def __gt__(self, other):
|
366
|
+
if isinstance(other, OptimizedDate):
|
367
|
+
return self.datetime > other.datetime
|
368
|
+
elif hasattr(other, 'strftime'): # datetime object
|
369
|
+
return self.datetime > other
|
370
|
+
return NotImplemented
|
371
|
+
|
372
|
+
def strftime(self, format_str):
|
373
|
+
"""Fallback for any custom format needs"""
|
374
|
+
return self.datetime.strftime(format_str)
|
375
|
+
|
376
|
+
@classmethod
|
377
|
+
def from_string(cls, date_str, cleaned=False):
|
378
|
+
"""
|
379
|
+
Create OptimizedDate from string, with optional pre-cleaning.
|
380
|
+
|
381
|
+
Args:
|
382
|
+
date_str: Date string to parse
|
383
|
+
cleaned: If True, assumes string is already cleaned
|
384
|
+
|
385
|
+
Returns:
|
386
|
+
OptimizedDate object or None if parsing fails
|
387
|
+
"""
|
388
|
+
if not cleaned:
|
389
|
+
date_str = clean_surgery_date_string(date_str)
|
390
|
+
if not date_str:
|
391
|
+
return None
|
392
|
+
|
393
|
+
# Try standard format first (most common)
|
394
|
+
try:
|
395
|
+
return cls(datetime.strptime(date_str, '%m/%d/%Y'))
|
396
|
+
except ValueError:
|
397
|
+
pass
|
398
|
+
|
399
|
+
# Try alternative formats
|
400
|
+
formats = ['%m-%d-%Y', '%m/%d/%y', '%m-%d-%y', '%Y/%m/%d', '%Y-%m-%d']
|
401
|
+
for fmt in formats:
|
402
|
+
try:
|
403
|
+
return cls(datetime.strptime(date_str, fmt))
|
404
|
+
except ValueError:
|
405
|
+
continue
|
406
|
+
|
407
|
+
return None
|
408
|
+
|
312
409
|
def clean_surgery_date_string(date_str):
|
313
410
|
"""
|
314
411
|
Cleans and normalizes surgery date strings to handle damaged data.
|
@@ -1378,6 +1475,35 @@ def map_payer_ids_to_insurance_ids(patient_id_to_insurance_id, payer_id_to_patie
|
|
1378
1475
|
}
|
1379
1476
|
return payer_id_to_details
|
1380
1477
|
|
1478
|
+
def _display_mains_file_error(mains_path):
|
1479
|
+
"""
|
1480
|
+
Helper function to display the critical MAINS file error message.
|
1481
|
+
|
1482
|
+
Args:
|
1483
|
+
mains_path (str): The path where the MAINS file was expected to be found.
|
1484
|
+
"""
|
1485
|
+
error_msg = "CRITICAL: MAINS file not found at: {}. This file is required for insurance name to Medisoft ID mapping.".format(mains_path)
|
1486
|
+
if hasattr(MediLink_ConfigLoader, 'log'):
|
1487
|
+
MediLink_ConfigLoader.log(error_msg, level="CRITICAL")
|
1488
|
+
print("\n" + "="*80)
|
1489
|
+
print("CRITICAL ERROR: MAINS FILE MISSING")
|
1490
|
+
print("="*80)
|
1491
|
+
print("\nThe MAINS file is required for the following critical functions:")
|
1492
|
+
print("* Mapping insurance company names to Medisoft IDs")
|
1493
|
+
print("* Converting insurance names to payer IDs for claim submission")
|
1494
|
+
print("* Creating properly formatted 837p claim files")
|
1495
|
+
print("\nWithout this file, claim submission will fail because:")
|
1496
|
+
print("* Insurance names cannot be converted to payer IDs")
|
1497
|
+
print("* 837p claim files cannot be generated")
|
1498
|
+
print("* Claims cannot be submitted to insurance companies")
|
1499
|
+
print("\nTO FIX THIS:")
|
1500
|
+
print("1. Ensure the MAINS file exists at: {}".format(mains_path))
|
1501
|
+
print("2. If the file is missing, llamar a Dani")
|
1502
|
+
print("3. The file should contain insurance company data from your Medisoft system")
|
1503
|
+
print("="*80)
|
1504
|
+
time.sleep(3) # 3 second pause to allow user to read critical error message
|
1505
|
+
|
1506
|
+
|
1381
1507
|
def load_insurance_data_from_mains(config):
|
1382
1508
|
"""
|
1383
1509
|
Loads insurance data from MAINS and creates a mapping from insurance names to their respective IDs.
|
@@ -1421,25 +1547,7 @@ def load_insurance_data_from_mains(config):
|
|
1421
1547
|
try:
|
1422
1548
|
# Check if MAINS file exists before attempting to read
|
1423
1549
|
if not os.path.exists(mains_path):
|
1424
|
-
|
1425
|
-
if hasattr(MediLink_ConfigLoader, 'log'):
|
1426
|
-
MediLink_ConfigLoader.log(error_msg, level="CRITICAL")
|
1427
|
-
print("\n" + "="*80)
|
1428
|
-
print("CRITICAL ERROR: MAINS FILE MISSING")
|
1429
|
-
print("="*80)
|
1430
|
-
print("\nThe MAINS file is required for the following critical functions:")
|
1431
|
-
print("* Mapping insurance company names to Medisoft IDs")
|
1432
|
-
print("* Converting insurance names to payer IDs for claim submission")
|
1433
|
-
print("* Creating properly formatted 837p claim files")
|
1434
|
-
print("\nWithout this file, claim submission will fail because:")
|
1435
|
-
print("* Insurance names cannot be converted to payer IDs")
|
1436
|
-
print("* 837p claim files cannot be generated")
|
1437
|
-
print("* Claims cannot be submitted to insurance companies")
|
1438
|
-
print("\nTO FIX THIS:")
|
1439
|
-
print("1. Ensure the MAINS file exists at: {}".format(mains_path))
|
1440
|
-
print("2. If the file is missing, llamar a Dani")
|
1441
|
-
print("3. The file should contain insurance company data from your Medisoft system")
|
1442
|
-
print("="*80)
|
1550
|
+
_display_mains_file_error(mains_path)
|
1443
1551
|
return insurance_to_id
|
1444
1552
|
|
1445
1553
|
# XP Compatibility: Check if MediLink_DataMgmt has the required function
|
@@ -1459,25 +1567,7 @@ def load_insurance_data_from_mains(config):
|
|
1459
1567
|
print("Successfully loaded {} insurance records from MAINS".format(len(insurance_to_id)))
|
1460
1568
|
|
1461
1569
|
except FileNotFoundError:
|
1462
|
-
|
1463
|
-
if hasattr(MediLink_ConfigLoader, 'log'):
|
1464
|
-
MediLink_ConfigLoader.log(error_msg, level="CRITICAL")
|
1465
|
-
print("\n" + "="*80)
|
1466
|
-
print("CRITICAL ERROR: MAINS FILE MISSING")
|
1467
|
-
print("="*80)
|
1468
|
-
print("\nThe MAINS file is required for the following critical functions:")
|
1469
|
-
print("* Mapping insurance company names to Medisoft IDs")
|
1470
|
-
print("* Converting insurance names to payer IDs for claim submission")
|
1471
|
-
print("* Creating properly formatted 837p claim files")
|
1472
|
-
print("\nWithout this file, claim submission will fail because:")
|
1473
|
-
print("* Insurance names cannot be converted to payer IDs")
|
1474
|
-
print("* 837p claim files cannot be generated")
|
1475
|
-
print("* Claims cannot be submitted to insurance companies")
|
1476
|
-
print("\nTO FIX THIS:")
|
1477
|
-
print("1. Ensure the MAINS file exists at: {}".format(mains_path))
|
1478
|
-
print("2. If the file is missing, llamar a Dani")
|
1479
|
-
print("3. The file should contain insurance company data from your Medisoft system")
|
1480
|
-
print("="*80)
|
1570
|
+
_display_mains_file_error(mains_path)
|
1481
1571
|
except Exception as e:
|
1482
1572
|
error_msg = "Error loading MAINS data: {}. Continuing without MAINS data.".format(str(e))
|
1483
1573
|
if hasattr(MediLink_ConfigLoader, 'log'):
|
MediBot/MediBot_UI.py
CHANGED
@@ -316,6 +316,10 @@ def display_patient_selection_menu(csv_data, reverse_mapping, proceed_as_medicar
|
|
316
316
|
selected_patient_ids = []
|
317
317
|
selected_indices = []
|
318
318
|
|
319
|
+
# TODO: Future enhancement - make this configurable via config file
|
320
|
+
# Example: config.get('silent_initial_selection', True)
|
321
|
+
SILENT_INITIAL_SELECTION = True # Set to False to restore original interactive behavior
|
322
|
+
|
319
323
|
def display_menu_header(title):
|
320
324
|
print("\n" + "-" * 60)
|
321
325
|
print(title)
|
@@ -348,7 +352,10 @@ def display_patient_selection_menu(csv_data, reverse_mapping, proceed_as_medicar
|
|
348
352
|
formatted_date = surgery_date.strftime('%m-%d')
|
349
353
|
except Exception:
|
350
354
|
formatted_date = str(surgery_date)
|
351
|
-
|
355
|
+
|
356
|
+
# Only display if not in silent mode
|
357
|
+
if not SILENT_INITIAL_SELECTION:
|
358
|
+
print("{0:03d}: {3} (ID: {2}) {1} ".format(index+1, patient_name, patient_id, formatted_date))
|
352
359
|
|
353
360
|
displayed_indices.append(index)
|
354
361
|
displayed_patient_ids.append(patient_id)
|
@@ -356,23 +363,44 @@ def display_patient_selection_menu(csv_data, reverse_mapping, proceed_as_medicar
|
|
356
363
|
return displayed_indices, displayed_patient_ids
|
357
364
|
|
358
365
|
if proceed_as_medicare:
|
359
|
-
|
366
|
+
if not SILENT_INITIAL_SELECTION:
|
367
|
+
display_menu_header("MEDICARE Patient Selection for Today's Data Entry")
|
360
368
|
selected_indices, selected_patient_ids = display_patient_list(csv_data, reverse_mapping, medicare_filter=True)
|
361
369
|
else:
|
362
|
-
|
370
|
+
if not SILENT_INITIAL_SELECTION:
|
371
|
+
display_menu_header("PRIVATE Patient Selection for Today's Data Entry")
|
363
372
|
selected_indices, selected_patient_ids = display_patient_list(csv_data, reverse_mapping, exclude_medicare=True)
|
364
373
|
|
365
|
-
|
366
|
-
|
374
|
+
if not SILENT_INITIAL_SELECTION:
|
375
|
+
print("-" * 60)
|
376
|
+
proceed = input("\nDo you want to proceed with the selected patients? (yes/no): ").lower().strip() in ['yes', 'y']
|
377
|
+
else:
|
378
|
+
# Auto-confirm in silent mode
|
379
|
+
proceed = True
|
367
380
|
|
368
381
|
if not proceed:
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
|
382
|
+
if not SILENT_INITIAL_SELECTION:
|
383
|
+
display_menu_header("Patient Selection for Today's Data Entry")
|
384
|
+
selected_indices, selected_patient_ids = display_patient_list(csv_data, reverse_mapping)
|
385
|
+
print("-" * 60)
|
386
|
+
|
374
387
|
while True:
|
375
|
-
|
388
|
+
while True:
|
389
|
+
selection = input("\nEnter the number(s) of the patients you wish to proceed with\n(e.g., 1, 3, 5): ").strip()
|
390
|
+
if not selection:
|
391
|
+
print("Invalid entry. Please provide at least one number.")
|
392
|
+
continue
|
393
|
+
|
394
|
+
selection = selection.replace('.', ',') # Replace '.' with ',' in the user input just in case
|
395
|
+
selected_indices = [int(x.strip()) - 1 for x in selection.split(',') if x.strip().isdigit()]
|
396
|
+
|
397
|
+
if not selected_indices:
|
398
|
+
print("Invalid entry. Please provide at least one integer.")
|
399
|
+
continue
|
400
|
+
|
401
|
+
proceed = True
|
402
|
+
break
|
403
|
+
|
376
404
|
if not selection:
|
377
405
|
print("Invalid entry. Please provide at least one number.")
|
378
406
|
continue
|
@@ -386,20 +414,6 @@ def display_patient_selection_menu(csv_data, reverse_mapping, proceed_as_medicar
|
|
386
414
|
|
387
415
|
proceed = True
|
388
416
|
break
|
389
|
-
|
390
|
-
if not selection:
|
391
|
-
print("Invalid entry. Please provide at least one number.")
|
392
|
-
continue
|
393
|
-
|
394
|
-
selection = selection.replace('.', ',') # Replace '.' with ',' in the user input just in case
|
395
|
-
selected_indices = [int(x.strip()) - 1 for x in selection.split(',') if x.strip().isdigit()]
|
396
|
-
|
397
|
-
if not selected_indices:
|
398
|
-
print("Invalid entry. Please provide at least one integer.")
|
399
|
-
continue
|
400
|
-
|
401
|
-
proceed = True
|
402
|
-
break
|
403
417
|
|
404
418
|
patient_id_header = reverse_mapping['Patient ID #2']
|
405
419
|
selected_patient_ids = [csv_data[i][patient_id_header] for i in selected_indices if i < len(csv_data)]
|
@@ -498,6 +512,15 @@ def user_interaction(csv_data, interaction_mode, error_message, reverse_mapping)
|
|
498
512
|
fixed_values.update(medicare_added_fixed_values) # Add any medicare-specific fixed values from config
|
499
513
|
|
500
514
|
proceed, selected_patient_ids, selected_indices = display_patient_selection_menu(csv_data, reverse_mapping, response in ['yes', 'y'])
|
501
|
-
|
502
|
-
|
503
|
-
|
515
|
+
is_medicare = response in ['yes', 'y']
|
516
|
+
return proceed, selected_patient_ids, selected_indices, fixed_values, is_medicare
|
517
|
+
|
518
|
+
# For non-triage modes (error, normal), return a compatible structure
|
519
|
+
# The is_medicare value is not relevant in these modes, so we'll use a default
|
520
|
+
result = handle_user_interaction(interaction_mode, error_message)
|
521
|
+
if isinstance(result, int):
|
522
|
+
# This is a control value (-1, 1, -2), return with default values
|
523
|
+
return False, [], [], {}, False # proceed=False, empty lists, empty dict, is_medicare=False
|
524
|
+
else:
|
525
|
+
# Unexpected return type, handle gracefully
|
526
|
+
return False, [], [], {}, False
|
MediBot/__init__.py
CHANGED