medicafe 0.250728.8__py3-none-any.whl → 0.250805.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 +233 -19
- MediBot/MediBot.py +138 -46
- MediBot/MediBot_Crosswalk_Library.py +127 -623
- MediBot/MediBot_Crosswalk_Utils.py +618 -0
- MediBot/MediBot_Preprocessor.py +72 -17
- MediBot/MediBot_Preprocessor_lib.py +470 -76
- MediBot/MediBot_UI.py +32 -17
- MediBot/MediBot_dataformat_library.py +68 -20
- MediBot/MediBot_docx_decoder.py +120 -19
- MediBot/MediBot_smart_import.py +180 -0
- MediBot/__init__.py +89 -0
- MediBot/get_medicafe_version.py +25 -0
- MediBot/update_json.py +35 -6
- MediBot/update_medicafe.py +19 -1
- MediCafe/MediLink_ConfigLoader.py +160 -0
- MediCafe/__init__.py +171 -0
- MediCafe/__main__.py +222 -0
- MediCafe/api_core.py +1098 -0
- MediCafe/api_core_backup.py +427 -0
- MediCafe/api_factory.py +306 -0
- MediCafe/api_utils.py +356 -0
- MediCafe/core_utils.py +450 -0
- MediCafe/graphql_utils.py +445 -0
- MediCafe/logging_config.py +123 -0
- MediCafe/logging_demo.py +61 -0
- MediCafe/migration_helpers.py +463 -0
- MediCafe/smart_import.py +436 -0
- MediLink/MediLink.py +66 -26
- MediLink/MediLink_837p_cob_library.py +28 -28
- MediLink/MediLink_837p_encoder.py +33 -34
- MediLink/MediLink_837p_encoder_library.py +243 -151
- MediLink/MediLink_837p_utilities.py +129 -5
- MediLink/MediLink_API_Generator.py +83 -60
- MediLink/MediLink_API_v3.py +1 -1
- MediLink/MediLink_ClaimStatus.py +177 -31
- MediLink/MediLink_DataMgmt.py +405 -72
- MediLink/MediLink_Decoder.py +20 -1
- MediLink/MediLink_Deductible.py +155 -28
- MediLink/MediLink_Display_Utils.py +72 -0
- MediLink/MediLink_Down.py +127 -5
- MediLink/MediLink_Gmail.py +712 -653
- MediLink/MediLink_PatientProcessor.py +257 -0
- MediLink/MediLink_UI.py +85 -61
- MediLink/MediLink_Up.py +28 -4
- MediLink/MediLink_insurance_utils.py +227 -264
- MediLink/MediLink_main.py +248 -0
- MediLink/MediLink_smart_import.py +264 -0
- MediLink/__init__.py +93 -0
- MediLink/insurance_type_integration_test.py +66 -76
- MediLink/test.py +1 -1
- MediLink/test_timing.py +59 -0
- {medicafe-0.250728.8.dist-info → medicafe-0.250805.0.dist-info}/METADATA +1 -1
- medicafe-0.250805.0.dist-info/RECORD +81 -0
- medicafe-0.250805.0.dist-info/entry_points.txt +2 -0
- {medicafe-0.250728.8.dist-info → medicafe-0.250805.0.dist-info}/top_level.txt +1 -0
- medicafe-0.250728.8.dist-info/RECORD +0 -59
- {medicafe-0.250728.8.dist-info → medicafe-0.250805.0.dist-info}/LICENSE +0 -0
- {medicafe-0.250728.8.dist-info → medicafe-0.250805.0.dist-info}/WHEEL +0 -0
MediLink/MediLink_ClaimStatus.py
CHANGED
|
@@ -1,24 +1,86 @@
|
|
|
1
1
|
# MediLink_ClaimStatus.py
|
|
2
2
|
from datetime import datetime, timedelta
|
|
3
|
-
import os
|
|
4
|
-
import time
|
|
5
|
-
import json
|
|
6
|
-
import MediLink_API_v3
|
|
3
|
+
import os, sys
|
|
7
4
|
|
|
5
|
+
# Import centralized logging configuration
|
|
8
6
|
try:
|
|
9
|
-
from
|
|
7
|
+
from MediCafe.logging_config import DEBUG, PERFORMANCE_LOGGING
|
|
10
8
|
except ImportError:
|
|
11
|
-
|
|
9
|
+
# Fallback to local flags if centralized config is not available
|
|
10
|
+
DEBUG = False
|
|
11
|
+
PERFORMANCE_LOGGING = False
|
|
12
12
|
|
|
13
|
-
#
|
|
14
|
-
|
|
13
|
+
# Set up project paths first
|
|
14
|
+
project_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))
|
|
15
|
+
if project_dir not in sys.path:
|
|
16
|
+
sys.path.insert(0, project_dir)
|
|
17
|
+
|
|
18
|
+
# Use core utilities for standardized imports
|
|
19
|
+
try:
|
|
20
|
+
from MediCafe.core_utils import get_shared_config_loader, get_api_client, create_config_cache
|
|
21
|
+
MediLink_ConfigLoader = get_shared_config_loader()
|
|
22
|
+
except ImportError:
|
|
23
|
+
print("Error: Unable to import MediCafe.core_utils. Please ensure MediCafe package is properly installed.")
|
|
24
|
+
sys.exit(1)
|
|
25
|
+
|
|
26
|
+
# Import api_core for claim operations
|
|
27
|
+
try:
|
|
28
|
+
from MediCafe import api_core
|
|
29
|
+
except ImportError:
|
|
30
|
+
api_core = None
|
|
31
|
+
|
|
32
|
+
# Calculate start_date and end_date for the API:
|
|
33
|
+
# Official API documentation requires last date less than 31 days from the First Date
|
|
34
|
+
# Use a conservative 30-day range to stay within the 31-day limit
|
|
35
|
+
current_date = datetime.today()
|
|
36
|
+
end_date = current_date - timedelta(days=1) # Yesterday (avoid future dates)
|
|
37
|
+
start_date = end_date - timedelta(days=29) # 29 days before end date (30-day range total)
|
|
38
|
+
|
|
39
|
+
# Validate date range according to official API documentation
|
|
40
|
+
def validate_date_range(start_date, end_date):
|
|
41
|
+
"""Validate date range according to official API documentation"""
|
|
42
|
+
current_date = datetime.today()
|
|
43
|
+
|
|
44
|
+
if end_date > current_date:
|
|
45
|
+
raise ValueError("End date cannot be in the future")
|
|
46
|
+
|
|
47
|
+
date_diff = (end_date - start_date).days
|
|
48
|
+
if date_diff > 30: # Official docs say "less than 31 days"
|
|
49
|
+
raise ValueError("Date range must not exceed 30 days (official API limit)")
|
|
50
|
+
|
|
51
|
+
if date_diff < 0:
|
|
52
|
+
raise ValueError("Start date must be before end date")
|
|
53
|
+
|
|
54
|
+
# Check if dates are within reasonable range (last 24 months as per swagger)
|
|
55
|
+
max_start_date = current_date - timedelta(days=730) # 24 months
|
|
56
|
+
if start_date < max_start_date:
|
|
57
|
+
raise ValueError("Start date must be within last 24 months")
|
|
58
|
+
|
|
59
|
+
# Validate the calculated date range
|
|
60
|
+
try:
|
|
61
|
+
validate_date_range(start_date, end_date)
|
|
62
|
+
except ValueError as e:
|
|
63
|
+
print("Date validation error: {}".format(e))
|
|
64
|
+
# Fallback to a safe date range within 30 days
|
|
65
|
+
end_date = current_date - timedelta(days=1)
|
|
66
|
+
start_date = end_date - timedelta(days=15) # 15-day range as fallback
|
|
15
67
|
|
|
16
|
-
# Calculate start_date as 60 days before today's date and end_date as today's date
|
|
17
|
-
end_date = datetime.today()
|
|
18
|
-
start_date = end_date - timedelta(days=60)
|
|
19
68
|
end_date_str = end_date.strftime('%m/%d/%Y')
|
|
20
69
|
start_date_str = start_date.strftime('%m/%d/%Y')
|
|
21
70
|
|
|
71
|
+
# Inline commentary: The official API documentation requires last date less than 31 days
|
|
72
|
+
# from the First Date, so we use a 30-day range to stay within this limit.
|
|
73
|
+
if DEBUG:
|
|
74
|
+
print("Using date range for API compliance (30-day range, up to yesterday)")
|
|
75
|
+
print(" Start Date: {}".format(start_date_str))
|
|
76
|
+
print(" End Date: {}".format(end_date_str))
|
|
77
|
+
|
|
78
|
+
# Use latest core_utils configuration cache for better performance
|
|
79
|
+
_get_config, (_config_cache, _crosswalk_cache) = create_config_cache()
|
|
80
|
+
|
|
81
|
+
# Load configuration using latest core_utils pattern
|
|
82
|
+
config, _ = _get_config()
|
|
83
|
+
|
|
22
84
|
# Get billing provider TIN from configuration
|
|
23
85
|
billing_provider_tin = config['MediLink_Config'].get('billing_provider_tin')
|
|
24
86
|
|
|
@@ -26,8 +88,18 @@ billing_provider_tin = config['MediLink_Config'].get('billing_provider_tin')
|
|
|
26
88
|
payer_ids = ['87726', '03432', '96385', '95467', '86050', '86047', '95378', '37602']
|
|
27
89
|
# Allowed payer id's for UHC 87726, 03432, 96385, 95467, 86050, 86047, 95378, 37602. This api does not support payerId 06111.
|
|
28
90
|
|
|
29
|
-
# Initialize the API client
|
|
30
|
-
client =
|
|
91
|
+
# Initialize the API client via factory
|
|
92
|
+
client = get_api_client()
|
|
93
|
+
if client is None:
|
|
94
|
+
if DEBUG:
|
|
95
|
+
print("Warning: API client not available via factory")
|
|
96
|
+
# Fallback to direct instantiation
|
|
97
|
+
try:
|
|
98
|
+
from MediCafe import api_core
|
|
99
|
+
client = api_core.APIClient()
|
|
100
|
+
except ImportError:
|
|
101
|
+
print("Error: Unable to create API client")
|
|
102
|
+
client = None
|
|
31
103
|
|
|
32
104
|
class ClaimCache:
|
|
33
105
|
"""In-memory cache for API responses"""
|
|
@@ -132,32 +204,89 @@ def extract_claim_data(claim):
|
|
|
132
204
|
'claim_xwalk_data': claim['claimSummary']['clmXWalkData']
|
|
133
205
|
}
|
|
134
206
|
|
|
207
|
+
def handle_api_error(error, payer_id):
|
|
208
|
+
"""Handle specific API errors according to official documentation"""
|
|
209
|
+
error_message = str(error)
|
|
210
|
+
|
|
211
|
+
# Handle specific error codes from official documentation
|
|
212
|
+
if "LCLM_PS_102" in error_message:
|
|
213
|
+
return "Mandatory element missing in request (tin, firstServiceDt, lastServiceDt, or payerId)"
|
|
214
|
+
elif "LCLM_PS_105" in error_message or "LCLM_PS_202" in error_message:
|
|
215
|
+
return "Authorization error: Payer ID {} not allowed".format(payer_id)
|
|
216
|
+
elif "LCLM_PS_106" in error_message:
|
|
217
|
+
return "Invalid parameter combination: must use (firstServiceDt,lastServiceDt) or (transactionId)"
|
|
218
|
+
elif "LCLM_PS_107" in error_message:
|
|
219
|
+
return "Date range must be within last 24 months"
|
|
220
|
+
elif "LCLM_PS_108" in error_message or "LCLM_PS_111" in error_message:
|
|
221
|
+
return "Incorrect date format: use MM/dd/yyyy"
|
|
222
|
+
elif "LCLM_PS_112" in error_message:
|
|
223
|
+
return "Date range exceeds 30 days limit (official API constraint)"
|
|
224
|
+
elif "LCLM_PS_201" in error_message:
|
|
225
|
+
return "No data found with given request parameters"
|
|
226
|
+
elif "LCLM_PS_306" in error_message:
|
|
227
|
+
return "Search exceeds 500 claims limit - narrow date range"
|
|
228
|
+
elif "LCLM_PS_500" in error_message:
|
|
229
|
+
return "Server error: Exception from Claims 360 - try again later"
|
|
230
|
+
elif "401" in error_message:
|
|
231
|
+
return "Authentication error: check credentials"
|
|
232
|
+
elif "403" in error_message:
|
|
233
|
+
return "Authorization error: insufficient permissions"
|
|
234
|
+
elif "500" in error_message:
|
|
235
|
+
return "Server error: internal system failure"
|
|
236
|
+
else:
|
|
237
|
+
return "Unknown error: {}".format(error_message)
|
|
238
|
+
|
|
135
239
|
def process_claims_with_payer_rotation(billing_provider_tin, start_date_str, end_date_str,
|
|
136
240
|
payer_ids, cache, consolidated_claims):
|
|
137
241
|
"""
|
|
138
242
|
Process claims across multiple payer IDs with caching and consolidation
|
|
139
243
|
"""
|
|
140
|
-
|
|
244
|
+
from MediCafe.core_utils import get_api_client
|
|
245
|
+
client = get_api_client()
|
|
246
|
+
if client is None:
|
|
247
|
+
if DEBUG:
|
|
248
|
+
print("Warning: API client not available via factory")
|
|
249
|
+
# Fallback to direct instantiation
|
|
250
|
+
try:
|
|
251
|
+
from MediCafe import api_core
|
|
252
|
+
client = api_core.APIClient()
|
|
253
|
+
except ImportError:
|
|
254
|
+
print("Error: Unable to create API client")
|
|
255
|
+
return
|
|
141
256
|
|
|
142
257
|
for payer_id in payer_ids:
|
|
143
|
-
|
|
258
|
+
if DEBUG:
|
|
259
|
+
print("Processing Payer ID: {}".format(payer_id))
|
|
144
260
|
|
|
145
261
|
# Generate cache key
|
|
146
262
|
cache_key = cache.get_cache_key(billing_provider_tin, start_date_str, end_date_str, payer_id)
|
|
147
263
|
|
|
148
264
|
# Check cache first
|
|
149
265
|
if cache.is_cached(cache_key):
|
|
150
|
-
|
|
266
|
+
if DEBUG:
|
|
267
|
+
print(" Using cached response for Payer ID: {}".format(payer_id))
|
|
151
268
|
claim_summary = cache.get_cached_response(cache_key)
|
|
152
269
|
else:
|
|
153
|
-
|
|
270
|
+
if DEBUG:
|
|
271
|
+
print(" Making API call for Payer ID: {}".format(payer_id))
|
|
154
272
|
try:
|
|
155
|
-
|
|
156
|
-
|
|
273
|
+
# Import api_core locally to ensure it's available
|
|
274
|
+
from MediCafe import api_core
|
|
275
|
+
claim_summary = api_core.get_claim_summary_by_provider(
|
|
276
|
+
client, billing_provider_tin, start_date_str, end_date_str,
|
|
277
|
+
payer_id=payer_id
|
|
157
278
|
)
|
|
158
279
|
cache.cache_response(cache_key, claim_summary, payer_id)
|
|
159
280
|
except Exception as e:
|
|
160
|
-
|
|
281
|
+
error_msg = handle_api_error(e, payer_id)
|
|
282
|
+
print(" Error processing Payer ID {}: {}".format(payer_id, error_msg))
|
|
283
|
+
|
|
284
|
+
# Log the error for debugging (file only, not console)
|
|
285
|
+
MediLink_ConfigLoader.log(
|
|
286
|
+
"API Error for Payer ID {}: {}".format(payer_id, error_msg),
|
|
287
|
+
level="ERROR",
|
|
288
|
+
console_output=False
|
|
289
|
+
)
|
|
161
290
|
continue
|
|
162
291
|
|
|
163
292
|
# Process claims from this payer
|
|
@@ -219,14 +348,16 @@ def display_consolidated_claims(consolidated_claims, output_file):
|
|
|
219
348
|
clm508Cd = xwalk['clm508Cd']
|
|
220
349
|
clm508CdDesc = xwalk['clm508CdDesc']
|
|
221
350
|
clmIcnSufxCd = xwalk['clmIcnSufxCd']
|
|
222
|
-
|
|
223
|
-
|
|
351
|
+
if DEBUG:
|
|
352
|
+
print(" 507: {} ({}) | 508: {} ({}) | ICN Suffix: {}".format(
|
|
353
|
+
clm507Cd, clm507CdDesc, clm508Cd, clm508CdDesc, clmIcnSufxCd))
|
|
224
354
|
|
|
225
355
|
# Display duplicate warnings (terminal and log only, not file)
|
|
226
356
|
if consolidated_claims.duplicate_warnings:
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
357
|
+
if DEBUG:
|
|
358
|
+
print("\n" + "="*80)
|
|
359
|
+
print("DUPLICATE CLAIM WARNINGS:")
|
|
360
|
+
print("="*80)
|
|
230
361
|
|
|
231
362
|
for warning in consolidated_claims.duplicate_warnings:
|
|
232
363
|
warning_msg = (
|
|
@@ -244,12 +375,14 @@ def display_consolidated_claims(consolidated_claims, output_file):
|
|
|
244
375
|
warning['new_data']['total_paid_amount']
|
|
245
376
|
)
|
|
246
377
|
)
|
|
247
|
-
|
|
378
|
+
if DEBUG:
|
|
379
|
+
print(warning_msg)
|
|
248
380
|
|
|
249
|
-
# Log the warning
|
|
381
|
+
# Log the warning (file only, not console)
|
|
250
382
|
MediLink_ConfigLoader.log(
|
|
251
383
|
"Duplicate claim warning: {}".format(warning_msg),
|
|
252
|
-
level="WARNING"
|
|
384
|
+
level="WARNING",
|
|
385
|
+
console_output=False
|
|
253
386
|
)
|
|
254
387
|
|
|
255
388
|
# Initialize cache and consolidated claims
|
|
@@ -262,12 +395,25 @@ process_claims_with_payer_rotation(
|
|
|
262
395
|
)
|
|
263
396
|
|
|
264
397
|
# Display consolidated results
|
|
265
|
-
|
|
398
|
+
temp_dir = os.getenv('TEMP') or os.getenv('TMP') or '/tmp' # Cross-platform temp directory
|
|
399
|
+
output_file_path = os.path.join(temp_dir, 'claim_summary_report.txt')
|
|
266
400
|
with open(output_file_path, 'w') as output_file:
|
|
267
401
|
display_consolidated_claims(consolidated_claims, output_file)
|
|
268
402
|
|
|
269
403
|
# Clear cache after consolidated table is generated
|
|
270
404
|
cache.clear_cache()
|
|
271
405
|
|
|
272
|
-
# Open the generated file
|
|
273
|
-
|
|
406
|
+
# Open the generated file (cross-platform approach)
|
|
407
|
+
try:
|
|
408
|
+
if os.name == 'nt': # Windows
|
|
409
|
+
os.startfile(output_file_path)
|
|
410
|
+
elif os.name == 'posix': # Unix/Linux/MacOS
|
|
411
|
+
import subprocess
|
|
412
|
+
subprocess.call(['xdg-open', output_file_path])
|
|
413
|
+
else:
|
|
414
|
+
if DEBUG:
|
|
415
|
+
print("File saved to: {}".format(output_file_path))
|
|
416
|
+
except Exception as e:
|
|
417
|
+
if DEBUG:
|
|
418
|
+
print("File saved to: {}".format(output_file_path))
|
|
419
|
+
print("Could not open file automatically: {}".format(e))
|