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.
230 lines
9.3 KiB
PHP
230 lines
9.3 KiB
PHP
<?php
|
|
namespace pdt256\Shipping\Fedex;
|
|
|
|
use DateTime;
|
|
use pdt256\Shipping;
|
|
use pdt256\Shipping\Arr;
|
|
use pdt256\Shipping\Quote;
|
|
use pdt256\Shipping\RateAdapter;
|
|
use pdt256\Shipping\RateRequest;
|
|
use DOMDocument;
|
|
use Exception;
|
|
|
|
class Rate extends RateAdapter
|
|
{
|
|
private $urlDev = 'https://gatewaybeta.fedex.com/web-services/';
|
|
private $urlProd = 'https://gateway.fedex.com/web-services/';
|
|
|
|
private $key = 'XXX';
|
|
private $password = 'XXX';
|
|
private $accountNumber = 'XXX';
|
|
private $meterNumber = 'XXX';
|
|
private $dropOffType = 'BUSINESS_SERVICE_CENTER';
|
|
|
|
public $approvedCodes = [
|
|
'PRIORITY_OVERNIGHT',
|
|
'FEDEX_2_DAY',
|
|
'FEDEX_EXPRESS_SAVER',
|
|
'FEDEX_GROUND',
|
|
'GROUND_HOME_DELIVERY',
|
|
];
|
|
|
|
private $shippingCodes = [
|
|
'EUROPE_FIRST_INTERNATIONAL_PRIORITY' => 'Europe First International Priority',
|
|
'FEDEX_1_DAY_FREIGHT' => 'Fedex 1 Day Freight',
|
|
'FEDEX_2_DAY' => 'Fedex 2 Day',
|
|
'FEDEX_2_DAY_AM' => 'Fedex 2 Day AM',
|
|
'FEDEX_2_DAY_FREIGHT' => 'Fedex 2 Day Freight',
|
|
'FEDEX_3_DAY_FREIGHT' => 'Fedex 3 Day Freight',
|
|
'FEDEX_EXPRESS_SAVER' => 'Fedex Express Saver',
|
|
'FEDEX_FIRST_FREIGHT' => 'Fedex First Freight',
|
|
'FEDEX_FREIGHT_ECONOMY' => 'Fedex Freight Economy',
|
|
'FEDEX_FREIGHT_PRIORITY' => 'Fedex Freight Priority',
|
|
'FEDEX_GROUND' => 'Fedex Ground',
|
|
'FIRST_OVERNIGHT' => 'First Overnight',
|
|
'GROUND_HOME_DELIVERY' => 'Ground Home Delivery',
|
|
'INTERNATIONAL_ECONOMY' => 'International Economy',
|
|
'INTERNATIONAL_ECONOMY_FREIGHT' => 'International Economy Freight',
|
|
'INTERNATIONAL_FIRST' => 'International First',
|
|
'INTERNATIONAL_PRIORITY' => 'International Priority',
|
|
'INTERNATIONAL_PRIORITY_FREIGHT' => 'International Priority Freight',
|
|
'PRIORITY_OVERNIGHT' => 'Priority Overnight',
|
|
'SMART_POST' => 'Smart Post',
|
|
'STANDARD_OVERNIGHT' => 'Standard Overnight',
|
|
];
|
|
|
|
public function __construct($options = [])
|
|
{
|
|
parent::__construct($options);
|
|
|
|
$this->key = Arr::get($options, 'key');
|
|
$this->password = Arr::get($options, 'password');
|
|
$this->accountNumber = Arr::get($options, 'accountNumber');
|
|
$this->meterNumber = Arr::get($options, 'meterNumber');
|
|
$this->approvedCodes = Arr::get($options, 'approvedCodes');
|
|
$this->dropOffType = Arr::get($options, 'dropOffType');
|
|
|
|
$this->setRequestAdapter(Arr::get($options, 'requestAdapter', new RateRequest\Post()));
|
|
}
|
|
|
|
protected function prepare()
|
|
{
|
|
$date = time();
|
|
$day_name = date('l', $date);
|
|
|
|
if ($day_name == 'Saturday') {
|
|
$date += 172800;
|
|
} elseif ($day_name == 'Sunday') {
|
|
$date += 86400;
|
|
}
|
|
|
|
// http://www.fedex.com/templates/components/apps/wpor/secure/downloads/pdf/Aug13/PropDevGuide.pdf
|
|
// http://www.fedex.com/us/developer/product/WebServices/MyWebHelp_August2010/Content/
|
|
// Proprietary_Developer_Guide/Rate_Services_conditionalized.htm
|
|
|
|
$packages = '';
|
|
$sequence_number = 0;
|
|
foreach ($this->shipment->getPackages() as $package) {
|
|
$sequence_number++;
|
|
|
|
$packages .=
|
|
'<RequestedPackageLineItems>' .
|
|
'<SequenceNumber>' . $sequence_number . '</SequenceNumber>' .
|
|
'<GroupPackageCount>1</GroupPackageCount>' .
|
|
'<Weight>' .
|
|
'<Units>LB</Units>' .
|
|
'<Value>' . $package->getWeight() . '</Value>' .
|
|
'</Weight>' .
|
|
'<Dimensions>' .
|
|
'<Length>' . $package->getLength() . '</Length>' .
|
|
'<Width>' . $package->getWidth() . '</Width>' .
|
|
'<Height>' . $package->getHeight() . '</Height>' .
|
|
'<Units>IN</Units>' .
|
|
'</Dimensions>' .
|
|
'</RequestedPackageLineItems>';
|
|
}
|
|
|
|
$this->data = '<?xml version="1.0"?>' .
|
|
'<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" ' .
|
|
'xmlns="http://fedex.com/ws/rate/v13">' .
|
|
'<SOAP-ENV:Body>' .
|
|
'<RateRequest>' .
|
|
'<WebAuthenticationDetail>' .
|
|
'<UserCredential>' .
|
|
'<Key>' . $this->key . '</Key>' .
|
|
'<Password>' . $this->password . '</Password>' .
|
|
'</UserCredential>' .
|
|
'</WebAuthenticationDetail>' .
|
|
'<ClientDetail>' .
|
|
'<AccountNumber>' . $this->accountNumber . '</AccountNumber>' .
|
|
'<MeterNumber>' . $this->meterNumber . '</MeterNumber>' .
|
|
'</ClientDetail>' .
|
|
'<Version>' .
|
|
'<ServiceId>crs</ServiceId>' .
|
|
'<Major>13</Major>' .
|
|
'<Intermediate>0</Intermediate>' .
|
|
'<Minor>0</Minor>' .
|
|
'</Version>' .
|
|
'<ReturnTransitAndCommit>true</ReturnTransitAndCommit>' .
|
|
'<RequestedShipment>' .
|
|
'<ShipTimestamp>' . date('c') . '</ShipTimestamp>' .
|
|
'<DropoffType>' . $this->dropOffType . '</DropoffType>' .
|
|
'<PackagingType>YOUR_PACKAGING</PackagingType>' .
|
|
'<Shipper>' .
|
|
'<Address>' .
|
|
'<PostalCode>' . $this->shipment->getFromPostalCode() . '</PostalCode>' .
|
|
'<CountryCode>' . $this->shipment->getFromCountryCode() . '</CountryCode>' .
|
|
(
|
|
$this->shipment->getFromIsResidential() ?
|
|
'<Residential>1</Residential>' :
|
|
''
|
|
) .
|
|
'</Address>' .
|
|
'</Shipper>' .
|
|
'<Recipient>' .
|
|
'<Address>' .
|
|
'<PostalCode>' . $this->shipment->getToPostalCode() . '</PostalCode>' .
|
|
'<CountryCode>' . $this->shipment->getToCountryCode() . '</CountryCode>' .
|
|
(
|
|
$this->shipment->getToIsResidential() ?
|
|
'<Residential>1</Residential>' :
|
|
''
|
|
) .
|
|
'</Address>' .
|
|
'</Recipient>' .
|
|
'<RateRequestTypes>LIST</RateRequestTypes>' .
|
|
'<PackageCount>' . $this->shipment->packageCount() . '</PackageCount>' .
|
|
$packages .
|
|
'</RequestedShipment>' .
|
|
'</RateRequest>' .
|
|
'</SOAP-ENV:Body>' .
|
|
'</SOAP-ENV:Envelope>';
|
|
|
|
return $this;
|
|
}
|
|
|
|
protected function execute()
|
|
{
|
|
if ($this->isProduction) {
|
|
$url = $this->urlProd;
|
|
} else {
|
|
$url = $this->urlDev;
|
|
}
|
|
|
|
$this->response = $this->rateRequest->execute($url, $this->data);
|
|
|
|
return $this;
|
|
}
|
|
|
|
protected function process()
|
|
{
|
|
try {
|
|
$dom = new DOMDocument('1.0', 'UTF-8');
|
|
$dom->loadXml($this->response);
|
|
$rate_reply = $dom->getElementsByTagName('RateReplyDetails');
|
|
|
|
if (empty($rate_reply->length)) {
|
|
throw new Exception('Unable to get FedEx Rates.');
|
|
}
|
|
} catch (Exception $e) {
|
|
// StatsD::increment('error.shipping.get_fedex_rate');
|
|
// Kohana::$log->add(Log::ERROR, $e)->write();
|
|
throw $e;
|
|
}
|
|
|
|
foreach ($rate_reply as $rate) {
|
|
$code = $rate->getElementsByTagName('ServiceType')->item(0)->nodeValue;
|
|
|
|
if (! empty($this->approvedCodes) && ! in_array($code, $this->approvedCodes)) {
|
|
continue;
|
|
}
|
|
|
|
$name = Arr::get($this->shippingCodes, $code);
|
|
|
|
$delivery_ts = @$rate->getElementsByTagName('DeliveryTimestamp')->item(0)->nodeValue;
|
|
$transit_time = @$rate->getElementsByTagName('TransitTime')->item(0)->nodeValue;
|
|
|
|
$cost = $rate
|
|
->getElementsByTagName('RatedShipmentDetails')->item(0)
|
|
->getElementsByTagName('ShipmentRateDetail')->item(0)
|
|
->getElementsByTagName('TotalNetCharge')->item(0)
|
|
->getElementsByTagName('Amount')->item(0)->nodeValue;
|
|
|
|
$quote = new Quote;
|
|
$quote
|
|
->setCarrier('fedex')
|
|
->setCode($code)
|
|
->setName($name)
|
|
->setCost((int) ($cost * 100))
|
|
->setTransitTime($transit_time);
|
|
if ($delivery_ts) {
|
|
$quote->setDeliveryEstimate(new DateTime($delivery_ts));
|
|
}
|
|
|
|
$this->rates[] = $quote;
|
|
}
|
|
|
|
return $this;
|
|
}
|
|
}
|