Add "native" FedEx tracking

master
Skylar Ittner 2 years ago
parent 02a9646964
commit ac5ac2da00

@ -50,6 +50,8 @@ $SETTINGS = [
"ups_access_key" => "",
"ups_user_account" => "",
"ups_password" => "",
"fedex_apikey" => "",
"fedex_secret" => "",
"shippo_key" => "",
"easypost_key" => "",
];

@ -29,6 +29,8 @@ class Tracking {
return Tracking_USPS::track($barcode->getSanitized());
case "ups":
return Tracking_UPS::track($barcode->getSanitized());
case "fedex":
return Tracking_FedEx::track($barcode->getSanitized());
default:
return Tracking_EasyPost::track($barcode->getSanitized());
//return Tracking_Shippo::track($barcode->getSanitized());

@ -255,4 +255,73 @@ class TrackingStatus {
}
}
public static function FedExEventTypeToStatus(string $eventcode) {
switch ($eventcode) {
case "OC":
case "OX":
case "PD":
case "RP":
case "RG":
case "SH":
return TrackingStatus::TRACKING_STATUS_PRE_TRANSIT;
case "AA":
case "AC":
case "AD":
case "AF":
case "AP":
case "AR":
case "AX":
case "CH":
case "DD":
case "DP":
case "DR":
case "DS":
case "EA":
case "ED":
case "EO":
case "EP":
case "FD":
case "HL":
case "IT":
case "IX":
case "LO":
case "OD":
case "OF":
case "PF":
case "PL":
case "PM":
case "PU":
case "PX":
case "SF":
case "TR":
case "CC":
case "CD":
case "CP":
case "EA":
case "CA":
case "CU":
case "BR":
case "TP":
case "IP":
case "DO": // dropped off
return TrackingStatus::TRACKING_STATUS_TRANSIT;
case "RC": // Recipient
case "DL": // Delivered
case "HP": // Ready for pickup
return TrackingStatus::TRACKING_STATUS_DELIVERED;
case "RS":
return TrackingStatus::TRACKING_STATUS_RETURNED;
case "CA":
case "DE":
case "DY":
case "LP":
case "RD":
case "SE":
return TrackingStatus::TRACKING_STATUS_FAILURE;
case "SP":
default:
return TrackingStatus::TRACKING_STATUS_UNKNOWN;
}
}
}

@ -0,0 +1,187 @@
<?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;
}
}
Loading…
Cancel
Save