medicafe 0.250912.0__py3-none-any.whl → 0.250930.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/__init__.py +1 -1
- MediCafe/MediLink_ConfigLoader.py +7 -0
- MediCafe/__init__.py +1 -1
- MediCafe/api_core.py +151 -10
- MediCafe/error_reporter.py +287 -0
- MediLink/MediLink_837p_encoder_library.py +18 -15
- MediLink/MediLink_Deductible.py +47 -3
- MediLink/MediLink_Display_Utils.py +37 -1
- MediLink/MediLink_main.py +57 -0
- MediLink/__init__.py +1 -1
- {medicafe-0.250912.0.dist-info → medicafe-0.250930.0.dist-info}/METADATA +1 -1
- {medicafe-0.250912.0.dist-info → medicafe-0.250930.0.dist-info}/RECORD +16 -15
- {medicafe-0.250912.0.dist-info → medicafe-0.250930.0.dist-info}/LICENSE +0 -0
- {medicafe-0.250912.0.dist-info → medicafe-0.250930.0.dist-info}/WHEEL +0 -0
- {medicafe-0.250912.0.dist-info → medicafe-0.250930.0.dist-info}/entry_points.txt +0 -0
- {medicafe-0.250912.0.dist-info → medicafe-0.250930.0.dist-info}/top_level.txt +0 -0
MediBot/__init__.py
CHANGED
@@ -33,6 +33,13 @@ def get_default_config():
|
|
33
33
|
'level': 'INFO',
|
34
34
|
'console_output': True
|
35
35
|
},
|
36
|
+
'error_reporting': {
|
37
|
+
'enabled': False,
|
38
|
+
'endpoint_url': '',
|
39
|
+
'auth_token': '',
|
40
|
+
'insecure_http': False,
|
41
|
+
'max_bundle_bytes': 2097152
|
42
|
+
},
|
36
43
|
# STRATEGIC NOTE (COB Configuration): COB library is fully implemented and ready
|
37
44
|
# To enable COB functionality, add the following configuration:
|
38
45
|
# 'cob_settings': {
|
MediCafe/__init__.py
CHANGED
MediCafe/api_core.py
CHANGED
@@ -6,7 +6,7 @@ Moved from MediLink to centralize shared API operations.
|
|
6
6
|
COMPATIBILITY: Python 3.4.4 and Windows XP compatible
|
7
7
|
"""
|
8
8
|
|
9
|
-
import time, json, os, traceback, sys
|
9
|
+
import time, json, os, traceback, sys
|
10
10
|
|
11
11
|
# Import centralized logging configuration
|
12
12
|
try:
|
@@ -689,21 +689,61 @@ class APIClient(BaseAPIClient):
|
|
689
689
|
MediLink_ConfigLoader.log(log_message, level="ERROR")
|
690
690
|
raise
|
691
691
|
|
692
|
-
def fetch_payer_name_from_api(
|
692
|
+
def fetch_payer_name_from_api(*args, **kwargs):
|
693
693
|
"""
|
694
|
-
|
694
|
+
Fetch payer name by Payer ID with backward-compatible calling styles.
|
695
695
|
|
696
|
-
|
697
|
-
|
698
|
-
|
699
|
-
|
696
|
+
Supported call signatures:
|
697
|
+
- fetch_payer_name_from_api(client, payer_id, config, primary_endpoint='AVAILITY')
|
698
|
+
- fetch_payer_name_from_api(payer_id, config, primary_endpoint='AVAILITY') # client inferred via factory
|
699
|
+
- fetch_payer_name_from_api(payer_id=payer_id, config=config, client=client, primary_endpoint='AVAILITY')
|
700
700
|
"""
|
701
|
-
#
|
701
|
+
# Normalize arguments
|
702
|
+
client = None
|
703
|
+
payer_id = None
|
704
|
+
config = None
|
705
|
+
primary_endpoint = kwargs.get('primary_endpoint', 'AVAILITY')
|
706
|
+
|
707
|
+
if 'client' in kwargs:
|
708
|
+
client = kwargs.get('client')
|
709
|
+
if 'payer_id' in kwargs:
|
710
|
+
payer_id = kwargs.get('payer_id')
|
711
|
+
if 'config' in kwargs:
|
712
|
+
config = kwargs.get('config')
|
713
|
+
|
714
|
+
if len(args) >= 3 and isinstance(args[0], APIClient):
|
715
|
+
client = args[0]
|
716
|
+
payer_id = args[1]
|
717
|
+
config = args[2]
|
718
|
+
if len(args) >= 4 and 'primary_endpoint' not in kwargs:
|
719
|
+
primary_endpoint = args[3]
|
720
|
+
elif len(args) >= 2 and isinstance(args[0], str) and client is None:
|
721
|
+
# Called as (payer_id, config, [primary_endpoint])
|
722
|
+
payer_id = args[0]
|
723
|
+
config = args[1]
|
724
|
+
if len(args) >= 3 and 'primary_endpoint' not in kwargs:
|
725
|
+
primary_endpoint = args[2]
|
726
|
+
elif len(args) == 1 and isinstance(args[0], APIClient) and (payer_id is None or config is None):
|
727
|
+
# Partial positional with client first, other params via kwargs
|
728
|
+
client = args[0]
|
729
|
+
|
730
|
+
# Acquire client via factory if not provided
|
731
|
+
if client is None:
|
732
|
+
try:
|
733
|
+
from MediCafe.core_utils import get_api_client
|
734
|
+
client = get_api_client()
|
735
|
+
if client is None:
|
736
|
+
client = APIClient()
|
737
|
+
except Exception:
|
738
|
+
client = APIClient()
|
739
|
+
|
740
|
+
# Basic validation
|
702
741
|
if not isinstance(client, APIClient):
|
703
742
|
error_message = "Invalid client provided. Expected an instance of APIClient."
|
704
|
-
print(error_message)
|
705
743
|
MediLink_ConfigLoader.log(error_message, level="ERROR")
|
706
|
-
|
744
|
+
raise ValueError(error_message)
|
745
|
+
if payer_id is None or config is None:
|
746
|
+
raise ValueError("Missing required arguments: payer_id and config are required")
|
707
747
|
|
708
748
|
# TODO: FUTURE IMPLEMENTATION - Remove AVAILITY default when other endpoints have payer-list APIs
|
709
749
|
# Currently defaulting to AVAILITY as it's the only endpoint with confirmed payer-list functionality
|
@@ -750,6 +790,66 @@ def fetch_payer_name_from_api(client, payer_id, config, primary_endpoint='AVAILI
|
|
750
790
|
# 3. Fall back to endpoints with basic payer lookup if available
|
751
791
|
# 4. Use AVAILITY as final fallback
|
752
792
|
|
793
|
+
# If HTTP client is unavailable or endpoints missing, use offline fallback only when allowed (TestMode or env flag)
|
794
|
+
try:
|
795
|
+
http_unavailable = (requests is None) # type: ignore[name-defined]
|
796
|
+
except Exception:
|
797
|
+
http_unavailable = True
|
798
|
+
# Determine whether offline fallback is permitted
|
799
|
+
# Align with main flow: default True when TestMode key is absent
|
800
|
+
offline_allowed = True
|
801
|
+
try:
|
802
|
+
from MediCafe.core_utils import extract_medilink_config
|
803
|
+
medi_local = extract_medilink_config(config)
|
804
|
+
offline_allowed = bool(medi_local.get('TestMode', True))
|
805
|
+
except Exception:
|
806
|
+
offline_allowed = True
|
807
|
+
try:
|
808
|
+
if os.environ.get('MEDICAFE_OFFLINE_PERMISSIVE', '').strip().lower() in ('1', 'true', 'yes', 'y'):
|
809
|
+
offline_allowed = True
|
810
|
+
except Exception:
|
811
|
+
pass
|
812
|
+
|
813
|
+
if offline_allowed and (http_unavailable or not isinstance(endpoints, dict) or not endpoints):
|
814
|
+
try:
|
815
|
+
# Prefer crosswalk mapping when available
|
816
|
+
try:
|
817
|
+
_, cw = MediLink_ConfigLoader.load_configuration()
|
818
|
+
except Exception:
|
819
|
+
cw = {}
|
820
|
+
payer_mappings = {}
|
821
|
+
try:
|
822
|
+
if isinstance(cw, dict):
|
823
|
+
payer_mappings = cw.get('payer_mappings', {}) or {}
|
824
|
+
except Exception:
|
825
|
+
payer_mappings = {}
|
826
|
+
|
827
|
+
if payer_id in payer_mappings:
|
828
|
+
resolved = payer_mappings.get(payer_id)
|
829
|
+
MediLink_ConfigLoader.log(
|
830
|
+
"Using crosswalk mapping for payer {} -> {} (offline)".format(payer_id, resolved),
|
831
|
+
level="WARNING",
|
832
|
+
console_output=CONSOLE_LOGGING
|
833
|
+
)
|
834
|
+
return resolved
|
835
|
+
# Safe minimal hardcoded map as last resort (test/offline only)
|
836
|
+
fallback_map = {
|
837
|
+
'87726': 'UnitedHealthcare',
|
838
|
+
'06111': 'Aetna',
|
839
|
+
'03432': 'Cigna',
|
840
|
+
'95378': 'Anthem Blue Cross',
|
841
|
+
'95467': 'Blue Shield',
|
842
|
+
}
|
843
|
+
if payer_id in fallback_map:
|
844
|
+
MediLink_ConfigLoader.log(
|
845
|
+
"Using offline fallback for payer {} -> {}".format(payer_id, fallback_map[payer_id]),
|
846
|
+
level="WARNING",
|
847
|
+
console_output=CONSOLE_LOGGING
|
848
|
+
)
|
849
|
+
return fallback_map[payer_id]
|
850
|
+
except Exception:
|
851
|
+
pass
|
852
|
+
|
753
853
|
# Define endpoint rotation logic with payer-list capability detection
|
754
854
|
available_endpoints = []
|
755
855
|
|
@@ -820,6 +920,47 @@ def fetch_payer_name_from_api(client, payer_id, config, primary_endpoint='AVAILI
|
|
820
920
|
error_message = "Error calling {0} for Payer ID {1}. Exception: {2}".format(endpoint_name, payer_id, e)
|
821
921
|
MediLink_ConfigLoader.log(error_message, level="INFO")
|
822
922
|
|
923
|
+
# Offline/local fallback mapping for common payer IDs when API endpoints are unavailable
|
924
|
+
# Only when offline fallback is permitted
|
925
|
+
if offline_allowed:
|
926
|
+
try:
|
927
|
+
# Prefer crosswalk mapping first
|
928
|
+
try:
|
929
|
+
_, cw = MediLink_ConfigLoader.load_configuration()
|
930
|
+
except Exception:
|
931
|
+
cw = {}
|
932
|
+
payer_mappings = {}
|
933
|
+
try:
|
934
|
+
if isinstance(cw, dict):
|
935
|
+
payer_mappings = cw.get('payer_mappings', {}) or {}
|
936
|
+
except Exception:
|
937
|
+
payer_mappings = {}
|
938
|
+
if payer_id in payer_mappings:
|
939
|
+
resolved = payer_mappings.get(payer_id)
|
940
|
+
MediLink_ConfigLoader.log(
|
941
|
+
"Using crosswalk mapping for payer {} -> {} (offline)".format(payer_id, resolved),
|
942
|
+
level="WARNING",
|
943
|
+
console_output=CONSOLE_LOGGING
|
944
|
+
)
|
945
|
+
return resolved
|
946
|
+
# Minimal fallback map if crosswalk has no mapping (still offline-only)
|
947
|
+
fallback_map = {
|
948
|
+
'87726': 'UnitedHealthcare',
|
949
|
+
'06111': 'Aetna',
|
950
|
+
'03432': 'Cigna',
|
951
|
+
'95378': 'Anthem Blue Cross',
|
952
|
+
'95467': 'Blue Shield',
|
953
|
+
}
|
954
|
+
if payer_id in fallback_map:
|
955
|
+
MediLink_ConfigLoader.log(
|
956
|
+
"Using offline fallback for payer {} -> {}".format(payer_id, fallback_map[payer_id]),
|
957
|
+
level="WARNING",
|
958
|
+
console_output=CONSOLE_LOGGING
|
959
|
+
)
|
960
|
+
return fallback_map[payer_id]
|
961
|
+
except Exception:
|
962
|
+
pass
|
963
|
+
|
823
964
|
# If all endpoints fail
|
824
965
|
final_error_message = "All endpoints exhausted for Payer ID {0}.".format(payer_id)
|
825
966
|
print(final_error_message)
|
@@ -0,0 +1,287 @@
|
|
1
|
+
import os, sys, time, json, zipfile, hashlib, platform
|
2
|
+
|
3
|
+
try:
|
4
|
+
import requests
|
5
|
+
except Exception:
|
6
|
+
requests = None
|
7
|
+
|
8
|
+
from MediCafe.MediLink_ConfigLoader import load_configuration, log as mc_log
|
9
|
+
|
10
|
+
|
11
|
+
ASCII_SAFE_REPLACEMENTS = [
|
12
|
+
('"', '"'),
|
13
|
+
("'", "'"),
|
14
|
+
]
|
15
|
+
|
16
|
+
|
17
|
+
def _safe_ascii(text):
|
18
|
+
try:
|
19
|
+
if text is None:
|
20
|
+
return ''
|
21
|
+
if isinstance(text, bytes):
|
22
|
+
try:
|
23
|
+
text = text.decode('ascii', 'ignore')
|
24
|
+
except Exception:
|
25
|
+
text = text.decode('utf-8', 'ignore')
|
26
|
+
else:
|
27
|
+
text = str(text)
|
28
|
+
return text.encode('ascii', 'ignore').decode('ascii', 'ignore')
|
29
|
+
except Exception:
|
30
|
+
return ''
|
31
|
+
|
32
|
+
|
33
|
+
def _tail_file(path, max_lines):
|
34
|
+
lines = []
|
35
|
+
try:
|
36
|
+
with open(path, 'r') as f:
|
37
|
+
for line in f:
|
38
|
+
lines.append(line)
|
39
|
+
if len(lines) > max_lines:
|
40
|
+
lines.pop(0)
|
41
|
+
return ''.join(lines)
|
42
|
+
except Exception:
|
43
|
+
return ''
|
44
|
+
|
45
|
+
|
46
|
+
def _get_latest_log_path(local_storage_path):
|
47
|
+
try:
|
48
|
+
files = []
|
49
|
+
for name in os.listdir(local_storage_path or '.'):
|
50
|
+
if name.startswith('Log_') and name.endswith('.log'):
|
51
|
+
files.append(os.path.join(local_storage_path, name))
|
52
|
+
if not files:
|
53
|
+
return None
|
54
|
+
files.sort(key=lambda p: os.path.getmtime(p))
|
55
|
+
return files[-1]
|
56
|
+
except Exception:
|
57
|
+
return None
|
58
|
+
|
59
|
+
|
60
|
+
def _redact(text):
|
61
|
+
# Best-effort ASCII redaction: mask obvious numeric IDs and bearer tokens
|
62
|
+
try:
|
63
|
+
text = _safe_ascii(text)
|
64
|
+
import re
|
65
|
+
patterns = [
|
66
|
+
(r'\b(\d{3}-?\d{2}-?\d{4})\b', '***-**-****'),
|
67
|
+
(r'\b(\d{9,11})\b', '*********'),
|
68
|
+
(r'Bearer\s+[A-Za-z0-9\-._~+/]+=*', 'Bearer ***'),
|
69
|
+
(r'Authorization:\s*[^\n\r]+', 'Authorization: ***'),
|
70
|
+
]
|
71
|
+
for pat, rep in patterns:
|
72
|
+
text = re.sub(pat, rep, text)
|
73
|
+
return text
|
74
|
+
except Exception:
|
75
|
+
return text
|
76
|
+
|
77
|
+
|
78
|
+
def _ensure_dir(path):
|
79
|
+
try:
|
80
|
+
if not os.path.exists(path):
|
81
|
+
os.makedirs(path)
|
82
|
+
return True
|
83
|
+
except Exception:
|
84
|
+
return False
|
85
|
+
|
86
|
+
|
87
|
+
def _compute_report_id(zip_path):
|
88
|
+
try:
|
89
|
+
h = hashlib.sha256()
|
90
|
+
with open(zip_path, 'rb') as f:
|
91
|
+
chunk = f.read(256 * 1024)
|
92
|
+
h.update(chunk)
|
93
|
+
return 'mc-{}-{}'.format(int(time.time()), h.hexdigest()[:12])
|
94
|
+
except Exception:
|
95
|
+
return 'mc-{}-{}'.format(int(time.time()), '000000000000')
|
96
|
+
|
97
|
+
|
98
|
+
def collect_support_bundle(include_traceback=True, max_log_lines=2000):
|
99
|
+
config, _ = load_configuration()
|
100
|
+
medi = config.get('MediLink_Config', {})
|
101
|
+
local_storage_path = medi.get('local_storage_path', '.')
|
102
|
+
queue_dir = os.path.join(local_storage_path, 'reports_queue')
|
103
|
+
_ensure_dir(queue_dir)
|
104
|
+
|
105
|
+
stamp = time.strftime('%Y%m%d_%H%M%S')
|
106
|
+
bundle_name = 'support_report_{}.zip'.format(stamp)
|
107
|
+
zip_path = os.path.join(queue_dir, bundle_name)
|
108
|
+
|
109
|
+
latest_log = _get_latest_log_path(local_storage_path)
|
110
|
+
log_tail = _tail_file(latest_log, max_log_lines) if latest_log else ''
|
111
|
+
log_tail = _redact(log_tail)
|
112
|
+
|
113
|
+
traceback_txt = ''
|
114
|
+
if include_traceback:
|
115
|
+
try:
|
116
|
+
trace_path = os.path.join(local_storage_path, 'traceback.txt')
|
117
|
+
if os.path.exists(trace_path):
|
118
|
+
with open(trace_path, 'r') as tf:
|
119
|
+
traceback_txt = _redact(tf.read())
|
120
|
+
except Exception:
|
121
|
+
traceback_txt = ''
|
122
|
+
|
123
|
+
meta = {
|
124
|
+
'app_version': _safe_ascii(_get_version()),
|
125
|
+
'python_version': _safe_ascii(sys.version.split(' ')[0]),
|
126
|
+
'platform': _safe_ascii(platform.platform()),
|
127
|
+
'timestamp': time.strftime('%Y-%m-%dT%H:%M:%SZ', time.gmtime()),
|
128
|
+
'error_summary': _safe_ascii(_first_line(traceback_txt)),
|
129
|
+
'traceback_present': bool(traceback_txt),
|
130
|
+
'config_flags': {
|
131
|
+
'console_logging': bool(medi.get('logging', {}).get('console_output', False)),
|
132
|
+
'test_mode': bool(medi.get('TestMode', False))
|
133
|
+
}
|
134
|
+
}
|
135
|
+
|
136
|
+
try:
|
137
|
+
with zipfile.ZipFile(zip_path, 'w', zipfile.ZIP_DEFLATED) as z:
|
138
|
+
z.writestr('meta.json', json.dumps(meta, ensure_ascii=True, indent=2))
|
139
|
+
if latest_log and log_tail:
|
140
|
+
z.writestr('log_tail.txt', log_tail)
|
141
|
+
if traceback_txt:
|
142
|
+
z.writestr('traceback.txt', traceback_txt)
|
143
|
+
z.writestr('README.txt', _readme_text())
|
144
|
+
return zip_path
|
145
|
+
except Exception as e:
|
146
|
+
mc_log('Error creating support bundle: {}'.format(e), level='ERROR')
|
147
|
+
return None
|
148
|
+
|
149
|
+
|
150
|
+
def _first_line(text):
|
151
|
+
try:
|
152
|
+
for line in (text or '').splitlines():
|
153
|
+
line = line.strip()
|
154
|
+
if line:
|
155
|
+
return line[:200]
|
156
|
+
return ''
|
157
|
+
except Exception:
|
158
|
+
return ''
|
159
|
+
|
160
|
+
|
161
|
+
def _readme_text():
|
162
|
+
return (
|
163
|
+
"MediCafe Support Bundle\n\n"
|
164
|
+
"This archive contains a redacted log tail, optional traceback, and metadata.\n"
|
165
|
+
"You may submit this bundle automatically from the app or send it manually to support.\n"
|
166
|
+
)
|
167
|
+
|
168
|
+
|
169
|
+
def _get_version():
|
170
|
+
try:
|
171
|
+
from MediCafe import __version__
|
172
|
+
return __version__
|
173
|
+
except Exception:
|
174
|
+
return 'unknown'
|
175
|
+
|
176
|
+
|
177
|
+
def submit_support_bundle(zip_path):
|
178
|
+
config, _ = load_configuration()
|
179
|
+
medi = config.get('MediLink_Config', {})
|
180
|
+
rep = medi.get('error_reporting', {}) if isinstance(medi, dict) else {}
|
181
|
+
endpoint_url = _safe_ascii(rep.get('endpoint_url', ''))
|
182
|
+
auth_token = _safe_ascii(rep.get('auth_token', ''))
|
183
|
+
insecure = bool(rep.get('insecure_http', False))
|
184
|
+
max_bytes = int(rep.get('max_bundle_bytes', 2097152))
|
185
|
+
|
186
|
+
if not requests:
|
187
|
+
print("[ERROR] requests module not available; cannot submit report.")
|
188
|
+
return False
|
189
|
+
if not endpoint_url:
|
190
|
+
print("[ERROR] error_reporting.endpoint_url not configured.")
|
191
|
+
return False
|
192
|
+
if not os.path.exists(zip_path):
|
193
|
+
print("[ERROR] Bundle not found: {}".format(zip_path))
|
194
|
+
return False
|
195
|
+
try:
|
196
|
+
size = os.path.getsize(zip_path)
|
197
|
+
if size > max_bytes:
|
198
|
+
print("[INFO] Bundle size {} exceeds cap {}; rebuilding smaller not implemented here.".format(size, max_bytes))
|
199
|
+
except Exception:
|
200
|
+
pass
|
201
|
+
|
202
|
+
report_id = _compute_report_id(zip_path)
|
203
|
+
headers = {
|
204
|
+
'X-Auth-Token': auth_token or '',
|
205
|
+
'X-Report-Id': report_id,
|
206
|
+
'User-Agent': 'MediCafe-Reporter/1.0'
|
207
|
+
}
|
208
|
+
|
209
|
+
# Prepare meta.json stream derived from inside the zip for server convenience
|
210
|
+
meta_json = '{}'
|
211
|
+
try:
|
212
|
+
with zipfile.ZipFile(zip_path, 'r') as z:
|
213
|
+
if 'meta.json' in z.namelist():
|
214
|
+
meta_json = z.read('meta.json')
|
215
|
+
except Exception:
|
216
|
+
meta_json = '{}'
|
217
|
+
|
218
|
+
try:
|
219
|
+
bundle_fh = open(zip_path, 'rb')
|
220
|
+
files = {
|
221
|
+
'meta': ('meta.json', meta_json, 'application/json'),
|
222
|
+
'bundle': (os.path.basename(zip_path), bundle_fh, 'application/zip')
|
223
|
+
}
|
224
|
+
r = requests.post(endpoint_url, headers=headers, files=files, timeout=(10, 20), verify=(not insecure))
|
225
|
+
code = getattr(r, 'status_code', None)
|
226
|
+
if code == 200:
|
227
|
+
print("[SUCCESS] Report submitted. ID: {}".format(report_id))
|
228
|
+
return True
|
229
|
+
elif code == 401:
|
230
|
+
print("[ERROR] Unauthorized (401). Check error_reporting.auth_token.")
|
231
|
+
return False
|
232
|
+
elif code == 413:
|
233
|
+
print("[ERROR] Too large (413). Consider reducing max log lines.")
|
234
|
+
return False
|
235
|
+
else:
|
236
|
+
print("[ERROR] Submission failed with status {}".format(code))
|
237
|
+
return False
|
238
|
+
except Exception as e:
|
239
|
+
print("[ERROR] Submission exception: {}".format(e))
|
240
|
+
return False
|
241
|
+
finally:
|
242
|
+
try:
|
243
|
+
bundle_fh.close()
|
244
|
+
except Exception:
|
245
|
+
pass
|
246
|
+
|
247
|
+
|
248
|
+
def flush_queued_reports():
|
249
|
+
config, _ = load_configuration()
|
250
|
+
medi = config.get('MediLink_Config', {})
|
251
|
+
local_storage_path = medi.get('local_storage_path', '.')
|
252
|
+
queue_dir = os.path.join(local_storage_path, 'reports_queue')
|
253
|
+
if not os.path.isdir(queue_dir):
|
254
|
+
return 0, 0
|
255
|
+
count_ok = 0
|
256
|
+
count_total = 0
|
257
|
+
for name in sorted(os.listdir(queue_dir)):
|
258
|
+
if not name.endswith('.zip'):
|
259
|
+
continue
|
260
|
+
zip_path = os.path.join(queue_dir, name)
|
261
|
+
count_total += 1
|
262
|
+
print("Attempting upload of queued report: {}".format(name))
|
263
|
+
ok = submit_support_bundle(zip_path)
|
264
|
+
if ok:
|
265
|
+
try:
|
266
|
+
os.remove(zip_path)
|
267
|
+
except Exception:
|
268
|
+
pass
|
269
|
+
count_ok += 1
|
270
|
+
return count_ok, count_total
|
271
|
+
|
272
|
+
|
273
|
+
def capture_unhandled_traceback(exc_type, exc_value, exc_traceback):
|
274
|
+
try:
|
275
|
+
config, _ = load_configuration()
|
276
|
+
medi = config.get('MediLink_Config', {})
|
277
|
+
local_storage_path = medi.get('local_storage_path', '.')
|
278
|
+
trace_path = os.path.join(local_storage_path, 'traceback.txt')
|
279
|
+
import traceback
|
280
|
+
text = ''.join(traceback.format_exception(exc_type, exc_value, exc_traceback))
|
281
|
+
text = _redact(text)
|
282
|
+
with open(trace_path, 'w') as f:
|
283
|
+
f.write(text)
|
284
|
+
print("An error occurred. A traceback was saved to {}".format(trace_path))
|
285
|
+
except Exception:
|
286
|
+
pass
|
287
|
+
|
@@ -87,21 +87,24 @@ except (ImportError, SystemError):
|
|
87
87
|
except ImportError:
|
88
88
|
MediLink_UI = None
|
89
89
|
|
90
|
-
# Import MediBot crosswalk utilities
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
90
|
+
# Import MediBot crosswalk utilities via centralized import helpers
|
91
|
+
from MediCafe.core_utils import import_medibot_module
|
92
|
+
|
93
|
+
# Resolve required functions directly at import-time using centralized helper (Py 3.4.4 friendly)
|
94
|
+
update_crosswalk_with_new_payer_id = (
|
95
|
+
import_medibot_module('MediBot_Crosswalk_Utils', 'update_crosswalk_with_new_payer_id') or
|
96
|
+
import_medibot_module('MediBot_Crosswalk_Library', 'update_crosswalk_with_new_payer_id')
|
97
|
+
)
|
98
|
+
|
99
|
+
update_crosswalk_with_corrected_payer_id = (
|
100
|
+
import_medibot_module('MediBot_Crosswalk_Utils', 'update_crosswalk_with_corrected_payer_id') or
|
101
|
+
import_medibot_module('MediBot_Crosswalk_Library', 'update_crosswalk_with_corrected_payer_id')
|
102
|
+
)
|
103
|
+
|
104
|
+
if not callable(update_crosswalk_with_new_payer_id):
|
105
|
+
raise RuntimeError("Crosswalk update function not available (new payer id). Ensure MediBot_Crosswalk_Utils or MediBot_Crosswalk_Library is importable.")
|
106
|
+
if not callable(update_crosswalk_with_corrected_payer_id):
|
107
|
+
raise RuntimeError("Crosswalk update function not available (corrected payer id). Ensure MediBot_Crosswalk_Utils or MediBot_Crosswalk_Library is importable.")
|
105
108
|
|
106
109
|
# Import enhanced insurance selection with fallback
|
107
110
|
# XP/Python34 Compatibility: Enhanced error handling with verbose output
|
MediLink/MediLink_Deductible.py
CHANGED
@@ -390,17 +390,50 @@ def manual_deductible_lookup():
|
|
390
390
|
# Already processed data from merge_responses
|
391
391
|
enhanced_result = eligibility_data
|
392
392
|
elif convert_eligibility_to_enhanced_format is not None:
|
393
|
+
# Attempt CSV backfill context for manual route
|
394
|
+
csv_row = patient_row_index.get((formatted_dob, member_id))
|
395
|
+
derived_patient_id = ""
|
396
|
+
derived_service_date = ""
|
397
|
+
if csv_row:
|
398
|
+
try:
|
399
|
+
derived_patient_id = str(csv_row.get('Patient ID #2', csv_row.get('Patient ID', '')))
|
400
|
+
derived_service_date = str(csv_row.get('Service Date', ''))
|
401
|
+
except Exception:
|
402
|
+
derived_patient_id = ""
|
403
|
+
derived_service_date = ""
|
393
404
|
# Raw API data needs conversion with patient info
|
394
|
-
enhanced_result = convert_eligibility_to_enhanced_format(
|
405
|
+
enhanced_result = convert_eligibility_to_enhanced_format(
|
406
|
+
eligibility_data, formatted_dob, member_id, derived_patient_id, derived_service_date
|
407
|
+
)
|
395
408
|
else:
|
396
409
|
# Fallback if utility function not available
|
397
410
|
enhanced_result = None
|
398
411
|
if enhanced_result:
|
399
412
|
try:
|
400
413
|
# Backfill with CSV row data when available
|
401
|
-
|
414
|
+
csv_row = patient_row_index.get((formatted_dob, member_id))
|
415
|
+
enhanced_result = backfill_enhanced_result(enhanced_result, csv_row)
|
416
|
+
except Exception:
|
417
|
+
pass
|
418
|
+
# Ensure patient_id present; warn/log and set surrogate if missing
|
419
|
+
try:
|
420
|
+
pid = str(enhanced_result.get('patient_id', '')).strip()
|
421
|
+
if not pid:
|
422
|
+
surrogate = "{}:{}".format(formatted_dob, member_id)
|
423
|
+
enhanced_result['patient_id'] = surrogate
|
424
|
+
print("Warning: Missing Patient ID; using surrogate key {}".format(surrogate))
|
425
|
+
MediLink_ConfigLoader.log(
|
426
|
+
"Manual lookup: Missing Patient ID; using surrogate key {}".format(surrogate),
|
427
|
+
level="WARNING"
|
428
|
+
)
|
402
429
|
except Exception:
|
403
430
|
pass
|
431
|
+
# Ensure patient_name not blank
|
432
|
+
try:
|
433
|
+
if not str(enhanced_result.get('patient_name', '')).strip():
|
434
|
+
enhanced_result['patient_name'] = 'Unknown Patient'
|
435
|
+
except Exception:
|
436
|
+
enhanced_result['patient_name'] = 'Unknown Patient'
|
404
437
|
print("\n" + "=" * 60)
|
405
438
|
display_enhanced_deductible_table([enhanced_result], context="post_api",
|
406
439
|
title="Manual Lookup Result")
|
@@ -441,7 +474,18 @@ def manual_deductible_lookup():
|
|
441
474
|
"Patient Name", "DOB", "Insurance Type", "PayID", "Policy Status", "Remaining Amt")
|
442
475
|
output_file.write(table_header + "\n")
|
443
476
|
output_file.write("-" * len(table_header) + "\n")
|
444
|
-
|
477
|
+
# Write directly from enhanced_result to ensure CSV backfill/defaults are preserved
|
478
|
+
if enhanced_result:
|
479
|
+
table_row = "{:<20} | {:<10} | {:<40} | {:<5} | {:<14} | {:<14}".format(
|
480
|
+
enhanced_result['patient_name'][:20],
|
481
|
+
enhanced_result['dob'],
|
482
|
+
enhanced_result['insurance_type'][:40],
|
483
|
+
enhanced_result['payer_id'][:5],
|
484
|
+
enhanced_result['policy_status'][:14],
|
485
|
+
enhanced_result['remaining_amount'][:14])
|
486
|
+
output_file.write(table_row + "\n")
|
487
|
+
else:
|
488
|
+
display_eligibility_info(eligibility_data, formatted_dob, member_id, output_file)
|
445
489
|
|
446
490
|
# Ask if user wants to open the report
|
447
491
|
open_report = input("\nEligibility data found! Open the report? (Y/N): ").strip().lower()
|
@@ -177,6 +177,20 @@ def _normalize_pre_api_data(row):
|
|
177
177
|
member_id = row.get('Primary Policy Number', row.get('Ins1 Member ID', '')).strip()
|
178
178
|
payer_id = row.get('Ins1 Payer ID', '')
|
179
179
|
patient_id = row.get('Patient ID #2', row.get('Patient ID', ''))
|
180
|
+
|
181
|
+
# Surrogate key and warnings if patient_id missing/blank
|
182
|
+
if not str(patient_id).strip():
|
183
|
+
surrogate = "{}:{}".format(dob, member_id)
|
184
|
+
patient_id = surrogate
|
185
|
+
try:
|
186
|
+
# Print visible warning and log as WARNING event
|
187
|
+
print("Warning: Missing Patient ID in CSV row; using surrogate key {}".format(surrogate))
|
188
|
+
MediLink_ConfigLoader.log(
|
189
|
+
"Missing Patient ID in CSV; using surrogate key {}".format(surrogate),
|
190
|
+
level="WARNING"
|
191
|
+
)
|
192
|
+
except Exception:
|
193
|
+
pass
|
180
194
|
|
181
195
|
return {
|
182
196
|
'patient_id': str(patient_id),
|
@@ -200,7 +214,7 @@ def _normalize_post_api_data(eligibility_result):
|
|
200
214
|
try:
|
201
215
|
# Handle the enhanced format that comes from convert_eligibility_to_enhanced_format
|
202
216
|
if isinstance(eligibility_result, dict):
|
203
|
-
|
217
|
+
normalized = {
|
204
218
|
'patient_id': str(eligibility_result.get('patient_id', '')),
|
205
219
|
'patient_name': str(eligibility_result.get('patient_name', '')),
|
206
220
|
'dob': str(eligibility_result.get('dob', '')),
|
@@ -214,6 +228,28 @@ def _normalize_post_api_data(eligibility_result):
|
|
214
228
|
'remaining_amount': str(eligibility_result.get('remaining_amount', '')),
|
215
229
|
'data_source': str(eligibility_result.get('data_source', ''))
|
216
230
|
}
|
231
|
+
|
232
|
+
# Default unknown patient name when blank
|
233
|
+
try:
|
234
|
+
if not normalized['patient_name'].strip():
|
235
|
+
normalized['patient_name'] = 'Unknown Patient'
|
236
|
+
except Exception:
|
237
|
+
normalized['patient_name'] = 'Unknown Patient'
|
238
|
+
|
239
|
+
# Surrogate key and warnings if patient_id missing/blank
|
240
|
+
try:
|
241
|
+
if not normalized['patient_id'].strip():
|
242
|
+
surrogate = "{}:{}".format(normalized.get('dob', ''), normalized.get('member_id', ''))
|
243
|
+
normalized['patient_id'] = surrogate
|
244
|
+
print("Warning: Missing Patient ID in eligibility result; using surrogate key {}".format(surrogate))
|
245
|
+
MediLink_ConfigLoader.log(
|
246
|
+
"Missing Patient ID in eligibility result; using surrogate key {}".format(surrogate),
|
247
|
+
level="WARNING"
|
248
|
+
)
|
249
|
+
except Exception:
|
250
|
+
pass
|
251
|
+
|
252
|
+
return normalized
|
217
253
|
else:
|
218
254
|
MediLink_ConfigLoader.log("Unexpected eligibility result format: {}".format(type(eligibility_result)), level="WARNING")
|
219
255
|
return None
|
MediLink/MediLink_main.py
CHANGED
@@ -22,6 +22,7 @@ if PERFORMANCE_LOGGING:
|
|
22
22
|
|
23
23
|
# Now import core utilities after path setup
|
24
24
|
from MediCafe.core_utils import get_shared_config_loader, setup_module_paths, extract_medilink_config
|
25
|
+
from MediCafe.error_reporter import flush_queued_reports, collect_support_bundle, submit_support_bundle, capture_unhandled_traceback
|
25
26
|
setup_module_paths(__file__)
|
26
27
|
|
27
28
|
# Import modules after path setup
|
@@ -57,6 +58,8 @@ def _tools_menu(config, medi):
|
|
57
58
|
print("\nMaintenance Tools:")
|
58
59
|
options = [
|
59
60
|
"Rebuild submission index now",
|
61
|
+
"Submit Error Report (online)",
|
62
|
+
"Create Support Bundle (offline)",
|
60
63
|
"Back"
|
61
64
|
]
|
62
65
|
MediLink_UI.display_menu(options)
|
@@ -75,6 +78,27 @@ def _tools_menu(config, medi):
|
|
75
78
|
except Exception as e:
|
76
79
|
print("Index rebuild error: {}".format(e))
|
77
80
|
elif choice == '2':
|
81
|
+
try:
|
82
|
+
print("\nSubmitting Error Report (online)...")
|
83
|
+
zip_path = collect_support_bundle(include_traceback=True)
|
84
|
+
if not zip_path:
|
85
|
+
print("Failed to create support bundle.")
|
86
|
+
else:
|
87
|
+
ok = submit_support_bundle(zip_path)
|
88
|
+
if not ok:
|
89
|
+
print("Submission failed. Bundle saved at {} for later retry.".format(zip_path))
|
90
|
+
except Exception as e:
|
91
|
+
print("Error during report submission: {}".format(e))
|
92
|
+
elif choice == '3':
|
93
|
+
try:
|
94
|
+
zip_path = collect_support_bundle(include_traceback=True)
|
95
|
+
if zip_path:
|
96
|
+
print("Support bundle created: {}".format(zip_path))
|
97
|
+
else:
|
98
|
+
print("Failed to create support bundle.")
|
99
|
+
except Exception as e:
|
100
|
+
print("Error creating support bundle: {}".format(e))
|
101
|
+
elif choice == '4':
|
78
102
|
break
|
79
103
|
else:
|
80
104
|
MediLink_UI.display_invalid_choice()
|
@@ -167,6 +191,15 @@ def main_menu():
|
|
167
191
|
if PERFORMANCE_LOGGING:
|
168
192
|
print("Welcome display completed in {:.2f} seconds".format(welcome_end - welcome_start))
|
169
193
|
|
194
|
+
# Startup: flush any queued error reports (non-blocking style)
|
195
|
+
try:
|
196
|
+
print("\nChecking for queued error reports...")
|
197
|
+
uploaded, total = flush_queued_reports()
|
198
|
+
if total:
|
199
|
+
print("Queued reports: {} | Uploaded now: {}".format(total, uploaded))
|
200
|
+
except Exception:
|
201
|
+
pass
|
202
|
+
|
170
203
|
# Show message if new records were found during boot-time scan. TODO we need this to use the 'Last acknowledgements update:' timestamp to decide if it has already run in the last day so
|
171
204
|
# that we're not running it multiple times in rapid succession automatically. (user-initiated checks are fine like via selection of (1. Check for new remittances))
|
172
205
|
if ack_result:
|
@@ -428,6 +461,11 @@ if __name__ == "__main__":
|
|
428
461
|
total_start_time = time.time()
|
429
462
|
exit_code = 0
|
430
463
|
try:
|
464
|
+
# Install unhandled exception hook to capture tracebacks
|
465
|
+
try:
|
466
|
+
sys.excepthook = capture_unhandled_traceback
|
467
|
+
except Exception:
|
468
|
+
pass
|
431
469
|
main_menu()
|
432
470
|
except ValueError as e:
|
433
471
|
# Graceful domain error: show concise message without traceback, then exit
|
@@ -448,6 +486,25 @@ if __name__ == "__main__":
|
|
448
486
|
# Unexpected error: still avoid full traceback, present succinct notice
|
449
487
|
sys.stderr.write("An unexpected error occurred; process halted.\n")
|
450
488
|
sys.stderr.write(str(e) + "\n")
|
489
|
+
# Offer to create and submit an error report
|
490
|
+
try:
|
491
|
+
ans = input("Create and submit an error report now? (y/N): ").strip().lower()
|
492
|
+
except Exception:
|
493
|
+
ans = 'n'
|
494
|
+
if ans in ['y', 'yes']:
|
495
|
+
try:
|
496
|
+
from MediCafe.error_reporter import collect_support_bundle, submit_support_bundle
|
497
|
+
zip_path = collect_support_bundle(include_traceback=True)
|
498
|
+
if not zip_path:
|
499
|
+
print("Failed to create support bundle.")
|
500
|
+
else:
|
501
|
+
ok = submit_support_bundle(zip_path)
|
502
|
+
if ok:
|
503
|
+
print("Report submitted successfully.")
|
504
|
+
else:
|
505
|
+
print("Submission failed. Bundle saved at {} for later retry.".format(zip_path))
|
506
|
+
except Exception as _erre:
|
507
|
+
print("Error while creating/submitting report: {}".format(_erre))
|
451
508
|
sys.stderr.write("\nPress Enter to exit...\n")
|
452
509
|
try:
|
453
510
|
input()
|
MediLink/__init__.py
CHANGED
@@ -12,7 +12,7 @@ MediBot/MediBot_dataformat_library.py,sha256=D46fdPtxcgfWTzaLBtSvjtozzZBNqNiODgu
|
|
12
12
|
MediBot/MediBot_debug.bat,sha256=F5Lfi3nFEEo4Ddx9EbX94u3fNAMgzMp3wsn-ULyASTM,6017
|
13
13
|
MediBot/MediBot_docx_decoder.py,sha256=9BSjV-kB90VHnqfL_5iX4zl5u0HcHvHuL7YNfx3gXpQ,33143
|
14
14
|
MediBot/MediBot_smart_import.py,sha256=Emvz7NwemHGCHvG5kZcUyXMcCheidbGKaPfOTg-YCEs,6684
|
15
|
-
MediBot/__init__.py,sha256=
|
15
|
+
MediBot/__init__.py,sha256=TD2TjOOLwIklKHXMC7OU3WamrLSJqF8vdQFmdzOhuAg,3192
|
16
16
|
MediBot/clear_cache.bat,sha256=F6-VhETWw6xDdGWG2wUqvtXjCl3lY4sSUFqF90bM8-8,1860
|
17
17
|
MediBot/crash_diagnostic.bat,sha256=j8kUtyBg6NOWbXpeFuEqIRHOkVzgUrLOqO3FBMfNxTo,9268
|
18
18
|
MediBot/f_drive_diagnostic.bat,sha256=4572hZaiwZ5wVAarPcZJQxkOSTwAdDuT_X914noARak,6878
|
@@ -21,14 +21,15 @@ MediBot/get_medicafe_version.py,sha256=uyL_UIE42MyFuJ3SRYxJp8sZx8xjTqlYZ3FdQuxLd
|
|
21
21
|
MediBot/process_csvs.bat,sha256=3tI7h1z9eRj8rUUL4wJ7dy-Qrak20lRmpAPtGbUMbVQ,3489
|
22
22
|
MediBot/update_json.py,sha256=vvUF4mKCuaVly8MmoadDO59M231fCIInc0KI1EtDtPA,3704
|
23
23
|
MediBot/update_medicafe.py,sha256=G1lyvVOHYuho1d-TJQNN6qaB4HBWaJ2PpXqemBoPlRQ,17937
|
24
|
-
MediCafe/MediLink_ConfigLoader.py,sha256=
|
25
|
-
MediCafe/__init__.py,sha256=
|
24
|
+
MediCafe/MediLink_ConfigLoader.py,sha256=NoLb2YiJwlkrRYCt2PHvcFJ7yTIRWQCrsvkZIJWreM4,11141
|
25
|
+
MediCafe/__init__.py,sha256=B2m0aF3q1XVoCTmPK4wgbWtROmUsTwEiuyD7LH9VnOA,5721
|
26
26
|
MediCafe/__main__.py,sha256=mRNyk3D9Ilnu2XhgVI_rut7r5Ro7UIKtwV871giAHI8,12992
|
27
|
-
MediCafe/api_core.py,sha256=
|
27
|
+
MediCafe/api_core.py,sha256=tzCMB1fO7aLpfzlGxbU0qmhd9nD26YoIUohgDkXzNgA,84383
|
28
28
|
MediCafe/api_factory.py,sha256=I5AeJoyu6m7oCrjc2OvVvO_4KSBRutTsR1riiWhTZV0,12086
|
29
29
|
MediCafe/api_utils.py,sha256=KWQB0q1k5E6frOFFlKWcFpHNcqfrS7KJ_82672wbupw,14041
|
30
30
|
MediCafe/core_utils.py,sha256=XKUpyv7yKjIQ8iNrhD76PIURyt6GZxb98v0daiI7aaw,27303
|
31
31
|
MediCafe/deductible_utils.py,sha256=bsI5YRO8QzaEU-sxi2F5zIx6k4D53rYUt0mlg-6-Jc8,57644
|
32
|
+
MediCafe/error_reporter.py,sha256=t9AAkkVsmZMxPMSA6DW7wDf2cxXpFfA9oJW5-thg5VQ,8176
|
32
33
|
MediCafe/graphql_utils.py,sha256=xrREl0mqktEBkV6SZeAImuuDc8Sp2Q80rWxKIh-zD7Q,44499
|
33
34
|
MediCafe/logging_config.py,sha256=auT65LN5oDEXVhkMeLke63kJHTWxYf2o8YihAfQFgzU,5493
|
34
35
|
MediCafe/logging_demo.py,sha256=TwUhzafna5pMdN3zSKGrpUWRqX96F1JGGsSUtr3dygs,1975
|
@@ -38,7 +39,7 @@ MediCafe/submission_index.py,sha256=35gz8Anx1dIqG1I14GvuLY0nTO4dSBr2YsZwof9aIQg,
|
|
38
39
|
MediLink/InsuranceTypeService.py,sha256=FKWC1nRfKV_OtCDUtZustauXNhmCYDFiY9jsAGHPPUM,2178
|
39
40
|
MediLink/MediLink_837p_cob_library.py,sha256=glc7SJBDx0taCGmwmCs81GFJJcvA_D7nycIkTfmIuwE,30650
|
40
41
|
MediLink/MediLink_837p_encoder.py,sha256=lJnly96LsSBnzEgF8Ne-nQTL7cmRhoFL2fJajtpvOcU,32209
|
41
|
-
MediLink/MediLink_837p_encoder_library.py,sha256=
|
42
|
+
MediLink/MediLink_837p_encoder_library.py,sha256=zQDoIjyezmPlv0uR_IUoLqdsVdc6Dy5n-yv51yeT44g,92093
|
42
43
|
MediLink/MediLink_837p_utilities.py,sha256=AJ0F22LoF8du20zPBH4TZXgsdXCD-1qYKBnHJM-mXl0,16260
|
43
44
|
MediLink/MediLink_API_Generator.py,sha256=VZBL9W8yFTMJ4ikSwbUI8ANtaJCLnUyqoF8xQEJQn_E,11176
|
44
45
|
MediLink/MediLink_Azure.py,sha256=Ow70jctiHFIylskBExN7WUoRgrKOvBR6jNTnQMk6lJA,210
|
@@ -46,9 +47,9 @@ MediLink/MediLink_Charges.py,sha256=82fnqHGvT7tfdfjucnFHiLdUE0WhHDXrcS0k_Ln3c8U,
|
|
46
47
|
MediLink/MediLink_ClaimStatus.py,sha256=75LzWfYaxrLWelId-8rHHN_lchHXxAe34pRgvKPdP2o,22118
|
47
48
|
MediLink/MediLink_DataMgmt.py,sha256=9hc5jyWU65nYT66afDybOyYAcW-DvEYuHpWTun96U50,52407
|
48
49
|
MediLink/MediLink_Decoder.py,sha256=1gzdybNg4Vv69s5PNbX8bPNrXT_N_kPpFpt2HpkauWA,16430
|
49
|
-
MediLink/MediLink_Deductible.py,sha256=
|
50
|
+
MediLink/MediLink_Deductible.py,sha256=8EaJpJICcWcWL_Oge646bXE9STJhvbfIEmHl-5y-DMo,57937
|
50
51
|
MediLink/MediLink_Deductible_Validator.py,sha256=1h5GJ9jbcVarxd6a-lKPEOhJYz4QkeeBlHw0Zdd9vUU,24855
|
51
|
-
MediLink/MediLink_Display_Utils.py,sha256=
|
52
|
+
MediLink/MediLink_Display_Utils.py,sha256=pZqd3KRck27zzwnGh_qN1NN1Q-2FF6NFBtRPSO-syiI,22899
|
52
53
|
MediLink/MediLink_Down.py,sha256=s4_z-RaqHYanjwbQCl-OSkg4XIpcIQ2Q6jXa8-q_QXw,28111
|
53
54
|
MediLink/MediLink_Gmail.py,sha256=muqZI3girXDu92KT5Nft7dLHtpnQAjH-QfvdcGo28_Y,26801
|
54
55
|
MediLink/MediLink_Mailer.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
@@ -59,18 +60,18 @@ MediLink/MediLink_Scheduler.py,sha256=UJvxhDvHraqra2_TlQVlGeh5jRFrrfK6nCVUHnKOEM
|
|
59
60
|
MediLink/MediLink_UI.py,sha256=ZEJ14EGh7pDu1XjAdORDFiay4UtTsLNWwNSJ0prHFWg,10381
|
60
61
|
MediLink/MediLink_Up.py,sha256=uB6J63hWOn8Ot8iGtc2_OgcejNWVgnX7Se_e_UWBNho,38082
|
61
62
|
MediLink/MediLink_insurance_utils.py,sha256=g741Fj2K26cMy0JX5d_XavMw9LgkK6hjaUJYfysT7t8,9301
|
62
|
-
MediLink/MediLink_main.py,sha256=
|
63
|
+
MediLink/MediLink_main.py,sha256=CAXu0IRzhra3ppIFDcCppFNAZp7kCuN6gPtJSdFqGzs,24857
|
63
64
|
MediLink/MediLink_smart_import.py,sha256=B5SfBn_4bYEWJJDolXbjnwKx_-MaqGZ76LyXQwWDV80,9838
|
64
65
|
MediLink/Soumit_api.py,sha256=5JfOecK98ZC6NpZklZW2AkOzkjvrbYxpJpZNH3rFxDw,497
|
65
|
-
MediLink/__init__.py,sha256=
|
66
|
+
MediLink/__init__.py,sha256=rSHkkkTfid24CUGEFtuMAh8ebWQ41_Tew1vYYlb9hfo,3888
|
66
67
|
MediLink/gmail_http_utils.py,sha256=gtqCCrzJC7e8JFQzMNrf7EbK8na2h4sfTu-NMaZ_UHc,4006
|
67
68
|
MediLink/gmail_oauth_utils.py,sha256=Ugr-DEqs4_RddRMSCJ_dbgA3TVeaxpbAor-dktcTIgY,3713
|
68
69
|
MediLink/openssl.cnf,sha256=76VdcGCykf0Typyiv8Wd1mMVKixrQ5RraG6HnfKFqTo,887
|
69
70
|
MediLink/test.py,sha256=DM_E8gEbhbVfTAm3wTMiNnK2GCD1e5eH6gwTk89QIc4,3116
|
70
71
|
MediLink/webapp.html,sha256=MI9zZ4y1_h5Ji3nz2fmm6Q29AsPunks-wR-R8Ct73-w,19856
|
71
|
-
medicafe-0.
|
72
|
-
medicafe-0.
|
73
|
-
medicafe-0.
|
74
|
-
medicafe-0.
|
75
|
-
medicafe-0.
|
76
|
-
medicafe-0.
|
72
|
+
medicafe-0.250930.0.dist-info/LICENSE,sha256=65lb-vVujdQK7uMH3RRJSMwUW-WMrMEsc5sOaUn2xUk,1096
|
73
|
+
medicafe-0.250930.0.dist-info/METADATA,sha256=FAUuG1PCF_01NP77xNySzjfAvSMLtppmiLmlqANYTdw,3414
|
74
|
+
medicafe-0.250930.0.dist-info/WHEEL,sha256=oiQVh_5PnQM0E3gPdiz09WCNmwiHDMaGer_elqB3coM,92
|
75
|
+
medicafe-0.250930.0.dist-info/entry_points.txt,sha256=m3RBUBjr-xRwEkKJ5W4a7NlqHZP_1rllGtjZnrRqKe8,52
|
76
|
+
medicafe-0.250930.0.dist-info/top_level.txt,sha256=U6-WBJ9RCEjyIs0BlzbQq_PwedCp_IV9n1616NNV5zA,26
|
77
|
+
medicafe-0.250930.0.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|