medicafe 0.250813.2__py3-none-any.whl → 0.250814.3__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.bat +1 -1
- MediBot/MediBot.py +1 -1
- MediBot/MediBot_Preprocessor_lib.py +21 -5
- MediBot/MediBot_UI.py +13 -1
- MediBot/__init__.py +1 -1
- MediBot/update_medicafe.py +69 -7
- MediCafe/__init__.py +1 -1
- MediLink/__init__.py +1 -1
- {medicafe-0.250813.2.dist-info → medicafe-0.250814.3.dist-info}/METADATA +1 -1
- {medicafe-0.250813.2.dist-info → medicafe-0.250814.3.dist-info}/RECORD +14 -27
- MediBot/MediPost.py +0 -5
- MediBot/PDF_to_CSV_Cleaner.py +0 -211
- MediLink/MediLink.py +0 -623
- MediLink/MediLink_277_decoder.py +0 -92
- MediLink/MediLink_API_v2.py +0 -176
- MediLink/MediLink_API_v3.py +0 -910
- MediLink/MediLink_APIs.py +0 -138
- MediLink/MediLink_ConfigLoader.py +0 -87
- MediLink/MediLink_ERA_decoder.py +0 -192
- MediLink/MediLink_GraphQL.py +0 -445
- MediLink/MediLink_StatusCheck.py +0 -0
- MediLink/MediLink_api_utils.py +0 -305
- MediLink/MediLink_batch.bat +0 -7
- {medicafe-0.250813.2.dist-info → medicafe-0.250814.3.dist-info}/LICENSE +0 -0
- {medicafe-0.250813.2.dist-info → medicafe-0.250814.3.dist-info}/WHEEL +0 -0
- {medicafe-0.250813.2.dist-info → medicafe-0.250814.3.dist-info}/entry_points.txt +0 -0
- {medicafe-0.250813.2.dist-info → medicafe-0.250814.3.dist-info}/top_level.txt +0 -0
MediLink/MediLink_APIs.py
DELETED
@@ -1,138 +0,0 @@
|
|
1
|
-
# Unused archive backup. This has been superceded by API_v2
|
2
|
-
|
3
|
-
import time, requests
|
4
|
-
try:
|
5
|
-
from MediLink import MediLink_ConfigLoader
|
6
|
-
except ImportError:
|
7
|
-
import MediLink_ConfigLoader
|
8
|
-
|
9
|
-
# Fetches the payer name from API based on the payer ID.
|
10
|
-
def fetch_payer_name_from_api(payer_id, config, primary_endpoint='AVAILITY'):
|
11
|
-
"""
|
12
|
-
Fetches the payer name from the API using the provided payer ID.
|
13
|
-
|
14
|
-
Args:
|
15
|
-
payer_id (str): The ID of the payer.
|
16
|
-
config (dict): Configuration settings.
|
17
|
-
primary_endpoint (str): The primary endpoint for resolving payer information.
|
18
|
-
|
19
|
-
Raises:
|
20
|
-
ValueError: If all endpoints are exhausted without finding the payer.
|
21
|
-
|
22
|
-
Returns:
|
23
|
-
str: The fetched payer name.
|
24
|
-
"""
|
25
|
-
# Reload for safety
|
26
|
-
config, _ = MediLink_ConfigLoader.load_configuration()
|
27
|
-
|
28
|
-
# Step 1: Retrieve endpoint configurations
|
29
|
-
endpoints = config['MediLink_Config']['endpoints']
|
30
|
-
tried_endpoints = []
|
31
|
-
|
32
|
-
# Step 2: Check if the primary endpoint is specified and is valid
|
33
|
-
if primary_endpoint and primary_endpoint in endpoints:
|
34
|
-
endpoint_order = [primary_endpoint] + [endpoint for endpoint in endpoints if endpoint != primary_endpoint]
|
35
|
-
else:
|
36
|
-
endpoint_order = list(endpoints.keys())
|
37
|
-
|
38
|
-
# Step 3: Iterate through available endpoints in specified order
|
39
|
-
for endpoint_name in endpoint_order:
|
40
|
-
endpoint_config = endpoints[endpoint_name]
|
41
|
-
if not all(key in endpoint_config for key in ['token_url', 'client_id', 'client_secret']):
|
42
|
-
MediLink_ConfigLoader.log("Skipping {} due to missing API keys.".format(endpoint_name), config, level="WARNING")
|
43
|
-
continue
|
44
|
-
|
45
|
-
# Step 4: Get access token for the endpoint
|
46
|
-
token = get_access_token(endpoint_config)
|
47
|
-
api_url = endpoint_config.get("api_url", "")
|
48
|
-
headers = {'Authorization': 'Bearer {}'.format(token), 'Accept': 'application/json'}
|
49
|
-
params = {'payerId': payer_id}
|
50
|
-
|
51
|
-
try:
|
52
|
-
# Step 5: Make API call to fetch payer name
|
53
|
-
response = requests.get(api_url, headers=headers, params=params)
|
54
|
-
response.raise_for_status()
|
55
|
-
data = response.json()
|
56
|
-
if 'payers' in data and data['payers']:
|
57
|
-
payer = data['payers'][0]
|
58
|
-
payer_name = payer.get('displayName') or payer.get('name')
|
59
|
-
|
60
|
-
# Log successful match
|
61
|
-
MediLink_ConfigLoader.log("Successfully found payer at {} for ID {}: {}".format(endpoint_name, payer_id, payer_name), config, level="INFO")
|
62
|
-
|
63
|
-
return payer_name
|
64
|
-
else:
|
65
|
-
MediLink_ConfigLoader.log("No payer found at {} for ID: {}. Trying next available endpoint.".format(endpoint_name, payer_id), config, level="INFO")
|
66
|
-
except requests.RequestException as e:
|
67
|
-
# Step 6: Log API call failure
|
68
|
-
MediLink_ConfigLoader.log("API call failed at {} for Payer ID '{}': {}".format(endpoint_name, payer_id, str(e)), config, level="ERROR")
|
69
|
-
tried_endpoints.append(endpoint_name)
|
70
|
-
|
71
|
-
# Step 7: Log all endpoints exhaustion and raise error
|
72
|
-
error_message = "All endpoints exhausted for Payer ID {}. Endpoints tried: {}".format(payer_id, ', '.join(tried_endpoints))
|
73
|
-
MediLink_ConfigLoader.log(error_message, config, level="CRITICAL")
|
74
|
-
raise ValueError(error_message)
|
75
|
-
|
76
|
-
# Test Case for API fetch
|
77
|
-
#payer_id = "11347"
|
78
|
-
#config = load_configuration()
|
79
|
-
#payer_name = fetch_payer_name_from_api(payer_id, config, endpoint='AVAILITY')
|
80
|
-
#print(payer_id, payer_name)
|
81
|
-
|
82
|
-
# Initialize a global dictionary to store the access token and its expiry time
|
83
|
-
# TODO (Low API) This will need to get setup for each endpoint separately.
|
84
|
-
token_cache = {
|
85
|
-
'access_token': None,
|
86
|
-
'expires_at': 0 # Timestamp of when the token expires
|
87
|
-
}
|
88
|
-
|
89
|
-
def get_access_token(endpoint_config):
|
90
|
-
current_time = time.time()
|
91
|
-
|
92
|
-
# Check if the cached token is still valid
|
93
|
-
if token_cache['access_token'] and token_cache['expires_at'] > current_time:
|
94
|
-
return token_cache['access_token']
|
95
|
-
|
96
|
-
# Validate endpoint configuration
|
97
|
-
if not endpoint_config or not all(k in endpoint_config for k in ['client_id', 'client_secret', 'token_url']):
|
98
|
-
raise ValueError("Endpoint configuration is incomplete or missing necessary fields.")
|
99
|
-
|
100
|
-
# Extract credentials and URL from the config
|
101
|
-
CLIENT_ID = endpoint_config.get("client_id")
|
102
|
-
CLIENT_SECRET = endpoint_config.get("client_secret")
|
103
|
-
url = endpoint_config.get("token_url")
|
104
|
-
|
105
|
-
# Setup the data payload and headers for the HTTP request
|
106
|
-
data = {
|
107
|
-
'grant_type': 'client_credentials',
|
108
|
-
'client_id': CLIENT_ID,
|
109
|
-
'client_secret': CLIENT_SECRET,
|
110
|
-
'scope': 'hipaa'
|
111
|
-
}
|
112
|
-
headers = {
|
113
|
-
'Content-Type': 'application/x-www-form-urlencoded'
|
114
|
-
}
|
115
|
-
|
116
|
-
try:
|
117
|
-
# Perform the HTTP request to get the access token
|
118
|
-
response = requests.post(url, headers=headers, data=data)
|
119
|
-
response.raise_for_status() # This will raise an exception for HTTP error statuses
|
120
|
-
json_response = response.json()
|
121
|
-
access_token = json_response.get('access_token')
|
122
|
-
expires_in = json_response.get('expires_in', 3600) # Default to 3600 seconds if not provided
|
123
|
-
|
124
|
-
if not access_token:
|
125
|
-
raise ValueError("No access token returned by the server.")
|
126
|
-
|
127
|
-
# Store the access token and calculate the expiry time
|
128
|
-
token_cache['access_token'] = access_token
|
129
|
-
token_cache['expires_at'] = current_time + expires_in - 120 # Subtracting 120 seconds to provide buffer
|
130
|
-
|
131
|
-
return access_token
|
132
|
-
except requests.RequestException as e:
|
133
|
-
# Handle HTTP errors (e.g., network problems, invalid response)
|
134
|
-
error_msg = "Failed to retrieve access token: {0}. Response status: {1}".format(str(e), response.status_code if response else 'No response')
|
135
|
-
raise Exception(error_msg)
|
136
|
-
except ValueError as e:
|
137
|
-
# Handle specific errors like missing access token
|
138
|
-
raise Exception("Configuration or server response error: {0}".format(str(e)))
|
@@ -1,87 +0,0 @@
|
|
1
|
-
# MediLink_ConfigLoader.py
|
2
|
-
import os, json, logging, sys, platform, yaml
|
3
|
-
from datetime import datetime
|
4
|
-
from collections import OrderedDict
|
5
|
-
|
6
|
-
"""
|
7
|
-
This function should be generalizable to have a initialization script over all the Medi* functions
|
8
|
-
"""
|
9
|
-
def load_configuration(config_path=os.path.join(os.path.dirname(__file__), '..', 'json', 'config.json'), crosswalk_path=os.path.join(os.path.dirname(__file__), '..', 'json', 'crosswalk.json')):
|
10
|
-
"""
|
11
|
-
Loads endpoint configuration, credentials, and other settings from JSON or YAML files.
|
12
|
-
|
13
|
-
Returns: A tuple containing dictionaries with configuration settings for the main config and crosswalk.
|
14
|
-
"""
|
15
|
-
# TODO (Low Config Upgrade) The Medicare / Private differentiator flag probably needs to be pulled or passed to this.
|
16
|
-
# BUG Hardcode sucks. This should probably be some local env variable.
|
17
|
-
# Detect the operating system
|
18
|
-
if platform.system() == 'Windows' and platform.release() == 'XP':
|
19
|
-
# Use F: paths for Windows XP
|
20
|
-
config_path = "F:\\Medibot\\json\\config.json"
|
21
|
-
crosswalk_path = "F:\\Medibot\\json\\crosswalk.json"
|
22
|
-
else:
|
23
|
-
# Use G: paths for other versions of Windows
|
24
|
-
config_path = "G:\\My Drive\\Codes\\MediCafe\\json\\config.json"
|
25
|
-
crosswalk_path = "G:\\My Drive\\Codes\\MediCafe\\json\\crosswalk.json"
|
26
|
-
|
27
|
-
try:
|
28
|
-
with open(config_path, 'r') as config_file:
|
29
|
-
if config_path.endswith('.yaml') or config_path.endswith('.yml'):
|
30
|
-
config = yaml.safe_load(config_file)
|
31
|
-
elif config_path.endswith('.json'):
|
32
|
-
config = json.load(config_file, object_pairs_hook=OrderedDict)
|
33
|
-
else:
|
34
|
-
raise ValueError("Unsupported configuration format.")
|
35
|
-
|
36
|
-
if 'MediLink_Config' not in config:
|
37
|
-
raise KeyError("MediLink_Config key is missing from the loaded configuration.")
|
38
|
-
|
39
|
-
with open(crosswalk_path, 'r') as crosswalk_file:
|
40
|
-
crosswalk = json.load(crosswalk_file)
|
41
|
-
|
42
|
-
return config, crosswalk
|
43
|
-
except ValueError as e:
|
44
|
-
if isinstance(e, UnicodeDecodeError):
|
45
|
-
print("Error decoding file: {}".format(e))
|
46
|
-
else:
|
47
|
-
print("Error parsing file: {}".format(e))
|
48
|
-
sys.exit(1) # Exit the script due to a critical error in configuration loading
|
49
|
-
except FileNotFoundError:
|
50
|
-
print("One or both configuration files not found. Config: {}, Crosswalk: {}".format(config_path, crosswalk_path))
|
51
|
-
sys.exit(1) # Exit the script due to a critical error in configuration loading
|
52
|
-
except KeyError as e:
|
53
|
-
print("Critical configuration is missing: {}".format(e))
|
54
|
-
sys.exit(1) # Exit the script due to a critical error in configuration loading
|
55
|
-
except Exception as e:
|
56
|
-
print("An unexpected error occurred while loading the configuration: {}".format(e))
|
57
|
-
sys.exit(1) # Exit the script due to a critical error in configuration loading
|
58
|
-
|
59
|
-
# Logs messages with optional error type and claim data.
|
60
|
-
def log(message, config=None, level="INFO", error_type=None, claim=None, verbose=False):
|
61
|
-
|
62
|
-
# If config is not provided, load it
|
63
|
-
if config is None:
|
64
|
-
config, _ = load_configuration()
|
65
|
-
|
66
|
-
# Setup logger if not already configured
|
67
|
-
if not logging.root.handlers:
|
68
|
-
local_storage_path = config['MediLink_Config'].get('local_storage_path', '.') if isinstance(config, dict) else '.'
|
69
|
-
log_filename = datetime.now().strftime("Log_%m%d%Y.log")
|
70
|
-
log_filepath = os.path.join(local_storage_path, log_filename)
|
71
|
-
|
72
|
-
# Set logging level based on verbosity
|
73
|
-
logging_level = logging.DEBUG if verbose else logging.INFO
|
74
|
-
|
75
|
-
logging.basicConfig(level=logging_level,
|
76
|
-
format='%(asctime)s - %(levelname)s - %(message)s',
|
77
|
-
filename=log_filepath,
|
78
|
-
filemode='a')
|
79
|
-
|
80
|
-
# Prepare log message
|
81
|
-
claim_data = " - Claim Data: {}".format(claim) if claim else ""
|
82
|
-
error_info = " - Error Type: {}".format(error_type) if error_type else ""
|
83
|
-
full_message = "{} {}{}".format(message, claim_data, error_info)
|
84
|
-
|
85
|
-
# Log the message
|
86
|
-
logger = logging.getLogger()
|
87
|
-
getattr(logger, level.lower())(full_message)
|
MediLink/MediLink_ERA_decoder.py
DELETED
@@ -1,192 +0,0 @@
|
|
1
|
-
import os
|
2
|
-
import sys
|
3
|
-
import csv
|
4
|
-
from MediLink_ConfigLoader import load_configuration, log
|
5
|
-
from MediLink_DataMgmt import consolidate_csvs
|
6
|
-
|
7
|
-
|
8
|
-
"""
|
9
|
-
1. ERA File Processing: Implement robust mechanisms for reading and parsing ERA files, addressing potential file integrity issues and accommodating scenarios with multiple payer addresses within a single ERA.
|
10
|
-
2. Wildcard File Processing: Enable effective batch processing of ERA files using wildcard patterns in the `--era_file_path` argument, resulting in a unified CSV output.
|
11
|
-
3. Date of Service Parsing: Enhance the parsing logic for 'Date of Service' to accommodate different segment identifiers, improving data extraction reliability.
|
12
|
-
4. Payer Address Extraction: Fine-tune the logic for extracting payer and provider addresses from ERA files, ensuring only relevant information is captured.
|
13
|
-
5. De-persisting Intermediate Files.
|
14
|
-
"""
|
15
|
-
|
16
|
-
# ERA Parser
|
17
|
-
def parse_era_content(content):
|
18
|
-
extracted_data = []
|
19
|
-
normalized_content = content.replace('~\n', '~')
|
20
|
-
lines = normalized_content.split('~')
|
21
|
-
|
22
|
-
# Reset these values for each new CLP segment
|
23
|
-
record = {}
|
24
|
-
check_eft, payer_address = None, None
|
25
|
-
allowed_amount, write_off, patient_responsibility, adjustment_amount = 0, 0, 0, 0
|
26
|
-
is_payer_section = False # Flag to identify payer section for accurate address capture
|
27
|
-
|
28
|
-
for line in lines:
|
29
|
-
segments = line.split('*')
|
30
|
-
|
31
|
-
if segments[0] == 'TRN' and len(segments) > 2:
|
32
|
-
check_eft = segments[2]
|
33
|
-
|
34
|
-
# Determine the start and end of the payer section to correctly capture the payer's address
|
35
|
-
if segments[0] == 'N1':
|
36
|
-
if segments[1] == 'PR': # Payer information starts
|
37
|
-
is_payer_section = True
|
38
|
-
# payer_name = segments[2] # Can capture payer name here if needed
|
39
|
-
elif segments[1] == 'PE': # Provider information starts, ending payer section
|
40
|
-
is_payer_section = False
|
41
|
-
|
42
|
-
# Correctly capture payer address only within payer section
|
43
|
-
if is_payer_section and segments[0] == 'N3' and len(segments) > 1:
|
44
|
-
payer_address = segments[1]
|
45
|
-
|
46
|
-
if segments[0] == 'CLP' and len(segments) >= 5:
|
47
|
-
if record:
|
48
|
-
if adjustment_amount == 0 and (write_off > 0 or patient_responsibility > 0):
|
49
|
-
adjustment_amount = write_off + patient_responsibility
|
50
|
-
|
51
|
-
# Finalize and append the current record before starting a new one
|
52
|
-
record.update({
|
53
|
-
# 'Payer Name': payer_name,
|
54
|
-
'Payer Address': payer_address,
|
55
|
-
'Allowed Amount': allowed_amount,
|
56
|
-
'Write Off': write_off,
|
57
|
-
'Patient Responsibility': patient_responsibility,
|
58
|
-
'Adjustment Amount': adjustment_amount,
|
59
|
-
})
|
60
|
-
extracted_data.append(record)
|
61
|
-
|
62
|
-
# Reset variables for the next record
|
63
|
-
allowed_amount, write_off, patient_responsibility, adjustment_amount = 0, 0, 0, 0
|
64
|
-
# payer_address = None # Reset address for the next CLP segment if it changes within one ERA file (so no. disable.)
|
65
|
-
|
66
|
-
# Initialize a new record
|
67
|
-
record = {
|
68
|
-
'Check EFT': check_eft,
|
69
|
-
'Chart Number': segments[1],
|
70
|
-
'Payer Address': payer_address,
|
71
|
-
'Amount Paid': segments[4],
|
72
|
-
'Charge': segments[3], # Total submitted charges for the claim
|
73
|
-
}
|
74
|
-
|
75
|
-
elif segments[0] == 'CAS':
|
76
|
-
# Parsing CAS segments for Write Off and Patient Responsibility
|
77
|
-
if segments[1] == 'CO': # Write Off
|
78
|
-
write_off += float(segments[3])
|
79
|
-
elif segments[1] == 'PR': # Patient Responsibility
|
80
|
-
patient_responsibility += float(segments[3])
|
81
|
-
elif segments[1] == 'OA': # Capture Adjustment Amount from CAS*OA segment
|
82
|
-
adjustment_amount += float(segments[3])
|
83
|
-
|
84
|
-
elif segments[0] == 'AMT' and segments[1] == 'B6':
|
85
|
-
# Allowed Amount from AMT segment
|
86
|
-
allowed_amount += float(segments[2])
|
87
|
-
|
88
|
-
elif segments[0] == 'DTM' and (segments[1] == '232' or segments[1] == '472'):
|
89
|
-
record['Date of Service'] = segments[2]
|
90
|
-
|
91
|
-
|
92
|
-
if record:
|
93
|
-
# Final record handling
|
94
|
-
if adjustment_amount == 0 and (write_off > 0 or patient_responsibility > 0):
|
95
|
-
adjustment_amount = write_off + patient_responsibility
|
96
|
-
# Append the last record
|
97
|
-
record.update({
|
98
|
-
'Allowed Amount': allowed_amount,
|
99
|
-
'Write Off': write_off,
|
100
|
-
'Patient Responsibility': patient_responsibility,
|
101
|
-
'Adjustment Amount': adjustment_amount,
|
102
|
-
})
|
103
|
-
extracted_data.append(record)
|
104
|
-
|
105
|
-
return extracted_data
|
106
|
-
|
107
|
-
def translate_era_to_csv(files, output_directory):
|
108
|
-
if not os.path.exists(output_directory):
|
109
|
-
os.makedirs(output_directory)
|
110
|
-
|
111
|
-
for file_path in files:
|
112
|
-
# Ensure the file is read correctly
|
113
|
-
with open(file_path, 'r') as era_file:
|
114
|
-
era_content = era_file.read()
|
115
|
-
|
116
|
-
data = parse_era_content(era_content)
|
117
|
-
# print("Parsed Data: ", data) # DEBUG
|
118
|
-
|
119
|
-
csv_file_path = os.path.join(output_directory, os.path.basename(file_path) + '.csv')
|
120
|
-
|
121
|
-
try:
|
122
|
-
# Open the CSV file with explicit newline handling
|
123
|
-
with open(csv_file_path, 'w', newline='') as csv_file:
|
124
|
-
fieldnames = ['Date of Service',
|
125
|
-
'Check EFT',
|
126
|
-
'Chart Number',
|
127
|
-
'Payer Address',
|
128
|
-
'Amount Paid',
|
129
|
-
'Adjustment Amount',
|
130
|
-
'Allowed Amount',
|
131
|
-
'Write Off',
|
132
|
-
'Patient Responsibility',
|
133
|
-
'Charge'
|
134
|
-
]
|
135
|
-
writer = csv.DictWriter(csv_file, fieldnames=fieldnames)
|
136
|
-
|
137
|
-
writer.writeheader()
|
138
|
-
for record in data:
|
139
|
-
|
140
|
-
# print("Writing record: ", record)
|
141
|
-
|
142
|
-
writer.writerow({
|
143
|
-
'Date of Service': record.get('Date of Service', ''),
|
144
|
-
'Check EFT': record.get('Check EFT', ''),
|
145
|
-
'Chart Number': record.get('Chart Number', ''),
|
146
|
-
'Payer Address': record.get('Payer Address', ''),
|
147
|
-
'Amount Paid': record.get('Amount Paid', ''),
|
148
|
-
'Adjustment Amount': record.get('Adjustment Amount', ''),
|
149
|
-
'Allowed Amount': record.get('Allowed Amount', ''),
|
150
|
-
'Write Off': record.get('Write Off', ''),
|
151
|
-
'Patient Responsibility': record.get('Patient Responsibility', ''),
|
152
|
-
'Charge': record.get('Charge', ''),
|
153
|
-
})
|
154
|
-
# Explicitly flush data to ensure it's written
|
155
|
-
csv_file.flush()
|
156
|
-
except Exception as e:
|
157
|
-
print("Error writing CSV: ", e)
|
158
|
-
|
159
|
-
# User Interface
|
160
|
-
def user_confirm_overwrite(chart_numbers):
|
161
|
-
"""Asks the user for confirmation to overwrite an existing file, showing Chart Numbers."""
|
162
|
-
print("The following Chart Numbers are in the existing file:")
|
163
|
-
for number in chart_numbers:
|
164
|
-
print(number)
|
165
|
-
return input("The file already exists. Do you want to overwrite it? (y/n): ").strip().lower() == 'y'
|
166
|
-
|
167
|
-
if __name__ == "__main__":
|
168
|
-
# Load configuration
|
169
|
-
|
170
|
-
config, _ = load_configuration()
|
171
|
-
|
172
|
-
# Setup logger
|
173
|
-
local_storage_path = config['MediLink_Config']['local_storage_path']
|
174
|
-
|
175
|
-
# Define output directory
|
176
|
-
output_directory = os.path.join(local_storage_path, "translated_csvs")
|
177
|
-
|
178
|
-
# Retrieve ERA files from command line arguments
|
179
|
-
files = sys.argv[1:] # Exclude the script name
|
180
|
-
if not files:
|
181
|
-
log("No ERA files provided as arguments.")
|
182
|
-
sys.exit(1)
|
183
|
-
|
184
|
-
# Translate ERA files to CSV format
|
185
|
-
translate_era_to_csv(files, output_directory)
|
186
|
-
|
187
|
-
# Consolidate CSVs
|
188
|
-
consolidate_csv_path = consolidate_csvs(output_directory)
|
189
|
-
if consolidate_csv_path:
|
190
|
-
print("Consolidated CSV File Created: {}".format(consolidate_csv_path))
|
191
|
-
else:
|
192
|
-
print("No CSV file was created.")
|