You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

188 lines
8.3 KiB
PHP

<?php
class Tracking_FedEx {
public static function getAuthToken() {
$headers = [
'Content-Type' => 'application/x-www-form-urlencoded'
];
$postdata = http_build_query([
"grant_type" => "client_credentials",
"client_id" => env("fedex_apikey", ""),
"client_secret" => env("fedex_secret", "")
]);
$ch = curl_init();
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 5);
curl_setopt($ch, CURLOPT_TIMEOUT, 45);
//curl_setopt($ch, CURLOPT_URL, "https://apis-sandbox.fedex.com/oauth/token"); // TEST
curl_setopt($ch, CURLOPT_URL, "https://apis.fedex.com/oauth/token"); // PROD
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $postdata);
$response = curl_exec($ch);
$data = json_decode($response, true);
if (isset($data["access_token"])) {
return [$data["access_token"], $data["expires_in"]];
}
throw new Exception("Couldn't get FedEx access token.");
}
/**
*
* @param string $code
* @return \TrackingInfo
* @throws TrackingException
*/
public static function track(string $code, string $carrier = ""): TrackingInfo {
global $memcache;
$barcode = new TrackingBarcode($code);
$fedexauthtoken = $memcache->get("logistics.tracking.fedex_auth_token");
if ($fedexauthtoken == false) {
$tokendata = Tracking_FedEx::getAuthToken();
$memcache->set("logistics.tracking.fedex_auth_token", $tokendata[0], $tokendata[1] - 120);
$fedexauthtoken = $tokendata[0];
}
try {
$trackrequest = [
"includeDetailedScans" => true,
"trackingInfo" => [
[
//"shipDateBegin" => date("Y-m-d", strtotime("now - 3 months")),
"trackingNumberInfo" => [
"trackingNumber" => $barcode->getCode()
]
]
]
];
$headers = [
"Authorization: Bearer $fedexauthtoken",
'X-locale: en_US',
'Content-Type: application/json'
];
$ch = curl_init();
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 5);
curl_setopt($ch, CURLOPT_TIMEOUT, 45);
//curl_setopt($ch, CURLOPT_URL, "https://apis-sandbox.fedex.com/track/v1/trackingnumbers"); // TEST
curl_setopt($ch, CURLOPT_URL, "https://apis.fedex.com/track/v1/trackingnumbers"); // PROD
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($trackrequest));
curl_setopt($ch, CURLOPT_ENCODING, "");
$response = curl_exec($ch);
// CHECK TO SEE IF WE GOT AN ERROR
if ((curl_errno($ch)) && (curl_errno($ch) != 0)) {
throw new TrackingException(curl_error($ch));
}
$result = json_decode($response, true);
if (isset($result["errors"]) || !empty($result["errors"])) {
if (count($result["errors"]) > 0) {
throw new TrackingException($result["errors"][0]["message"]);
}
throw new TrackingException("The FedEx tracking system responded with an error. Try again later.");
}
if (!empty($result["output"]["completeTrackResults"]) && !empty($result["output"]["completeTrackResults"][0]["trackResults"])) {
$trackinfo = $result["output"]["completeTrackResults"][0]["trackResults"][0];
} else {
throw new TrackingException("No tracking details found.");
}
if (!empty($result["output"]["completeTrackResults"][0]["trackResults"][0]["error"])) {
throw new TrackingException($result["output"]["completeTrackResults"][0]["trackResults"][0]["error"]["message"]);
}
} catch (TrackingException $ex) {
throw $ex;
} catch (Exception $ex) {
throw new TrackingException("There was a server problem. This code cannot be tracked right now.");
}
$info = new TrackingInfo();
$info->setCode($trackinfo["trackingNumberInfo"]["trackingNumber"]);
$info->setCarrier("fedex");
$info->setService(new Service($trackinfo["serviceDetail"]["type"], $trackinfo["serviceDetail"]["description"]));
// Set carrier info: Ground, Express, Freight, etc
$carrierid = "fedex";
switch ($trackinfo["trackingNumberInfo"]["carrierCode"]) {
case "FEDEX_GROUND":
case "FEDEX_EXPRESS":
case "FEDEX_FREIGHT":
default:
$carrierid = "fedex";
break;
}
$info->setCarrierAttributionText(CarrierAssets::getAttribution(Carriers::getCarrierCode($carrierid)));
$info->setCarrierLogo(CarrierAssets::getLogo(Carriers::getCarrierCode($carrierid)));
if (count($trackinfo["scanEvents"]) > 0) {
$current = $trackinfo["scanEvents"][0];
$current_status = new TrackingEntry(
TrackingStatus::FedExEventTypeToStatus($current["eventType"]),
($current["eventDescription"] ?? "Unknown")
. (TrackingStatus::FedExEventTypeToStatus($current["eventType"]) == TrackingStatus::TRACKING_STATUS_UNKNOWN ? " " . $current["eventType"] : ""),
date("c", strtotime($current["date"]))
);
$current_location = new Location();
// FedEx docs say it should be $current["scanLocation"]["locationContactAndAddress"]["address"]["...}] but it's not I guess
$current_location->city = $current["scanLocation"]["city"] ?? "";
$current_location->state = $current["scanLocation"]["stateOrProvinceCode"] ?? "";
$current_location->zip = $current["scanLocation"]["postalCode"] ?? "";
$current_location->country = $current["scanLocation"]["countryCode"] ?? "";
$current_status->setLocation($current_location);
$info->setCurrentStatus($current_status);
}
$to = new Location();
$to->city = $trackinfo["recipientInformation"]["address"]["city"] ?? "";
$to->state = $trackinfo["recipientInformation"]["address"]["stateOrProvinceCode"] ?? "";
$to->zip = $trackinfo["recipientInformation"]["address"]["postalCode"] ?? "";
$to->country = $trackinfo["recipientInformation"]["address"]["countryCode"] ?? "";
$info->setTo($to);
$from = new Location();
$from->city = $trackinfo["shipperInformation"]["address"]["city"] ?? "";
$from->state = $trackinfo["shipperInformation"]["address"]["stateOrProvinceCode"] ?? "";
$from->zip = $trackinfo["shipperInformation"]["address"]["postalCode"] ?? "";
$from->country = $trackinfo["shipperInformation"]["address"]["countryCode"] ?? "";
$info->setFrom($from);
foreach ($trackinfo["scanEvents"] as $history) {
$location = new Location();
$location->city = $history["scanLocation"]["city"] ?? "";
$location->state = $history["scanLocation"]["stateOrProvinceCode"] ?? "";
$location->zip = $history["scanLocation"]["postalCode"] ?? "";
$location->country = $history["scanLocation"]["countryCode"] ?? "";
if (!empty($history["date"])) {
$datetimestring = date("c", strtotime($history["date"]));
} else {
$datetimestring = "";
}
$info->appendHistoryEntry(new TrackingEntry(
TrackingStatus::FedExEventTypeToStatus($history["eventType"]),
($history["eventDescription"] ?? "Unknown")
. (TrackingStatus::FedExEventTypeToStatus($history["eventType"]) == TrackingStatus::TRACKING_STATUS_UNKNOWN ? " " . $history["eventType"] : ""),
$datetimestring,
$location));
}
return $info;
}
}