From a89504e722e688f07d5ebefca27ab7db209a21fa Mon Sep 17 00:00:00 2001 From: Troy Davisson Date: Thu, 27 Nov 2014 01:44:07 -0500 Subject: [PATCH] Expanded to support multiple packages per request, and now more object oriented. USPS still provides the cost of each package back individually, so we sum those up per service requested --- .gitignore | 4 ++ src/Fedex/Rate.php | 64 ++++++++--------- src/Package.php | 123 +++++++++++++++++++++++++++++++ src/RateAdapter.php | 13 +--- src/Shipment.php | 169 +++++++++++++++++++++++++++++++++++++++++++ src/UPS/Rate.php | 71 +++++++++--------- src/USPS/Rate.php | 57 ++++++++------- tests/ShipTest.php | 172 ++++++++++---------------------------------- 8 files changed, 430 insertions(+), 243 deletions(-) create mode 100644 .gitignore create mode 100644 src/Package.php create mode 100644 src/Shipment.php 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/src/Fedex/Rate.php b/src/Fedex/Rate.php index 1275416..5f91875 100644 --- a/src/Fedex/Rate.php +++ b/src/Fedex/Rate.php @@ -88,17 +88,6 @@ 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; - - if ($pounds < 1) { - throw new Exception('Weight missing'); - } - $date = time(); $day_name = date('l', $date); @@ -111,6 +100,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 +147,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 . '
diff --git a/src/Package.php b/src/Package.php new file mode 100644 index 0000000..07414ce --- /dev/null +++ b/src/Package.php @@ -0,0 +1,123 @@ +size_classification; + } + + /** + * @param mixed $size_classification + * @return $this + */ + public function setSizeClassification($size_classification) + { + $this->size_classification = $size_classification; + return $this; + } + + /** + * @return mixed + */ + public function getPackaging() + { + return $this->packaging; + } + + /** + * @param mixed $packaging + * @return $this + */ + public function setPackaging($packaging) + { + $this->packaging = $packaging; + return $this; + } + + /** + * @return mixed + */ + public function getWeight() + { + return $this->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/RateAdapter.php b/src/RateAdapter.php index 430305b..8fd7dbb 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) 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 45b1962..53a4cbb 100644 --- a/src/UPS/Rate.php +++ b/src/UPS/Rate.php @@ -114,19 +114,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 +154,31 @@ 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 . ' diff --git a/src/USPS/Rate.php b/src/USPS/Rate.php index c54351d..48bcc95 100644 --- a/src/USPS/Rate.php +++ b/src/USPS/Rate.php @@ -95,34 +95,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'); - // https://www.usps.com/business/web-tools-apis/rate-calculators-v1-7a.htm - $pounds = (int) Arr::get($this->shipment, 'weight'); - $ounces = 0; - - if ($pounds < 1) { - throw new Exception('Weight missing'); + $packages = ''; + $sequence_number = 0; + foreach ($this->shipment->getPackages() as $p) { + $sequence_number++; + + $packages .= ' + ALL + ' . $this->shipment->getFromPostalCode() . ' + ' . $this->shipment->getToPostalCode() . ' + ' . $p->getWeight() . ' + 0 + ' . $p->getPackaging() . ' + ' . $p->getSizeClassification() . ' + ' . $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 +157,8 @@ class Rate extends RateAdapter throw $e; } + $rates = []; + foreach ($postage_list as $postage) { $code = @$postage->getAttribute('CLASSID'); $cost = @$postage->getElementsByTagName('Rate')->item(0)->nodeValue; @@ -170,13 +169,21 @@ class Rate extends RateAdapter continue; } - $this->rates[] = array( + if (array_key_exists($code, $rates)) { + $cost = $rates[$code]['cost'] + ($cost * 100); + } else { + $cost = $cost * 100; + } + + $rates[$code] = [ 'code' => $code, 'name' => $name, - 'cost' => (int) $cost * 100, - ); + 'cost' => (int) $cost, + ]; } + $this->rates = array_values($rates); + return $this; } } diff --git a/tests/ShipTest.php b/tests/ShipTest.php index 9467d7f..34c6e2c 100644 --- a/tests/ShipTest.php +++ b/tests/ShipTest.php @@ -1,5 +1,7 @@ 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 +47,29 @@ 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) + ->setPackaging(Package::USPS_CONTAINER_RECTANGULAR) + ->setSizeClassification(Package::USPS_SIZE_LARGE); + + $s->addPackage($p); + + $this->shipment = $s; + } + private function getUSPSOptions() { $ship = Ship::factory($this->shipping_options); @@ -69,10 +79,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(), ]; @@ -100,6 +107,11 @@ class ShipTest extends PHPUnit_Framework_TestCase $ship = Ship::factory($this->shipping_options); $approved_codes = $ship->get_approved_codes('fedex'); + $ps = $this->shipment->getPackages(); + foreach ($ps as $p) { + $p->setPackaging(Package::FEDEX_YOUR_PACKAGING); + } + return [ 'prod' => FALSE, 'key' => 'XXXX', @@ -107,9 +119,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(), ]; @@ -124,12 +134,12 @@ class ShipTest extends PHPUnit_Framework_TestCase 1 => [ 'code' => '4', 'name' => 'Parcel Post', - 'cost' => 1000, + 'cost' => 1001, ], 0 => [ 'code' => '1', 'name' => 'Priority Mail', - 'cost' => 1200, + 'cost' => 1220, ], ]), json_encode($usps_rates)); } @@ -221,7 +231,7 @@ class ShipTest extends PHPUnit_Framework_TestCase 0 => [ 'code' => '4', 'name' => 'Parcel Post', - 'cost' => 1000, + 'cost' => 1001, 'carrier' => 'usps', ], ], @@ -248,114 +258,6 @@ class ShipTest extends PHPUnit_Framework_TestCase ]), 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(); - } - - /** - * @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() // {