ocm-tracking / app.py
Jacobmadwed's picture
Update app.py
78bfd56 verified
raw
history blame
10.8 kB
import requests
import logging
import json
import base64
import uuid
from datetime import datetime
from flask import Flask, jsonify, request
from threading import Thread
import time
from flask_cors import CORS
app = Flask(__name__)
CORS(app) # This will enable CORS for all routes
# Constants
UPDATE_INTERVAL = 60 * 10 # 10 minutes
UPS_CLIENT_ID = 'LKrZBgcSZ2v7vtAn3VAmEEBXqpkXD8zIEcZum97Eb8sSl7Fx'
UPS_CLIENT_SECRET = 'DBAV77mzTWgI5oqWwXlA12hi62hgyUkesoGsREZsmjd1WHMSugpDUuBGTjyUiteT'
FEDEX_API_KEY = 'l705da56bf34254c3495f351772a6ea2d3'
FEDEX_SECRET_KEY = 'ae27688af74341f094228fc67a36a8cc'
# Configure logging
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)
# Functions to get access tokens
def get_fedex_access_token():
url = "https://apis.fedex.com/oauth/token"
headers = {'Content-Type': "application/x-www-form-urlencoded"}
payload = {
'grant_type': 'client_credentials',
'client_id': FEDEX_API_KEY,
'client_secret': FEDEX_SECRET_KEY
}
try:
logger.info("Requesting FedEx token")
response = requests.post(url, data=payload, headers=headers)
response.raise_for_status()
token_data = response.json()
return token_data['access_token']
except requests.exceptions.RequestException as e:
logger.error(f"Error obtaining FedEx access token: {e}")
if hasattr(e, 'response'):
logger.error(f"Response status code: {e.response.status_code}")
logger.error(f"Response headers: {dict(e.response.headers)}")
logger.error(f"Response content: {e.response.text}")
raise
def get_ups_access_token():
token_url = "https://onlinetools.ups.com/security/v1/oauth/token"
headers = {
'Content-Type': 'application/x-www-form-urlencoded',
'Accept': 'application/json',
'User-Agent': 'OCMTrackingApp/1.0',
'transId': str(uuid.uuid4()),
'transactionSrc': 'OCMTrackingApp'
}
credentials = base64.b64encode(f"{UPS_CLIENT_ID}:{UPS_CLIENT_SECRET}".encode()).decode()
headers['Authorization'] = f'Basic {credentials}'
data = {'grant_type': 'client_credentials'}
try:
logger.info("Requesting UPS token")
response = requests.post(token_url, headers=headers, data=data)
response.raise_for_status()
token_data = response.json()
return token_data['access_token']
except requests.exceptions.RequestException as e:
logger.error(f"Error obtaining UPS access token: {e}")
if hasattr(e, 'response'):
logger.error(f"Response content: {e.response.text}")
raise
# Functions to fetch tracking info
def fetch_fedex_tracking_info(tracking_number):
access_token = get_fedex_access_token()
url = "https://apis.fedex.com/track/v1/trackingnumbers"
headers = {
'Content-Type': "application/json",
'X-locale': "en_US",
'Authorization': f"Bearer {access_token}"
}
payload = {
"trackingInfo": [
{"trackingNumberInfo": {"trackingNumber": tracking_number}}
],
"includeDetailedScans": True
}
try:
logger.info(f"Requesting FedEx tracking info for {tracking_number}")
response = requests.post(url, json=payload, headers=headers)
response.raise_for_status()
data = response.json()
track_results = data['output']['completeTrackResults'][0]['trackResults'][0]
latest_status = track_results['latestStatusDetail']
scan_events = track_results.get('scanEvents', [])
def format_date(date_str):
if not date_str or date_str == 'N/A':
return 'N/A'
try:
date = datetime.fromisoformat(date_str.replace('Z', '+00:00'))
return date.strftime('%m/%d/%Y %I:%M %p')
except ValueError:
logger.warning(f"Unable to parse date: {date_str}")
return 'N/A'
estimated_delivery = 'N/A'
if 'standardTransitTimeWindow' in track_results and 'window' in track_results['standardTransitTimeWindow'] and 'ends' in track_results['standardTransitTimeWindow']['window']:
estimated_delivery = format_date(track_results['standardTransitTimeWindow']['window']['ends'])
elif 'estimatedDeliveryTimeWindow' in track_results and 'window' in track_results['estimatedDeliveryTimeWindow'] and 'ends' in track_results['estimatedDeliveryTimeWindow']['window']:
estimated_delivery = format_date(track_results['estimatedDeliveryTimeWindow']['window']['ends'])
if 'scanLocation' in latest_status and 'city' in latest_status['scanLocation']:
location = f"{latest_status['scanLocation']['city']}, {latest_status['scanLocation'].get('stateOrProvinceCode', 'N/A')}"
else:
location = 'N/A'
latest_event_time = format_date(latest_status.get('scanDateTime'))
if latest_event_time == 'N/A' and scan_events:
latest_event_time = format_date(scan_events[0].get('date'))
delivery_time = 'N/A'
if latest_status.get('statusByLocale') == 'Delivered':
for date_time in track_results.get('dateAndTimes', []):
if date_time.get('type') == 'ACTUAL_DELIVERY':
delivery_time = format_date(date_time.get('dateTime'))
break
latest_checkpoint = latest_status.get('description', 'N/A')
if latest_status.get('code') == 'SE':
reason_description = latest_status.get('ancillaryDetails', [{}])[0].get('reasonDescription', '')
if reason_description:
latest_checkpoint += f" ({reason_description})"
last_update_date_time = delivery_time if delivery_time != 'N/A' else latest_event_time
return {
'status': latest_status.get('statusByLocale', 'N/A'),
'courier': 'FedEx',
'estimatedDelivery': estimated_delivery,
'latestLocation': location,
'latestCheckpoint': latest_checkpoint,
'lastUpdateDateTime': last_update_date_time,
}
except requests.exceptions.RequestException as e:
logger.error(f"Error fetching FedEx tracking info: {e}")
if hasattr(e, 'response'):
logger.error(f"Response status code: {e.response.status_code}")
logger.error(f"Response headers: {dict(e.response.headers)}")
logger.error(f"Response content: {e.response.text}")
raise
except (KeyError, IndexError) as e:
logger.error(f"Error parsing FedEx tracking info: {e}")
logger.error(f"Response content: {data}")
raise
def fetch_ups_tracking_info(tracking_number):
access_token = get_ups_access_token()
url = f"https://onlinetools.ups.com/api/track/v1/details/{tracking_number}"
headers = {
'Authorization': f'Bearer {access_token}',
'Content-Type': 'application/json',
'Accept': 'application/json',
'User-Agent': 'OCMTrackingApp/1.0',
'transId': str(uuid.uuid4()),
'transactionSrc': 'OCMTrackingApp'
}
params = {
"locale": "en_US",
"returnSignature": "false",
"returnMilestones": "false",
"returnPOD": "false"
}
try:
logger.info(f"Requesting UPS tracking info for {tracking_number}")
response = requests.get(url, headers=headers, params=params)
response.raise_for_status()
data = response.json()
shipment = data['trackResponse']['shipment'][0]
package = shipment['package'][0]
events = package.get('activity', [])
if events:
sorted_events = sorted(events, key=lambda x: x['date'] + x['time'], reverse=True)
latest_event = sorted_events[0]
else:
latest_event = None
def format_date(date_str, time_str):
if not date_str or not time_str or date_str == 'N/A' or time_str == 'N/A':
return 'N/A'
try:
date = datetime.strptime(date_str + time_str, '%Y%m%d%H%M%S')
return date.strftime('%m/%d/%Y %I:%M %p')
except ValueError:
logger.warning(f"Unable to parse date: {date_str} or time: {time_str}")
return 'N/A'
delivery_date = 'N/A'
delivery_time = 'N/A'
if 'deliveryDate' in package:
if isinstance(package['deliveryDate'], list) and package['deliveryDate']:
delivery_date = package['deliveryDate'][0].get('date', 'N/A')
elif isinstance(package['deliveryDate'], dict):
delivery_date = package['deliveryDate'].get('date', 'N/A')
if 'deliveryTime' in package:
delivery_time = package['deliveryTime'].get('endTime', 'N/A')
return {
'status': latest_event['status']['type'] if latest_event else 'N/A',
'courier': 'UPS',
'estimatedDelivery': format_date(delivery_date, delivery_time),
'latestLocation': latest_event['location']['address'].get('city', 'N/A') if latest_event else 'N/A',
'latestCheckpoint': latest_event['status']['description'] if latest_event else 'N/A',
'lastUpdateDateTime': format_date(latest_event['date'], latest_event['time']) if latest_event else 'N/A',
}
except requests.exceptions.RequestException as e:
logger.error(f"Error fetching UPS tracking info: {e}")
if hasattr(e, 'response'):
logger.error(f"Response content: {e.response.text}")
raise
@app.route('/')
def home():
return "Tracking update service is running."
@app.route('/ups', methods=['POST'])
def get_ups_tracking():
tracking_number = request.json.get('tracking_number')
if not tracking_number:
return jsonify({"status": "error", "message": "Tracking number is required"}), 400
try:
tracking_info = fetch_ups_tracking_info(tracking_number)
return jsonify(tracking_info), 200
except Exception as e:
logger.error(f"Error in get_ups_tracking: {e}")
return jsonify({"status": "error", "message": str(e)}), 500
@app.route('/fedex', methods=['POST'])
def get_fedex_tracking():
tracking_number = request.json.get('tracking_number')
if not tracking_number:
return jsonify({"status": "error", "message": "Tracking number is required"}), 400
try:
tracking_info = fetch_fedex_tracking_info(tracking_number)
return jsonify(tracking_info), 200
except Exception as e:
logger.error(f"Error in get_fedex_tracking: {e}")
return jsonify({"status": "error", "message": str(e)}), 500
if __name__ == '__main__':
app.run(host='0.0.0.0', port=7860)