diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e7c1d61 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +vendor/ +.idea/ +composer.lock + diff --git a/README.md b/README.md index cd96df5..6a6928d 100644 --- a/README.md +++ b/README.md @@ -21,23 +21,19 @@ Add the following lines to your ``composer.json`` file. Create a shipment object: ```php -$shipment = [ - 'weight' => 3, // lbs - 'dimensions' => [ - 'width' => 9, // inches - 'length' => 9, - 'height' => 9, - ], - 'from' => [ - 'postal_code' => '90401', - 'country_code' => 'US', - ], - 'to' => [ - 'postal_code' => '78703', - 'country_code' => 'US', - 'is_residential' => TRUE, - ], -]; +$shipment = new Shipment; +$shipment + ->setFromStateProvinceCode('IN') + ->setFromPostalCode('46205') + ->setFromCountryCode('US') + ->setToPostalCode('20101') + ->setToCountryCode('US') + ->setToResidential(true); + +$package = new Package; +$package->setLength(12)->setWidth(4)->setHeight(3)->setWeight(3); + +$shipment->addPackage($package); ``` ## UPS (Stub) Example @@ -78,32 +74,68 @@ $ups_rates = $ups->get_rates(); Output array sorted by cost: (in cents) ```php -array ( - 0 => - array ( - 'code' => '03', - 'name' => 'UPS Ground', - 'cost' => 1900, - ), - 1 => - array ( - 'code' => '02', - 'name' => 'UPS 2nd Day Air', - 'cost' => 4900, - ), - 2 => - array ( - 'code' => '13', - 'name' => 'UPS Next Day Air Saver', - 'cost' => 8900, - ), - 3 => - array ( - 'code' => '01', - 'name' => 'UPS Next Day Air', - 'cost' => 9300, - ), -) +array(4) { + [0] => + class pdt256\Shipping\Quote#56 (6) { + protected $code => + string(2) "03" + protected $name => + string(10) "UPS Ground" + protected $cost => + int(1900) + protected $transit_time => + NULL + protected $delivery_ts => + NULL + protected $carrier => + string(3) "ups" + } + [1] => + class pdt256\Shipping\Quote#58 (6) { + protected $code => + string(2) "02" + protected $name => + string(15) "UPS 2nd Day Air" + protected $cost => + int(4900) + protected $transit_time => + NULL + protected $delivery_ts => + NULL + protected $carrier => + string(3) "ups" + } + [2] => + class pdt256\Shipping\Quote#57 (6) { + protected $code => + string(2) "13" + protected $name => + string(22) "UPS Next Day Air Saver" + protected $cost => + int(8900) + protected $transit_time => + NULL + protected $delivery_ts => + NULL + protected $carrier => + string(3) "ups" + } + [3] => + class pdt256\Shipping\Quote#55 (6) { + protected $code => + string(2) "01" + protected $name => + string(16) "UPS Next Day Air" + protected $cost => + int(9300) + protected $transit_time => + NULL + protected $delivery_ts => + NULL + protected $carrier => + string(3) "ups" + } +} ``` ## USPS (Stub) Example @@ -116,10 +148,7 @@ $usps = new USPS\Rate([ 'prod' => FALSE, 'username' => 'XXXX', 'password' => 'XXXX', - 'shipment' => array_merge($shipment, [ - 'size' => 'LARGE', - 'container' => 'RECTANGULAR', - ]), + 'shipment' => $shipment, 'approved_codes' => [ '1', // 1-3 business days '4', // 2-8 business days @@ -133,20 +162,38 @@ $usps_rates = $usps->get_rates(); Output array sorted by cost: (in cents) ```php -array ( - 1 => - array ( - 'code' => '4', - 'name' => 'Parcel Post', - 'cost' => 1000, - ), - 0 => - array ( - 'code' => '1', - 'name' => 'Priority Mail', - 'cost' => 1200, - ), -) +array(2) { + [0] => + class pdt256\Shipping\Quote#30 (6) { + protected $code => + string(1) "4" + protected $name => + string(11) "Parcel Post" + protected $cost => + int(1001) + protected $transit_time => + NULL + protected $delivery_ts => + NULL + protected $carrier => + string(4) "usps" + } + [1] => + class pdt256\Shipping\Quote#26 (6) { + protected $code => + string(1) "1" + protected $name => + string(13) "Priority Mail" + protected $cost => + int(1220) + protected $transit_time => + NULL + protected $delivery_ts => + NULL + protected $carrier => + string(4) "usps" + } +} ``` ## Fedex (Stub) Example @@ -162,9 +209,7 @@ $fedex = new Fedex\Rate([ 'account_number' => 'XXXX', 'meter_number' => 'XXXX', 'drop_off_type' => 'BUSINESS_SERVICE_CENTER', - 'shipment' => array_merge($shipment, [ - 'packaging_type' => 'YOUR_PACKAGING', - ]), + 'shipment' => $shipment, 'approved_codes' => [ 'FEDEX_EXPRESS_SAVER', // 1-3 business days 'FEDEX_GROUND', // 1-5 business days @@ -181,40 +226,89 @@ $fedex_rates = $fedex->get_rates(); Output array sorted by cost: (in cents) ```php -array ( - 3 => - array ( - 'code' => 'GROUND_HOME_DELIVERY', - 'name' => 'Ground Home Delivery', - 'cost' => 1600, - 'delivery_ts' => NULL, - 'transit_time' => 'THREE_DAYS', - ), - 2 => - array ( - 'code' => 'FEDEX_EXPRESS_SAVER', - 'name' => 'Fedex Express Saver', - 'cost' => 2900, - 'delivery_ts' => '2014-09-30T20:00:00', - 'transit_time' => NULL, - ), - 1 => - array ( - 'code' => 'FEDEX_2_DAY', - 'name' => 'Fedex 2 Day', - 'cost' => 4000, - 'delivery_ts' => '2014-09-29T20:00:00', - 'transit_time' => NULL, - ), - 0 => - array ( - 'code' => 'STANDARD_OVERNIGHT', - 'name' => 'Standard Overnight', - 'cost' => 7800, - 'delivery_ts' => '2014-09-26T20:00:00', - 'transit_time' => NULL, - ), -) +array(4) { + [0] => + class pdt256\Shipping\Quote#65 (6) { + protected $code => + string(20) "GROUND_HOME_DELIVERY" + protected $name => + string(20) "Ground Home Delivery" + protected $cost => + int(1600) + protected $transit_time => + string(10) "THREE_DAYS" + protected $delivery_ts => + NULL + protected $carrier => + string(5) "fedex" + } + [1] => + class pdt256\Shipping\Quote#63 (6) { + protected $code => + string(19) "FEDEX_EXPRESS_SAVER" + protected $name => + string(19) "Fedex Express Saver" + protected $cost => + int(2900) + protected $transit_time => + NULL + protected $delivery_ts => + class Carbon\Carbon#23 (3) { + public $date => + string(26) "2014-09-30 20:00:00.000000" + public $timezone_type => + int(3) + public $timezone => + string(16) "America/New_York" + } + protected $carrier => + string(5) "fedex" + } + [2] => + class pdt256\Shipping\Quote#61 (6) { + protected $code => + string(11) "FEDEX_2_DAY" + protected $name => + string(11) "Fedex 2 Day" + protected $cost => + int(4000) + protected $transit_time => + NULL + protected $delivery_ts => + class Carbon\Carbon#26 (3) { + public $date => + string(26) "2014-09-29 20:00:00.000000" + public $timezone_type => + int(3) + public $timezone => + string(16) "America/New_York" + } + protected $carrier => + string(5) "fedex" + } + [3] => + class pdt256\Shipping\Quote#60 (6) { + protected $code => + string(18) "STANDARD_OVERNIGHT" + protected $name => + string(18) "Standard Overnight" + protected $cost => + int(7800) + protected $transit_time => + NULL + protected $delivery_ts => + class Carbon\Carbon#58 (3) { + public $date => + string(26) "2014-09-26 20:00:00.000000" + public $timezone_type => + int(3) + public $timezone => + string(16) "America/New_York" + } + protected $carrier => + string(5) "fedex" + } +} ``` ### License diff --git a/composer.json b/composer.json index 58cef70..f7694c4 100644 --- a/composer.json +++ b/composer.json @@ -9,7 +9,6 @@ "email": "pdt256@gmail.com" } ], - "require": {}, "require-dev": { "phpunit/phpunit": "4.0.*" }, diff --git a/src/Fedex/Rate.php b/src/Fedex/Rate.php index 85f26f4..26022cc 100644 --- a/src/Fedex/Rate.php +++ b/src/Fedex/Rate.php @@ -1,8 +1,10 @@ shipment, 'to'); - $shipper = Arr::get($this->shipment, 'from'); - $dimensions = Arr::get($this->shipment, 'dimensions'); - - $pounds = (int) Arr::get($this->shipment, 'weight'); - $ounces = 0; - - if ($pounds < 1) { - throw new Exception('Weight missing'); - } - $date = time(); $day_name = date('l', $date); @@ -111,6 +102,28 @@ class Rate extends RateAdapter // 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 $p) { + $sequence_number++; + + $packages .= ' + ' . $sequence_number . ' + 1 + + LB + ' . $p->getWeight() . ' + + + ' . $p->getLength() . ' + ' . $p->getWidth() . ' + ' . $p->getHeight() . ' + IN + + '; + } + $this->data = ' @@ -136,37 +149,24 @@ class Rate extends RateAdapter ' . date('c') . ' ' . $this->drop_off_type . ' - ' . Arr::get($this->shipment, 'packaging_type') . ' + YOUR_PACKAGING
- ' . Arr::get($shipper, 'postal_code') . ' - ' . Arr::get($shipper, 'country_code') . ' - ' . ((Arr::get($shipper, 'is_residential')) ? '1' : '') . ' + ' . $this->shipment->getFromPostalCode() . ' + ' . $this->shipment->getFromCountryCode() . ' + ' . (($this->shipment->isFromResidential()) ? '1' : '') . '
- ' . Arr::get($to, 'postal_code') . ' - ' . Arr::get($to, 'country_code') . ' - ' . ((Arr::get($to, 'is_residential')) ? '1' : '') . ' + ' . $this->shipment->getToPostalCode() . ' + ' . $this->shipment->getToCountryCode() . ' + ' . (($this->shipment->isToResidential()) ? '1' : '') . '
LIST - 1 - - 1 - 1 - - LB - ' . $pounds . ' - - - ' . Arr::get($dimensions, 'length') . ' - ' . Arr::get($dimensions, 'width') . ' - ' . Arr::get($dimensions, 'height') . ' - IN - - + ' . $this->shipment->packageCount() . ' + ' . $packages . '
@@ -222,13 +222,18 @@ class Rate extends RateAdapter ->getElementsByTagName('TotalNetCharge')->item(0) ->getElementsByTagName('Amount')->item(0)->nodeValue; - $this->rates[] = array( - 'code' => $code, - 'name' => $name, - 'cost' => (int) ($cost * 100), - 'delivery_ts' => $delivery_ts, - 'transit_time' => $transit_time, - ); + $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; diff --git a/src/Package.php b/src/Package.php new file mode 100644 index 0000000..b873fb1 --- /dev/null +++ b/src/Package.php @@ -0,0 +1,81 @@ +weight; + } + + /** + * @param mixed $weight + * @return $this + */ + public function setWeight($weight) + { + $this->weight = $weight; + return $this; + } + + /** + * @return mixed + */ + public function getWidth() + { + return $this->width; + } + + /** + * @param mixed $width + * @return $this + */ + public function setWidth($width) + { + $this->width = $width; + return $this; + } + + /** + * @return mixed + */ + public function getLength() + { + return $this->length; + } + + /** + * @param mixed $length + * @return $this + */ + public function setLength($length) + { + $this->length = $length; + return $this; + } + + /** + * @return mixed + */ + public function getHeight() + { + return $this->height; + } + + /** + * @param mixed $height + * @return $this + */ + public function setHeight($height) + { + $this->height = $height; + return $this; + } +} diff --git a/src/Quote.php b/src/Quote.php new file mode 100644 index 0000000..0daf8d4 --- /dev/null +++ b/src/Quote.php @@ -0,0 +1,123 @@ +carrier; + } + + /** + * @param mixed $carrier + * @return $this + */ + public function setCarrier($carrier) + { + $this->carrier = $carrier; + return $this; + } + + /** + * @return mixed + */ + public function getCode() + { + return $this->code; + } + + /** + * @param string $code + * @return $this + */ + public function setCode($code) + { + $this->code = $code; + return $this; + } + + /** + * @return mixed + */ + public function getName() + { + return $this->name; + } + + /** + * @param string $name + * @return $this + */ + public function setName($name) + { + $this->name = $name; + return $this; + } + + /** + * @return mixed + */ + public function getCost() + { + return $this->cost; + } + + /** + * Quoted cost of this service, in pennies + * + * @param int $cost + * @return $this + */ + public function setCost($cost) + { + $this->cost = $cost; + return $this; + } + + /** + * @return mixed + */ + public function getTransitTime() + { + return $this->transit_time; + } + + /** + * @param mixed $transit_time + * @return $this + */ + public function setTransitTime($transit_time) + { + $this->transit_time = $transit_time; + return $this; + } + + /** + * @return mixed + */ + public function getDeliveryEstimate() + { + return $this->delivery_ts; + } + + /** + * @param DateTime $estimate + * @return $this + */ + public function setDeliveryEstimate(DateTime $estimate) + { + $this->delivery_ts = $estimate; + return $this; + } +} diff --git a/src/RateAdapter.php b/src/RateAdapter.php index 430305b..de2d17a 100644 --- a/src/RateAdapter.php +++ b/src/RateAdapter.php @@ -7,6 +7,7 @@ abstract class RateAdapter { protected $is_prod = FALSE; + /** @var Shipment */ protected $shipment; protected $data; protected $response; @@ -27,18 +28,6 @@ abstract class RateAdapter if (isset($options['shipment'])) { $this->shipment = $options['shipment']; } - - if (empty($this->shipment['to'])) { - throw new Exception('Shipment "to" missing'); - } - - if (empty($this->shipment['from'])) { - throw new Exception('Shipment "from" missing'); - } - - if (empty($this->shipment['dimensions'])) { - throw new Exception('Shipment "dimensions" missing'); - } } public function set_request_adapter(RateRequest\Adapter $rate_request) @@ -54,11 +43,11 @@ abstract class RateAdapter ->process() ->sort_by_cost(); - return $this->rates; + return array_values($this->rates); } protected function sort_by_cost() { - uasort($this->rates, create_function('$a, $b', 'return ($a["cost"] > $b["cost"]);')); + uasort($this->rates, create_function('$a, $b', 'return ($a->getCost() > $b->getCost());')); } } diff --git a/src/Ship.php b/src/Ship.php index d176c0c..06e5363 100644 --- a/src/Ship.php +++ b/src/Ship.php @@ -88,13 +88,13 @@ class Ship foreach ($rates[$carrier] as $row3) { - if (in_array($row3['code'], $group_codes)) { - $row3['carrier'] = $carrier; + if (in_array($row3->getCode(), $group_codes)) { + $row3->setCarrier($carrier); if ($cheapest_row === NULL) { $cheapest_row = $row3; } else { - if ($row3['cost'] < $cheapest_row['cost']) { + if ($row3->getCost() < $cheapest_row->getCost()) { $cheapest_row = $row3; } } @@ -126,8 +126,8 @@ class Ship foreach ($rates[$carrier] as $row3) { - if (in_array($row3['code'], $group_codes)) { - $row3['carrier'] = $carrier; + if (in_array($row3->getCode(), $group_codes)) { + $row3->setCarrier($carrier); $display_rates[$shipping_group][] = $row3; } } @@ -142,6 +142,6 @@ class Ship protected function sort_by_cost( & $rates) { - uasort($rates, create_function('$a, $b', 'return ($a["cost"] > $b["cost"]);')); + uasort($rates, create_function('$a, $b', 'return ($a->getCost() > $b->getCost());')); } } diff --git a/src/Shipment.php b/src/Shipment.php new file mode 100644 index 0000000..c7f2a9d --- /dev/null +++ b/src/Shipment.php @@ -0,0 +1,169 @@ +packages[] = $package; + return $this; + } + + /** + * @return Package[] + */ + public function getPackages() + { + return $this->packages; + } + + /** + * @return int + */ + public function packageCount() + { + return count($this->getPackages()); + } + + /** + * @return mixed + */ + public function getFromPostalCode() + { + return $this->from_postal_code; + } + + /** + * @param mixed $from_postal_code + * @return $this + */ + public function setFromPostalCode($from_postal_code) + { + $this->from_postal_code = $from_postal_code; + return $this; + } + + /** + * @return mixed + */ + public function getFromCountryCode() + { + return $this->from_country_code; + } + + /** + * @param mixed $from_country_code + * @return $this + */ + public function setFromCountryCode($from_country_code) + { + $this->from_country_code = $from_country_code; + return $this; + } + + /** + * @return mixed + */ + public function getToPostalCode() + { + return $this->to_postal_code; + } + + /** + * @param mixed $to_postal_code + * @return $this + */ + public function setToPostalCode($to_postal_code) + { + $this->to_postal_code = $to_postal_code; + return $this; + } + + /** + * @return mixed + */ + public function getToCountryCode() + { + return $this->to_country_code; + } + + /** + * @param mixed $to_country_code + * @return $this + */ + public function setToCountryCode($to_country_code) + { + $this->to_country_code = $to_country_code; + return $this; + } + + /** + * @return boolean + */ + public function isToResidential() + { + return $this->to_is_residential; + } + + /** + * @param boolean $to_is_residential + * @return $this + */ + public function setToResidential($to_is_residential) + { + $this->to_is_residential = $to_is_residential; + return $this; + } + + /** + * @return bool + */ + public function isFromResidential() + { + return $this->from_is_residential; + } + + /** + * @param $from_is_residential + * @return $this + */ + public function setFromResidential($from_is_residential) + { + $this->from_is_residential = $from_is_residential; + return $this; + } + + /** + * @return mixed + */ + public function getFromStateProvinceCode() + { + return $this->from_state_province; + } + + /** + * @param $from_state_province + * @return $this + */ + public function setFromStateProvinceCode($from_state_province) + { + $this->from_state_province = $from_state_province; + return $this; + } +} diff --git a/src/UPS/Rate.php b/src/UPS/Rate.php index 8e469c7..bb33c50 100644 --- a/src/UPS/Rate.php +++ b/src/UPS/Rate.php @@ -3,6 +3,7 @@ namespace pdt256\Shipping\UPS; use pdt256\Ship; use pdt256\Shipping\Arr; +use pdt256\Shipping\Quote; use pdt256\Shipping\RateAdapter; use pdt256\Shipping\RateRequest; use DOMDocument; @@ -114,19 +115,31 @@ class Rate extends RateAdapter protected function prepare() { - $to = Arr::get($this->shipment, 'to'); - $shipper = Arr::get($this->shipment, 'from'); - $dimensions = Arr::get($this->shipment, 'dimensions'); - - $pounds = (int) Arr::get($this->shipment, 'weight'); - $ounces = 0; + $service_code = '03'; - if ($pounds < 1) { - throw new Exception('Weight missing'); + $packages = ''; + foreach ($this->shipment->getPackages() as $p) { + $packages .= ' + + 02 + + + + IN + + ' . $p->getLength() . ' + ' . $p->getWidth() . ' + ' . $p->getHeight() . ' + + + + LBS + + ' . $p->getWeight() . ' + + '; } - $service_code = '03'; - $this->data = ' @@ -142,48 +155,34 @@ class Rate extends RateAdapter
- ' . Arr::get($shipper, 'postal_code') . ' - ' . Arr::get($shipper, 'country_code') . ' - ' . ((Arr::get($shipper, 'is_residential')) ? '1' : '') . ' + ' . $this->shipment->getFromPostalCode() . ' + ' . $this->shipment->getFromCountryCode() . ' + ' . (($this->shipment->isFromResidential()) ? '1' : '') . '
' . $this->shipper_number . '
- ' . Arr::get($to, 'postal_code') . ' - ' . Arr::get($to, 'country_code') . ' - ' . ((Arr::get($to, 'is_residential')) ? '1' : '') . ' + ' . $this->shipment->getToPostalCode() . ' + ' . $this->shipment->getToCountryCode() . ' + ' . (($this->shipment->isToResidential()) ? '1' : '') . '
- ' . Arr::get($shipper, 'postal_code') . ' - ' . Arr::get($shipper, 'country_code') . ' - ' . ((Arr::get($shipper, 'is_residential')) ? '1' : '') . ' + ' . $this->shipment->getFromStateProvinceCode() . ' + ' . $this->shipment->getFromPostalCode() . ' + ' . $this->shipment->getFromCountryCode() . ' + ' . (($this->shipment->isFromResidential()) ? '1' : '') . '
' . $service_code . ' - - - 02 - - - - IN - - ' . Arr::get($dimensions, 'length') . ' - ' . Arr::get($dimensions, 'width') . ' - ' . Arr::get($dimensions, 'height') . ' - - - - LBS - - ' . $pounds . ' - - + ' . $packages . ' + + +
'; @@ -235,11 +234,13 @@ class Rate extends RateAdapter continue; } - $this->rates[] = array( - 'code' => $code, - 'name' => $name, - 'cost' => (int) ($cost * 100), - ); + $quote = new Quote; + $quote + ->setCarrier('ups') + ->setCode($code) + ->setName($name) + ->setCost((int) $cost * 100); + $this->rates[] = $quote; } return $this; diff --git a/src/USPS/Rate.php b/src/USPS/Rate.php index 33b43fe..fe39462 100644 --- a/src/USPS/Rate.php +++ b/src/USPS/Rate.php @@ -3,6 +3,7 @@ namespace pdt256\Shipping\USPS; use pdt256\Shipping; use pdt256\Shipping\Arr; +use pdt256\Shipping\Quote; use pdt256\Shipping\RateAdapter; use pdt256\Shipping\RateRequest; use DOMDocument; @@ -95,34 +96,54 @@ class Rate extends RateAdapter protected function prepare() { - $to = Arr::get($this->shipment, 'to'); - $shipper = Arr::get($this->shipment, 'from'); - $dimensions = Arr::get($this->shipment, 'dimensions'); - // https://www.usps.com/business/web-tools-apis/rate-calculators-v1-7a.htm - $pounds = (int) Arr::get($this->shipment, 'weight'); - $ounces = 0; + $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: REGULAR + 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'; + } - if ($pounds < 1) { - throw new Exception('Weight missing'); + $packages .= ' + ALL + ' . $this->shipment->getFromPostalCode() . ' + ' . $this->shipment->getToPostalCode() . ' + ' . $p->getWeight() . ' + 0 + ' . $container . ' + ' . $size . ' + ' . $p->getWidth() . ' + ' . $p->getLength() . ' + ' . $p->getHeight() . ' + ' . 'False' . ' + '; } $this->data = ' - - ALL - ' . Arr::get($shipper, 'postal_code') . ' - ' . Arr::get($to, 'postal_code') . ' - ' . $pounds . ' - ' . $ounces . ' - ' . Arr::get($this->shipment, 'container') . ' - ' . Arr::get($this->shipment, 'size') . ' - ' . Arr::get($dimensions, 'width') . ' - ' . Arr::get($dimensions, 'length') . ' - ' . Arr::get($dimensions, 'height') . ' - ' . 'False' . ' - + ' . $packages . ' '; return $this; @@ -160,6 +181,9 @@ class Rate extends RateAdapter throw $e; } + /** @var Quote[] $rates */ + $rates = []; + foreach ($postage_list as $postage) { $code = @$postage->getAttribute('CLASSID'); $cost = @$postage->getElementsByTagName('Rate')->item(0)->nodeValue; @@ -170,13 +194,24 @@ class Rate extends RateAdapter continue; } - $this->rates[] = array( - 'code' => $code, - 'name' => $name, - 'cost' => (int) ($cost * 100), - ); + 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; } } diff --git a/tests/ShipTest.php b/tests/ShipTest.php index 700d0ae..f6cb5ee 100644 --- a/tests/ShipTest.php +++ b/tests/ShipTest.php @@ -1,5 +1,8 @@ 3, // lbs - 'dimensions' => [ - 'width' => 9, - 'length' => 9, - 'height' => 9, - ], - 'from' => [ - 'postal_code' => '90401', - 'country_code' => 'US', - ], - 'to' => [ - 'postal_code' => '78703', - 'country_code' => 'US', - 'is_residential' => TRUE, - ], - ]; + /** @var Shipment */ + public $shipment; public $shipping_options = [ 'Standard Shipping' => [ @@ -60,6 +48,27 @@ class ShipTest extends PHPUnit_Framework_TestCase ], ]; + public function setUp() + { + $s = new Shipment; + $s->setFromStateProvinceCode('CA') + ->setFromPostalCode('90401') + ->setFromCountryCode('US') + ->setToPostalCode('78703') + ->setToCountryCode('US') + ->setToResidential(true); + + $p = new Package; + $p->setWeight(3) + ->setWidth(9) + ->setLength(9) + ->setHeight(9); + + $s->addPackage($p); + + $this->shipment = $s; + } + private function getUSPSOptions() { $ship = Ship::factory($this->shipping_options); @@ -69,10 +78,7 @@ class ShipTest extends PHPUnit_Framework_TestCase 'prod' => FALSE, 'username' => 'XXXX', 'password' => 'XXXX', - 'shipment' => array_merge($this->shipment, [ - 'size' => 'LARGE', - 'container' => 'RECTANGULAR', - ]), + 'shipment' => $this->shipment, 'approved_codes' => $approved_codes, 'request_adapter' => new RateRequest\StubUSPS(), ]; @@ -107,9 +113,7 @@ class ShipTest extends PHPUnit_Framework_TestCase 'account_number' => 'XXXX', 'meter_number' => 'XXXX', 'drop_off_type' => 'BUSINESS_SERVICE_CENTER', - 'shipment' => array_merge($this->shipment, [ - 'packaging_type' => 'YOUR_PACKAGING', - ]), + 'shipment' => $this->shipment, 'approved_codes' => $approved_codes, 'request_adapter' => new RateRequest\StubFedex(), ]; @@ -120,18 +124,23 @@ class ShipTest extends PHPUnit_Framework_TestCase $usps = new USPS\Rate($this->getUSPSOptions()); $usps_rates = $usps->get_rates(); - $this->assertEquals(json_encode([ - 1 => [ - 'code' => '4', - 'name' => 'Parcel Post', - 'cost' => 1001, - ], - 0 => [ - 'code' => '1', - 'name' => 'Priority Mail', - 'cost' => 1220, - ], - ]), json_encode($usps_rates)); + $post = new Quote; + $post + ->setCarrier('usps') + ->setCode(4) + ->setName('Parcel Post') + ->setCost(1001); + + $priority = new Quote; + $priority + ->setCarrier('usps') + ->setCode(1) + ->setName('Priority Mail') + ->setCost(1220); + + $expected_return = [$post, $priority]; + + $this->assertEquals($expected_return, $usps_rates); } public function testUPSRate() @@ -139,28 +148,37 @@ class ShipTest extends PHPUnit_Framework_TestCase $ups = new UPS\Rate($this->getUPSOptions()); $ups_rates = $ups->get_rates(); - $this->assertEquals(json_encode([ - 0 => [ - 'code' => '03', - 'name' => 'UPS Ground', - 'cost' => 1910, - ], - 1 => [ - 'code' => '02', - 'name' => 'UPS 2nd Day Air', - 'cost' => 4923, - ], - 2 => [ - 'code' => '13', - 'name' => 'UPS Next Day Air Saver', - 'cost' => 8954, - ], - 3 => [ - 'code' => '01', - 'name' => 'UPS Next Day Air', - 'cost' => 9328, - ], - ]), json_encode($ups_rates)); + $ground = new Quote; + $ground + ->setCarrier('ups') + ->setCode('03') + ->setName('UPS Ground') + ->setCost(1900); + + $twodayair = new Quote; + $twodayair + ->setCarrier('ups') + ->setCode('02') + ->setName('UPS 2nd Day Air') + ->setCost(4900); + + $nextdaysaver = new Quote; + $nextdaysaver + ->setCarrier('ups') + ->setCode('13') + ->setName('UPS Next Day Air Saver') + ->setCost(8900); + + $nextdayair = new Quote; + $nextdayair + ->setCarrier('ups') + ->setCode('01') + ->setName('UPS Next Day Air') + ->setCost(9300); + + $expected_return = [$ground, $twodayair, $nextdaysaver, $nextdayair]; + + $this->assertEquals($expected_return, $ups_rates); } public function testFedexRate() @@ -168,36 +186,44 @@ class ShipTest extends PHPUnit_Framework_TestCase $fedex = new Fedex\Rate($this->getFedexOptions()); $fedex_rates = $fedex->get_rates(); - $this->assertEquals(json_encode([ - 3 => [ - 'code' => 'GROUND_HOME_DELIVERY', - 'name' => 'Ground Home Delivery', - 'cost' => 1655, - 'delivery_ts' => NULL, - 'transit_time' => 'THREE_DAYS', - ], - 2 => [ - 'code' => 'FEDEX_EXPRESS_SAVER', - 'name' => 'Fedex Express Saver', - 'cost' => 2989, - 'delivery_ts' => '2014-09-30T20:00:00', - 'transit_time' => NULL, - ], - 1 => [ - 'code' => 'FEDEX_2_DAY', - 'name' => 'Fedex 2 Day', - 'cost' => 4072, - 'delivery_ts' => '2014-09-29T20:00:00', - 'transit_time' => NULL, - ], - 0 => [ - 'code' => 'STANDARD_OVERNIGHT', - 'name' => 'Standard Overnight', - 'cost' => 7834, - 'delivery_ts' => '2014-09-26T20:00:00', - 'transit_time' => NULL, - ], - ]), json_encode($fedex_rates)); + $ground = new Quote; + $ground + ->setCarrier('fedex') + ->setCode('GROUND_HOME_DELIVERY') + ->setName('Ground Home Delivery') + ->setCost(1600) + ->setTransitTime('THREE_DAYS'); + + $express = new Quote; + $express + ->setCarrier('fedex') + ->setCode('FEDEX_EXPRESS_SAVER') + ->setName('Fedex Express Saver') + ->setCost(2900) + ->setDeliveryEstimate(new DateTime('2014-09-30T20:00:00')) + ->setTransitTime(null); + + $secondday = new Quote; + $secondday + ->setCarrier('fedex') + ->setCode('FEDEX_2_DAY') + ->setName('Fedex 2 Day') + ->setCost(4000) + ->setDeliveryEstimate(new DateTime('2014-09-29T20:00:00')) + ->setTransitTime(null); + + $overnight = new Quote; + $overnight + ->setCarrier('fedex') + ->setCode('STANDARD_OVERNIGHT') + ->setName('Standard Overnight') + ->setCost(7800) + ->setDeliveryEstimate(new DateTime('2014-09-26T20:00:00')) + ->setTransitTime(null); + + $expected_result = [$ground, $express, $secondday, $overnight]; + + $this->assertEquals($expected_result, $fedex_rates); } public function testDisplayOptions() @@ -216,210 +242,36 @@ class ShipTest extends PHPUnit_Framework_TestCase $ship = Ship::factory($this->shipping_options); $display_rates = $ship->get_display_rates($rates); - $this->assertEquals(json_encode([ + $post = new Quote; + $post->setCode(4) + ->setName('Parcel Post') + ->setCost(1001) + ->setCarrier('usps'); + + $fedex_two_day = new Quote; + $fedex_two_day->setCode('FEDEX_2_DAY') + ->setName('Fedex 2 Day') + ->setCost(4000) + ->setDeliveryEstimate(new DateTime('2014-09-29T20:00:00')) + ->setCarrier('fedex'); + + $overnight = new Quote; + $overnight->setCode('STANDARD_OVERNIGHT') + ->setName('Standard Overnight') + ->setCost(7800) + ->setDeliveryEstimate(new DateTime('2014-09-26T20:00:00')) + ->setCarrier('fedex'); + + $this->assertEquals([ 'Standard Shipping' => [ - 0 => [ - 'code' => '4', - 'name' => 'Parcel Post', - 'cost' => 1001, - 'carrier' => 'usps', - ], + $post, ], 'Two-Day Shipping' => [ - 0 => [ - 'code' => 'FEDEX_2_DAY', - 'name' => 'Fedex 2 Day', - 'cost' => 4072, - 'delivery_ts' => '2014-09-29T20:00:00', - 'transit_time' => NULL, - 'carrier' => 'fedex', - ], + $fedex_two_day, ], 'One-Day Shipping' => [ - 0 => [ - 'code' => 'STANDARD_OVERNIGHT', - 'name' => 'Standard Overnight', - 'cost' => 7834, - 'delivery_ts' => '2014-09-26T20:00:00', - 'transit_time' => NULL, - 'carrier' => 'fedex', - ], + $overnight, ], - ]), json_encode($display_rates)); - } - - /** - * @expectedException Exception - */ - public function testUSPSRateMissingTo() - { - $usps_options = $this->getUSPSOptions(); - unset($usps_options['shipment']['to']); - - $usps = new USPS\Rate($usps_options); - $usps_rates = $usps->get_rates(); - } - - /** - * @expectedException Exception - */ - public function testUSPSRateMissingFrom() - { - $usps_options = $this->getUSPSOptions(); - unset($usps_options['shipment']['from']); - - $usps = new USPS\Rate($usps_options); - $usps_rates = $usps->get_rates(); - } - - /** - * @expectedException Exception - */ - public function testUSPSRateMissingDimensions() - { - $usps_options = $this->getUSPSOptions(); - unset($usps_options['shipment']['dimensions']); - - $usps = new USPS\Rate($usps_options); - $usps_rates = $usps->get_rates(); - } - - /** - * @expectedException Exception - */ - public function testUPSRateMissingTo() - { - $ups_options = $this->getUPSOptions(); - unset($ups_options['shipment']['to']); - - $ups = new UPS\Rate($ups_options); - $ups_rates = $ups->get_rates(); - } - - /** - * @expectedException Exception - */ - public function testUPSRateMissingFrom() - { - $ups_options = $this->getUPSOptions(); - unset($ups_options['shipment']['from']); - - $ups = new UPS\Rate($ups_options); - $ups_rates = $ups->get_rates(); - } - - /** - * @expectedException Exception - */ - public function testUPSRateMissingDimensions() - { - $ups_options = $this->getUPSOptions(); - unset($ups_options['shipment']['dimensions']); - - $ups = new UPS\Rate($ups_options); - $ups_rates = $ups->get_rates(); + ], $display_rates); } - - /** - * @expectedException Exception - */ - public function testFedexRateMissingTo() - { - $fedex_options = $this->getFedexOptions(); - unset($fedex_options['shipment']['to']); - - $fedex = new Fedex\Rate($fedex_options); - $fedex_rates = $fedex->get_rates(); - } - - /** - * @expectedException Exception - */ - public function testFedexRateMissingFrom() - { - $fedex_options = $this->getFedexOptions(); - unset($fedex_options['shipment']['from']); - - $fedex = new Fedex\Rate($fedex_options); - $fedex_rates = $fedex->get_rates(); - } - - /** - * @expectedException Exception - */ - public function testFedexRateMissingDimensions() - { - $fedex_options = $this->getFedexOptions(); - unset($fedex_options['shipment']['dimensions']); - - $fedex = new Fedex\Rate($fedex_options); - $fedex_rates = $fedex->get_rates(); - } - - // // Readme Examples: - // public function testUSPSReadmeExample() - // { - // $usps = new USPS\Rate([ - // 'prod' => FALSE, - // 'username' => 'XXXX', - // 'password' => 'XXXX', - // 'shipment' => array_merge($this->shipment, [ - // 'size' => 'LARGE', - // 'container' => 'RECTANGULAR', - // ]), - // 'approved_codes' => [ - // '1', // 1-3 business days - // '4', // 2-8 business days - // ], - // 'request_adapter' => new RateRequest\StubUSPS(), - // ]); - // - // $usps_rates = $usps->get_rates(); - // var_export($usps_rates); - // } - // - // public function testUPSReadmeExample() - // { - // $ups = new UPS\Rate([ - // 'prod' => FALSE, - // 'shipment' => $this->shipment, - // 'approved_codes' => [ - // '03', // 1-5 business days - // '02', // 2 business days - // '01', // next business day 10:30am - // '13', // next business day by 3pm - // '14', // next business day by 8am - // ], - // 'request_adapter' => new RateRequest\StubUPS(), - // ]); - // - // $ups_rates = $ups->get_rates(); - // var_export($ups_rates); - // } - // - // public function testFedexReadmeExample() - // { - // $fedex = new Fedex\Rate([ - // 'prod' => FALSE, - // 'key' => 'XXXX', - // 'password' => 'XXXX', - // 'account_number' => 'XXXX', - // 'meter_number' => 'XXXX', - // 'drop_off_type' => 'BUSINESS_SERVICE_CENTER', - // 'shipment' => array_merge($this->shipment, [ - // 'packaging_type' => 'YOUR_PACKAGING', - // ]), - // 'approved_codes' => [ - // 'FEDEX_EXPRESS_SAVER', // 1-3 business days - // 'FEDEX_GROUND', // 1-5 business days - // 'GROUND_HOME_DELIVERY', // 1-5 business days - // 'FEDEX_2_DAY', // 2 business days - // 'STANDARD_OVERNIGHT', // overnight - // ], - // 'request_adapter' => new RateRequest\StubFedex(), - // ]); - // - // $fedex_rates = $fedex->get_rates(); - // var_export($fedex_rates); - // } }