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.
ShippingRates/src/USPS/Rate.php

207 lines
7.2 KiB
PHP

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<?php
namespace pdt256\Shipping\USPS;
use pdt256\Shipping;
use pdt256\Shipping\Arr;
use pdt256\Shipping\Quote;
use pdt256\Shipping\RateAdapter;
use pdt256\Shipping\RateRequest;
use pdt256\Shipping\Validator;
use DOMDocument;
use Exception;
class Rate extends RateAdapter {
private $urlDev = 'http://production.shippingapis.com/ShippingAPI.dll';
private $urlProd = 'http://production.shippingapis.com/ShippingAPI.dll';
private $username;
private $password;
/**
* Codes of appropriate shipping types. Default value is specified in __construct.
*/
public $approvedCodes;
private $shipping_codes = [
'domestic' => [
'00' => 'First-Class Mail Parcel',
'01' => 'First-Class Mail Large Envelope',
'02' => 'First-Class Mail Letter',
'03' => 'First-Class Mail Postcards',
'1' => 'Priority Mail',
'2' => 'Express Mail Hold for Pickup',
'3' => 'Express Mail',
'4' => 'Parcel Post', // Standard Post
'5' => 'Bound Printed Matter',
'6' => 'Media Mail',
'7' => 'Library',
'12' => 'First-Class Postcard Stamped',
'13' => 'Express Mail Flat-Rate Envelope',
'16' => 'Priority Mail Flat-Rate Envelope',
'17' => 'Priority Mail Regular Flat-Rate Box',
'18' => 'Priority Mail Keys and IDs',
'19' => 'First-Class Keys and IDs',
'22' => 'Priority Mail Flat-Rate Large Box',
'23' => 'Express Mail Sunday/Holiday',
'25' => 'Express Mail Flat-Rate Envelope Sunday/Holiday',
'27' => 'Express Mail Flat-Rate Envelope Hold For Pickup',
'28' => 'Priority Mail Small Flat-Rate Box',
],
'international' => [
'1' => 'Express Mail International',
'2' => 'Priority Mail International',
'4' => 'Global Express Guaranteed (Document and Non-document)',
'5' => 'Global Express Guaranteed Document used',
'6' => 'Global Express Guaranteed Non-Document Rectangular shape',
'7' => 'Global Express Guaranteed Non-Document Non-Rectangular',
'8' => 'Priority Mail Flat Rate Envelope',
'9' => 'Priority Mail Flat Rate Box',
'10' => 'Express Mail International Flat Rate Envelope',
'11' => 'Priority Mail Flat Rate Large Box',
'12' => 'Global Express Guaranteed Envelope',
'13' => 'First Class Mail International Letters',
'14' => 'First Class Mail International Flats',
'15' => 'First Class Mail International Parcels',
'16' => 'Priority Mail Flat Rate Small Box',
'21' => 'Postcards',
],
];
public function __construct($options = []) {
parent::__construct($options);
$this->username = Arr::get($options, 'username');
$this->password = Arr::get($options, 'password');
$this->approvedCodes = Arr::get($options, 'approvedCodes', [
'1',
'4',
]);
$this->setRequestAdapter(Arr::get($options, 'requestAdapter', new RateRequest\Get()));
}
protected function validate() {
$this->validatePackages();
Validator::checkIfNull($this->username, 'username');
Validator::checkIfNull($this->password, 'password');
Validator::checkIfNull($this->shipment->getFromPostalCode(), 'fromPostalCode');
Validator::checkIfNull($this->shipment->getToPostalCode(), 'toPostalCode');
return $this;
}
protected function prepare() {
$packages = '';
$sequence_number = 0;
foreach ($this->shipment->getPackages() as $p) {
$sequence_number++;
/**
* RateV4Request / Package / Size
* required once
* Defined as follows:
*
* REGULAR: Package dimensions are 12 or less;
* LARGE: Any package dimension is larger than 12.
*
* For example: <Size>REGULAR</Size>
* string
* whiteSpace=collapse
* enumeration=LARGE
* enumeration=REGULAR
*/
if ($p->getWidth() > 12 or $p->getLength() > 12 or $p->getHeight() > 12) {
$size = 'LARGE';
$container = 'RECTANGULAR';
} else {
$size = 'REGULAR';
$container = 'VARIABLE';
}
$packages .= '<Package ID="' . $sequence_number . '">' .
'<Service>ALL</Service>' .
'<ZipOrigination>' . $this->shipment->getFromPostalCode() . '</ZipOrigination>' .
'<ZipDestination>' . $this->shipment->getToPostalCode() . '</ZipDestination>' .
'<Pounds>' . $p->getPounds() . '</Pounds>' .
'<Ounces>' . $p->getOunces() . '</Ounces>' .
'<Container>' . $container . '</Container>' .
'<Size>' . $size . '</Size>' .
'<Width>' . $p->getWidth() . '</Width>' .
'<Length>' . $p->getLength() . '</Length>' .
'<Height>' . $p->getHeight() . '</Height>' .
'<Machinable>' . 'False' . '</Machinable>' .
'</Package>';
}
$this->data = '<RateV4Request USERID="' . $this->username . '">' .
'<Revision/>' .
$packages .
'</RateV4Request>';
return $this;
}
protected function execute() {
if ($this->isProduction) {
$url = $this->urlProd;
} else {
$url = $this->urlDev;
}
$url_request = $url . '?API=RateV4&XML=' . rawurlencode($this->data);
$this->response = $this->rateRequest->execute($url_request);
return $this;
}
protected function process() {
try {
$dom = new DOMDocument('1.0', 'UTF-8');
$dom->loadXml($this->response);
$postage_list = @$dom->getElementsByTagName('Postage');
if (empty($postage_list)) {
throw new Exception('Unable to get USPS Rates.');
}
} catch (Exception $e) {
throw $e;
}
/** @var Quote[] $rates */
$rates = [];
foreach ($postage_list as $postage) {
$code = @$postage->getAttribute('CLASSID');
$cost = @$postage->getElementsByTagName('Rate')->item(0)->nodeValue;
$name = Arr::get($this->shipping_codes['domestic'], $code);
if (!empty($this->approvedCodes) && !in_array($code, $this->approvedCodes)) {
continue;
}
if (array_key_exists($code, $rates)) {
$cost = $rates[$code]->getCost() + ($cost * 100);
} else {
$cost = $cost * 100;
}
$quote = new Quote;
$quote
->setCarrier('usps')
->setCode($code)
->setName($name)
->setCost((int) $cost);
$rates[$quote->getCode()] = $quote;
}
$this->rates = array_values($rates);
return $this;
}
}