Spaces:
Sleeping
Sleeping
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 | |
def home(): | |
return "Tracking update service is running." | |
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 | |
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) | |