148 lines
6.5 KiB
PHP
148 lines
6.5 KiB
PHP
<?php
|
|
|
|
class Tracking_USPS {
|
|
|
|
/**
|
|
* Sometimes the API returns a city but no state or ZIP. This is a lookup table of city => state
|
|
* so the API can return a more complete response.
|
|
*/
|
|
public const STATELESS_CITIES = [
|
|
"LOS ANGELES" => "CA",
|
|
"SAN FRANCISCO" => "CA",
|
|
"NEW YORK" => "NY",
|
|
"CHICAGO" => "IL",
|
|
"MIAMI" => "FL"
|
|
];
|
|
|
|
/**
|
|
*
|
|
* @param string $code
|
|
* @return \TrackingInfo
|
|
* @throws TrackingException
|
|
*/
|
|
public static function track(string $code, string $carrier = ""): TrackingInfo {
|
|
$barcode = new TrackingBarcode($code);
|
|
|
|
try {
|
|
|
|
$resp = USPSAPIs::getAPIRequest("tracking/v3/tracking/$code?expand=DETAIL");
|
|
$resp = str_replace("<SUP>reg;</SUP>", "®", $resp);
|
|
$resp = str_replace("<SUP>®</SUP>", "®", $resp);
|
|
$resp = str_replace("<SUP>™</SUP>", "™", $resp);
|
|
$json = json_decode($resp, true);
|
|
|
|
if (!empty($json["error"])) {
|
|
if (!empty($json["error"]["errors"]) && $json["error"]["errors"][0]["code"] == "150001") {
|
|
// Tracking number not found
|
|
throw new TrackingException(str_replace("12: ", "", $json["error"]["errors"][0]["title"]));
|
|
}
|
|
if (!empty($json["error"]["message"])) {
|
|
throw new TrackingException("The USPS tracking system is having problems: \"" . trim($json["error"]["message"]) . "\"");
|
|
}
|
|
throw new TrackingException("The USPS tracking system is having problems. Try again later.");
|
|
}
|
|
|
|
$trackinfo = $json;
|
|
} catch (TrackingException $ex) {
|
|
throw $ex;
|
|
} catch (Exception $ex) {
|
|
throw new TrackingException("There was a server error. This code cannot be tracked right now. Try again later.");
|
|
}
|
|
|
|
$info = new TrackingInfo();
|
|
|
|
try {
|
|
$info->setCode($trackinfo["trackingNumber"]);
|
|
} catch (Exception $ex) {
|
|
throw new TrackingException("The USPS tracking system returned an invalid response. Try again later.");
|
|
}
|
|
|
|
$info->setCarrier("usps");
|
|
$info->setService(new Service((string) $trackinfo["mailClass"], (string) $trackinfo["mailClass"]));
|
|
$info->setCarrierAttributionText(CarrierAssets::getAttribution(Carriers::getCarrierCode($info->getCarrier())));
|
|
$info->setCarrierLogo(CarrierAssets::getLogo(Carriers::getCarrierCode($info->getCarrier())));
|
|
|
|
// Current status
|
|
if (count($trackinfo["trackingEvents"]) > 0) {
|
|
$index = 0;
|
|
$evt = $trackinfo["trackingEvents"][$index];
|
|
$current_status = new TrackingEntry(
|
|
TrackingStatus::USPSEventCodeToStatus($evt["eventCode"]),
|
|
($evt["eventType"] ?? "Unknown") . (TrackingStatus::USPSEventCodeToStatus($evt["eventCode"]) == TrackingStatus::TRACKING_STATUS_UNKNOWN ? " " . $evt["eventCode"] : ""),
|
|
date("Y-m-d\TH:i:s", strtotime($evt["eventTimestamp"])),
|
|
null,
|
|
TrackingStatus::isUSPSEventCodeContainerScan($evt["eventCode"])
|
|
);
|
|
|
|
$current_location = new Location();
|
|
$current_location->city = (string) $evt["eventCity"] ?? "";
|
|
$current_location->state = (string) $evt["eventState"] ?? "";
|
|
$current_location->zip = (string) $evt["eventZIP"] ?? "";
|
|
$current_location->country = (string) $evt["eventCountry"] ?? "";
|
|
|
|
/*
|
|
* Fill in state from list above when it's missing from the API response
|
|
*/
|
|
if ($current_location->state == "" && $current_location->zip == "") {
|
|
if (array_key_exists(strtoupper($current_location->city), self::STATELESS_CITIES)) {
|
|
$current_location->state = self::STATELESS_CITIES[$current_location->city];
|
|
}
|
|
}
|
|
} else {
|
|
$current_status = new TrackingEntry(
|
|
TrackingStatus::TRACKING_STATUS_PRE_TRANSIT,
|
|
($trackinfo["statusSummary"] ?? "Unknown"),
|
|
date("Y-m-d\TH:i:s", strtotime("now")),
|
|
null,
|
|
false
|
|
);
|
|
$current_location = new Location();
|
|
}
|
|
|
|
$current_status->setLocation($current_location);
|
|
|
|
$info->setCurrentStatus($current_status);
|
|
|
|
$from = new Location();
|
|
$from->city = (string) $trackinfo["originCity"] ?? "";
|
|
$from->state = (string) $trackinfo["originState"] ?? "";
|
|
$from->zip = (string) $trackinfo["originZIP"] ?? "";
|
|
$from->country = (string) (isset($trackinfo["originCountry"]) ? $trackinfo["originCountry"] : "");
|
|
|
|
$info->setFrom($from);
|
|
|
|
$to = new Location();
|
|
$to->city = (string) $trackinfo["destinationCity"] ?? "";
|
|
$to->state = (string) $trackinfo["destinationState"] ?? "";
|
|
$to->zip = (string) $trackinfo["destinationZIP"] ?? "";
|
|
$to->country = (string) (isset($trackinfo["destinationCountry"]) ? $trackinfo["destinationCountry"] : "");
|
|
|
|
$info->setTo($to);
|
|
|
|
for ($i = 0; $i < count($trackinfo["trackingEvents"]); $i++) {
|
|
$history = $trackinfo["trackingEvents"][$i];
|
|
$location = new Location();
|
|
$location->city = (string) $history["eventCity"] ?? "";
|
|
$location->state = (string) $history["eventState"] ?? "";
|
|
$location->zip = (string) $history["eventZIP"] ?? "";
|
|
$location->country = (string) $history["eventCountry"] ?? "";
|
|
/*
|
|
* Fill in state from list above when it's missing from the API response
|
|
*/
|
|
if ($location->state == "" && $location->zip == "") {
|
|
if (array_key_exists(strtoupper($location->city), self::STATELESS_CITIES)) {
|
|
$location->state = self::STATELESS_CITIES[$location->city];
|
|
}
|
|
}
|
|
$info->appendHistoryEntry(new TrackingEntry(
|
|
TrackingStatus::USPSEventCodeToStatus((string) $history["eventCode"]),
|
|
$history["eventType"] . (TrackingStatus::USPSEventCodeToStatus((string) $history["eventCode"]) == TrackingStatus::TRACKING_STATUS_UNKNOWN ? " " . (string) $history["eventCode"] : ""),
|
|
$history["eventTimestamp"],
|
|
$location,
|
|
TrackingStatus::isUSPSEventCodeContainerScan((string) $history["eventCode"])));
|
|
}
|
|
|
|
return $info;
|
|
}
|
|
}
|