Compare commits

..

No commits in common. "master" and "v0.2-beta" have entirely different histories.

40 changed files with 1352 additions and 6412 deletions

8
.gitignore vendored
View File

@ -1,8 +0,0 @@
vendor
composer.lock
coverage_report
.idea/*
!.idea/runConfigurations/
.DS_Store
live_phpunit.sh
/nbproject/private/

View File

@ -1,6 +0,0 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="All Unit Tests" type="PHPUnitRunConfigurationType" factoryName="PHPUnit">
<TestRunner class="pdt256\Shipping\PackageDimensionsValidationTrait" configuration_file="$PROJECT_DIR$/phpunit.xml" directory="$PROJECT_DIR$" file="$PROJECT_DIR$/tests/PackageDimensionsValidationTrait.php" scope="XML" use_alternative_configuration_file="true" />
<method v="2" />
</configuration>
</component>

View File

@ -1,13 +0,0 @@
language: php
php:
- 7.1
- 7.2
- 7.3
- 7.4
before_script:
- composer install --prefer-dist
script:
- vendor/bin/phpcs --standard=PSR2 src/ tests/
- vendor/bin/phpunit

View File

@ -1,7 +1,6 @@
The MIT License (MIT)
Copyright (c) 2014 Jamie Isaacs <pdt256@gmail.com>
Copyright (c) 2020 Netsyms Technologies <opensource@netsyms.com>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

316
README.md
View File

@ -1,55 +1,54 @@
## PHP Shipping API
![Test Coverage](http://img.shields.io/badge/coverage-86%25-green.svg)
[![Build Status](https://travis-ci.org/pdt256/shipping.svg?branch=master)](https://travis-ci.org/pdt256/shipping)
[![Downloads](https://img.shields.io/packagist/dt/pdt256/shipping.svg)](https://packagist.org/packages/pdt256/shipping)
[![License](https://img.shields.io/packagist/l/pdt256/shipping.svg)](https://github.com/pdt256/shipping/blob/master/LICENSE.txt)
[![Total Downloads](https://poser.pugx.org/pdt256/shipping/downloads.svg)](https://packagist.org/packages/pdt256/shipping) [![Latest Stable Version](https://poser.pugx.org/pdt256/shipping/v/stable.svg)](https://packagist.org/packages/pdt256/shipping) [![Latest Unstable Version](https://poser.pugx.org/pdt256/shipping/v/unstable.svg)](https://packagist.org/packages/pdt256/shipping) [![License](https://poser.pugx.org/pdt256/shipping/license.svg)](https://packagist.org/packages/pdt256/shipping)
A shipping rate wrapper for USPS, UPS, and Fedex.
## Introduction
## Installation
This is a PHP shipping package that wraps API calls to UPS, FedEx, and USPS for shipping rates.
Multiple packages can be added to get additional rates.
All code (including tests) conform to the PSR-2 coding standards.
The namespace and autoloader are using the PSR-4 standard.
Add the following lines to your ``composer.json`` file.
```JSON
{
"require": {
"pdt256/shipping": "dev-master"
}
}
```
## Example
Create a shipment object:
```php
$shipment = new Shipment;
$shipment
->setFromIsResidential(false)
->setFromStateProvinceCode('IN')
->setFromPostalCode('46205')
->setFromCountryCode('US')
->setToIsResidential(true)
->setToPostalCode('20101')
->setToCountryCode('US');
$package = new Package;
$package
->setLength(12)
->setWidth(4)
->setHeight(3)
->setWeight(3);
$shipment->addPackage($package);
$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,
],
];
```
## UPS (Stub) Example
Below is an example request to get shipping rates from the UPS API.
Below is an example request to get shipping rates from the UPS API.
Notice: The below line uses a stub class to fake a response from the UPS API.
You can immediately use this method in your code until you get an account with UPS.
```php
'requestAdapter' => new RateRequest\StubUPS(),
'request_adapter' => new RateRequest\StubUPS(),
```
```php
@ -57,65 +56,53 @@ use pdt256\Shipping\UPS;
use pdt256\Shipping\RateRequest;
$ups = new UPS\Rate([
'prod' => false,
'accessKey' => 'XXXX',
'userId' => 'XXXX',
'password' => 'XXXX',
'shipperNumber' => 'XXXX',
'shipment' => $shipment,
'approvedCodes' => [
'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
],
'requestAdapter' => new RateRequest\StubUPS(),
'prod' => FALSE,
'access_key' => 'XXXX',
'user_id' => 'XXXX',
'password' => 'XXXX',
'shipper_number' => 'XXXX',
'shipment' => $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(),
]);
$rates = $ups->getRates();
$ups_rates = $ups->get_rates();
```
Output array sorted by cost: (in cents)
```php
array (
0 =>
pdt256\Shipping\Quote::__set_state(array(
'code' => '03',
'name' => 'UPS Ground',
'cost' => 1910,
'transitTime' => NULL,
'deliveryEstimate' => NULL,
'carrier' => 'ups',
)),
1 =>
pdt256\Shipping\Quote::__set_state(array(
'code' => '02',
'name' => 'UPS 2nd Day Air',
'cost' => 4923,
'transitTime' => NULL,
'deliveryEstimate' => NULL,
'carrier' => 'ups',
)),
2 =>
pdt256\Shipping\Quote::__set_state(array(
'code' => '13',
'name' => 'UPS Next Day Air Saver',
'cost' => 8954,
'transitTime' => NULL,
'deliveryEstimate' => NULL,
'carrier' => 'ups',
)),
3 =>
pdt256\Shipping\Quote::__set_state(array(
'code' => '01',
'name' => 'UPS Next Day Air',
'cost' => 9328,
'transitTime' => NULL,
'deliveryEstimate' => NULL,
'carrier' => 'ups',
)),
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,
),
)
```
@ -126,42 +113,39 @@ use pdt256\Shipping\USPS;
use pdt256\Shipping\RateRequest;
$usps = new USPS\Rate([
'prod' => false,
'prod' => FALSE,
'username' => 'XXXX',
'password' => 'XXXX',
'shipment' => $shipment,
'approvedCodes' => [
'shipment' => array_merge($shipment, [
'size' => 'LARGE',
'container' => 'RECTANGULAR',
]),
'approved_codes' => [
'1', // 1-3 business days
'4', // 2-8 business days
],
'requestAdapter' => new RateRequest\StubUSPS(),
'request_adapter' => new RateRequest\StubUSPS(),
]);
$rates = $usps->getRates();
$usps_rates = $usps->get_rates();
```
Output array sorted by cost: (in cents)
```php
array (
0 =>
pdt256\Shipping\Quote::__set_state(array(
'code' => '4',
'name' => 'Parcel Post',
'cost' => 1001,
'transitTime' => NULL,
'deliveryEstimate' => NULL,
'carrier' => 'usps',
)),
1 =>
pdt256\Shipping\Quote::__set_state(array(
'code' => '1',
'name' => 'Priority Mail',
'cost' => 1220,
'transitTime' => NULL,
'deliveryEstimate' => NULL,
'carrier' => 'usps',
)),
1 =>
array (
'code' => '4',
'name' => 'Parcel Post',
'cost' => 1000,
),
0 =>
array (
'code' => '1',
'name' => 'Priority Mail',
'cost' => 1200,
),
)
```
@ -175,106 +159,64 @@ $fedex = new Fedex\Rate([
'prod' => FALSE,
'key' => 'XXXX',
'password' => 'XXXX',
'accountNumber' => 'XXXX',
'meterNumber' => 'XXXX',
'dropOffType' => 'BUSINESS_SERVICE_CENTER',
'shipment' => $shipment,
'approvedCodes' => [
'account_number' => 'XXXX',
'meter_number' => 'XXXX',
'drop_off_type' => 'BUSINESS_SERVICE_CENTER',
'shipment' => array_merge($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
],
'requestAdapter' => new RateRequest\StubFedex(),
'request_adapter' => new RateRequest\StubFedex(),
]);
$rates = $fedex->getRates();
$fedex_rates = $fedex->get_rates();
```
Output array sorted by cost: (in cents)
```php
array (
0 =>
pdt256\Shipping\Quote::__set_state(array(
'code' => 'GROUND_HOME_DELIVERY',
'name' => 'Ground Home Delivery',
'cost' => 1655,
'transitTime' => 'THREE_DAYS',
'deliveryEstimate' => NULL,
'carrier' => 'fedex',
)),
1 =>
pdt256\Shipping\Quote::__set_state(array(
'code' => 'FEDEX_EXPRESS_SAVER',
'name' => 'Fedex Express Saver',
'cost' => 2989,
'transitTime' => NULL,
'deliveryEstimate' =>
DateTime::__set_state(array(
'date' => '2014-09-30 20:00:00',
'timezone_type' => 3,
'timezone' => 'UTC',
)),
'carrier' => 'fedex',
)),
2 =>
pdt256\Shipping\Quote::__set_state(array(
'code' => 'FEDEX_2_DAY',
'name' => 'Fedex 2 Day',
'cost' => 4072,
'transitTime' => NULL,
'deliveryEstimate' =>
DateTime::__set_state(array(
'date' => '2014-09-29 20:00:00',
'timezone_type' => 3,
'timezone' => 'UTC',
)),
'carrier' => 'fedex',
)),
3 =>
pdt256\Shipping\Quote::__set_state(array(
'code' => 'STANDARD_OVERNIGHT',
'name' => 'Standard Overnight',
'cost' => 7834,
'transitTime' => NULL,
'deliveryEstimate' =>
DateTime::__set_state(array(
'date' => '2014-09-26 20:00:00',
'timezone_type' => 3,
'timezone' => 'UTC',
)),
'carrier' => 'fedex',
)),
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,
),
)
```
## Unit Tests:
```bash
vendor/bin/phpunit
```
### With Code Coverage:
```bash
vendor/bin/phpunit --coverage-text --coverage-html coverage_report
```
### With Live API Tests:
```bash
./live_phpunit.sh
```
## Run Coding Standards Test:
```bash
vendor/bin/phpcs --standard=PSR2 src/ tests/
```
### License
The MIT License (MIT)

View File

@ -1,5 +1,5 @@
{
"name": "netsyms/shippingrates",
"name": "pdt256/shipping",
"description": "Shipping Rate API",
"license": "MIT",
"keywords": ["ship", "ups", "usps", "fedex"],
@ -7,23 +7,11 @@
{
"name": "Jamie Isaacs",
"email": "pdt256@gmail.com"
},
{
"name": "Netsyms Technologies",
"email": "opensource@netsyms.com"
}
],
"extra": {
"branch-alias": {
"dev-master": "1.0.x-dev"
}
},
"require": {},
"require-dev": {
"phpunit/phpunit": "7.0.*",
"squizlabs/php_codesniffer": "3.5.*"
},
"require": {
"php": ">=7.1"
"phpunit/phpunit": "4.0.*"
},
"autoload": {
"psr-4": {

View File

@ -1,16 +0,0 @@
#!/bin/bash
export USPS_USERNAME='XXXXXXXXXXXX'
export USPS_PASSWORD='XXXXXXXXXXXX'
export UPS_ACCESS_KEY='XXXXXXXXXXXXXXXX'
export UPS_USER_ID='XXXXXX'
export UPS_PASSWORD='XXXX'
export UPS_SHIPPER_NUMBER='XXXXXX'
export FEDEX_KEY='XXXXXXXXXXXXXXXX'
export FEDEX_PASSWORD='XXXXXXXXXXXXXXXXXXXXXXXXX'
export FEDEX_ACCOUNT_NUMBER='XXXXXXXXX'
export FEDEX_METER_NUMBER='XXXXXXXXX'
vendor/bin/phpunit

View File

@ -1,22 +0,0 @@
auxiliary.org-netbeans-modules-php-phpunit.bootstrap_2e_create_2e_tests=false
auxiliary.org-netbeans-modules-php-phpunit.bootstrap_2e_enabled=false
auxiliary.org-netbeans-modules-php-phpunit.bootstrap_2e_path=
auxiliary.org-netbeans-modules-php-phpunit.configuration_2e_enabled=false
auxiliary.org-netbeans-modules-php-phpunit.configuration_2e_path=
auxiliary.org-netbeans-modules-php-phpunit.customSuite_2e_enabled=false
auxiliary.org-netbeans-modules-php-phpunit.customSuite_2e_path=
auxiliary.org-netbeans-modules-php-phpunit.phpUnit_2e_enabled=false
auxiliary.org-netbeans-modules-php-phpunit.phpUnit_2e_path=
auxiliary.org-netbeans-modules-php-phpunit.test_2e_groups_2e_ask=false
auxiliary.org-netbeans-modules-php-phpunit.test_2e_run_2e_all=false
auxiliary.org-netbeans-modules-php-phpunit.test_2e_run_2e_phpunit_2e_only=false
file.reference.ShippingRates-tests=tests
include.path=${php.global.include.path}
php.version=PHP_73
source.encoding=UTF-8
src.dir=src
tags.asp=false
tags.short=false
test.src.dir=${file.reference.ShippingRates-tests}
testing.providers=PhpUnit
web.root=.

View File

@ -1,9 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://www.netbeans.org/ns/project/1">
<type>org.netbeans.modules.php.project</type>
<configuration>
<data xmlns="http://www.netbeans.org/ns/php-project/1">
<name>ShippingRates</name>
</data>
</configuration>
</project>

View File

@ -1,22 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit backupGlobals="false"
backupStaticAttributes="false"
bootstrap="vendor/autoload.php"
colors="true"
convertErrorsToExceptions="true"
convertNoticesToExceptions="true"
convertWarningsToExceptions="true"
processIsolation="false"
stopOnFailure="false"
syntaxCheck="false">
<testsuites>
<testsuite name="Ship Test Suite">
<directory suffix=".php">./tests</directory>
</testsuite>
</testsuites>
<filter>
<whitelist>
<directory>./src</directory>
</whitelist>
</filter>
backupStaticAttributes="false"
bootstrap="vendor/autoload.php"
colors="true"
convertErrorsToExceptions="true"
convertNoticesToExceptions="true"
convertWarningsToExceptions="true"
processIsolation="false"
stopOnFailure="false"
syntaxCheck="false">
<testsuites>
<testsuite name="Ship Test Suite">
<directory suffix=".php">./tests</directory>
</testsuite>
</testsuites>
</phpunit>

View File

@ -3,8 +3,8 @@ namespace pdt256\Shipping;
class Arr
{
public static function get($array, $key, $default = null)
{
return isset($array[$key]) ? $array[$key] : $default;
}
public static function get($array, $key, $default = NULL)
{
return isset($array[$key]) ? $array[$key] : $default;
}
}

View File

@ -1,249 +1,236 @@
<?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 pdt256\Shipping\Validator;
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 $url_dev = 'https://gatewaybeta.fedex.com/web-services/';
private $url_prod = 'https://gateway.fedex.com/web-services/';
private $key;
private $password;
private $accountNumber;
private $meterNumber;
/**
* Type of Drop off, default value "BUSINESS_SERVICE_CENTER" is defined in __construct if not specified.
*/
private $dropOffType;
/**
* Codes of appropriate shipping types. Default value is specified in __construct.
*/
public $approvedCodes;
private $key = 'XXX';
private $password = 'XXX';
private $account_number = 'XXX';
private $meter_number = 'XXX';
private $drop_off_type = 'BUSINESS_SERVICE_CENTER';
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 $approved_codes = [
'PRIORITY_OVERNIGHT',
'FEDEX_2_DAY',
'FEDEX_EXPRESS_SAVER',
'FEDEX_GROUND',
'GROUND_HOME_DELIVERY',
];
public function __construct($options = [])
{
parent::__construct($options);
private $shipping_codes = [
'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',
];
$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', [
'PRIORITY_OVERNIGHT',
'FEDEX_2_DAY',
'FEDEX_EXPRESS_SAVER',
'FEDEX_GROUND',
'GROUND_HOME_DELIVERY',
]);
$this->dropOffType = Arr::get($options, 'dropOffType', 'BUSINESS_SERVICE_CENTER');
public function __construct($options = [])
{
parent::__construct($options);
$this->setRequestAdapter(Arr::get($options, 'requestAdapter', new RateRequest\Post()));
}
protected function validate()
{
$this->validatePackages();
Validator::checkIfNull($this->key, 'key');
Validator::checkIfNull($this->password, 'password');
Validator::checkIfNull($this->accountNumber, 'accountNumber');
Validator::checkIfNull($this->meterNumber, 'meterNumber');
Validator::checkIfNull($this->shipment->getFromPostalCode(), 'fromPostalCode');
Validator::checkIfNull($this->shipment->getFromCountryCode(), 'fromCountryCode');
Validator::checkIfNull($this->shipment->getFromIsResidential(), 'fromIsResidential');
Validator::checkIfNull($this->shipment->getToPostalCode(), 'toPostalCode');
Validator::checkIfNull($this->shipment->getToCountryCode(), 'toCountryCode');
Validator::checkIfNull($this->shipment->getToIsResidential(), 'toIsResidential');
if (isset($options['key'])) {
$this->key = $options['key'];
}
return $this;
}
protected function prepare()
{
$date = time();
$day_name = date('l', $date);
if (isset($options['password'])) {
$this->password = $options['password'];
}
if ($day_name == 'Saturday') {
$date += 172800;
} elseif ($day_name == 'Sunday') {
$date += 86400;
}
if (isset($options['account_number'])) {
$this->account_number = $options['account_number'];
}
// 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
if (isset($options['meter_number'])) {
$this->meter_number = $options['meter_number'];
}
$packages = '';
$sequence_number = 0;
foreach ($this->shipment->getPackages() as $package) {
$sequence_number++;
if (isset($options['approved_codes'])) {
$this->approved_codes = $options['approved_codes'];
}
$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>';
if (isset($options['drop_off_type'])) {
$this->drop_off_type = $options['drop_off_type'];
}
return $this;
}
if (isset($options['request_adapter'])) {
$this->set_request_adapter($options['request_adapter']);
} else {
$this->set_request_adapter(new RateRequest\Post());
}
}
protected function execute()
{
if ($this->isProduction) {
$url = $this->urlProd;
} else {
$url = $this->urlDev;
}
protected function prepare()
{
$to = Arr::get($this->shipment, 'to');
$shipper = Arr::get($this->shipment, 'from');
$dimensions = Arr::get($this->shipment, 'dimensions');
$this->response = $this->rateRequest->execute($url, $this->data);
$pounds = (int) Arr::get($this->shipment, 'weight');
$ounces = 0;
return $this;
}
if ($pounds < 1) {
throw new Exception('Weight missing');
}
protected function process()
{
try {
$dom = new DOMDocument('1.0', 'UTF-8');
$dom->loadXml($this->response);
$rate_reply = $dom->getElementsByTagName('RateReplyDetails');
$date = time();
$day_name = date('l', $date);
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;
}
if ($day_name == 'Saturday') {
$date += 172800;
} elseif ($day_name == 'Sunday') {
$date += 86400;
}
foreach ($rate_reply as $rate) {
$code = $rate->getElementsByTagName('ServiceType')->item(0)->nodeValue;
// 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
if (! empty($this->approvedCodes) && ! in_array($code, $this->approvedCodes)) {
continue;
}
$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->account_number . '</AccountNumber>
<MeterNumber>' . $this->meter_number . '</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->drop_off_type . '</DropoffType>
<PackagingType>' . Arr::get($this->shipment, 'packaging_type') . '</PackagingType>
<Shipper>
<Address>
<PostalCode>' . Arr::get($shipper, 'postal_code') . '</PostalCode>
<CountryCode>' . Arr::get($shipper, 'country_code') . '</CountryCode>
' . ((Arr::get($shipper, 'is_residential')) ? '<Residential>1</Residential>' : '') . '
</Address>
</Shipper>
<Recipient>
<Address>
<PostalCode>' . Arr::get($to, 'postal_code') . '</PostalCode>
<CountryCode>' . Arr::get($to, 'country_code') . '</CountryCode>
' . ((Arr::get($to, 'is_residential')) ? '<Residential>1</Residential>' : '') . '
</Address>
</Recipient>
<RateRequestTypes>LIST</RateRequestTypes>
<PackageCount>1</PackageCount>
<RequestedPackageLineItems>
<SequenceNumber>1</SequenceNumber>
<GroupPackageCount>1</GroupPackageCount>
<Weight>
<Units>LB</Units>
<Value>' . $pounds . '</Value>
</Weight>
<Dimensions>
<Length>' . Arr::get($dimensions, 'length') . '</Length>
<Width>' . Arr::get($dimensions, 'width') . '</Width>
<Height>' . Arr::get($dimensions, 'height') . '</Height>
<Units>IN</Units>
</Dimensions>
</RequestedPackageLineItems>
</RequestedShipment>
</RateRequest>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>';
$name = Arr::get($this->shippingCodes, $code);
return $this;
}
$delivery_ts = @$rate->getElementsByTagName('DeliveryTimestamp')->item(0)->nodeValue;
$transit_time = @$rate->getElementsByTagName('TransitTime')->item(0)->nodeValue;
protected function execute()
{
if ($this->is_prod) {
$url = $this->url_prod;
} else {
$url = $this->url_dev;
}
$cost = $rate
->getElementsByTagName('RatedShipmentDetails')->item(0)
->getElementsByTagName('ShipmentRateDetail')->item(0)
->getElementsByTagName('TotalNetCharge')->item(0)
->getElementsByTagName('Amount')->item(0)->nodeValue;
$this->response = $this->rate_request->execute($url, $this->data);
$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));
}
return $this;
}
$this->rates[] = $quote;
}
protected function process()
{
try {
$dom = new DOMDocument('1.0', 'UTF-8');
$dom->loadXml($this->response);
$rate_reply = $dom->getElementsByTagName('RateReplyDetails');
return $this;
}
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->approved_codes) AND ! in_array($code, $this->approved_codes)) {
continue;
}
$name = Arr::get($this->shipping_codes, $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;
$this->rates[] = array(
'code' => $code,
'name' => $name,
'cost' => (int) ($cost * 100),
'delivery_ts' => $delivery_ts,
'transit_time' => $transit_time,
);
}
return $this;
}
}

View File

@ -1,105 +0,0 @@
<?php
namespace pdt256\Shipping;
class Package {
protected $pounds;
protected $ounces;
protected $width;
protected $length;
protected $height;
public function getWeight() {
$weight = 0;
if (!empty($this->getPounds())) {
$weight += $this->getPounds();
}
if (!empty($this->getOunces())) {
$weight += ($this->getOunces() / 16);
}
if ($weight == 0) {
return null;
}
return $weight;
}
public function getPounds() {
return $this->pounds ?? 0;
}
public function getOunces() {
return $this->ounces ?? 0;
}
public function setWeight($pounds) {
return $this->setPounds($pounds)->setOunces(0);
}
/**
* @param mixed $pounds
* @return $this
*/
public function setPounds($pounds) {
$this->pounds = $pounds;
return $this;
}
/**
* @param mixed $ounces
* @return $this
*/
public function setOunces($ounces) {
$this->ounces = $ounces;
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;
}
}

View File

@ -1,131 +0,0 @@
<?php namespace pdt256\Shipping;
use DateTime;
class Quote
{
protected $code;
protected $name;
protected $cost;
protected $transitTime;
protected $deliveryEstimate;
protected $carrier;
public function __construct($carrier = null, $code = null, $name = null, $cost = null)
{
$this->setCarrier($carrier);
$this->setCode($code);
$this->setName($name);
$this->setCost($cost);
}
/**
* @return mixed
*/
public function getCarrier()
{
return $this->carrier;
}
/**
* @param mixed $carrier
* @return $this
*/
public function setCarrier($carrier)
{
$this->carrier = (string) $carrier;
return $this;
}
/**
* @return mixed
*/
public function getCode()
{
return $this->code;
}
/**
* @param string $code
* @return $this
*/
public function setCode($code)
{
$this->code = (string) $code;
return $this;
}
/**
* @return mixed
*/
public function getName()
{
return $this->name;
}
/**
* @param string $name
* @return $this
*/
public function setName($name)
{
$this->name = (string) $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 = (int) $cost;
return $this;
}
/**
* @return mixed
*/
public function getTransitTime()
{
return $this->transitTime;
}
/**
* @param mixed $transitTime
* @return $this
*/
public function setTransitTime($transitTime)
{
$this->transitTime = $transitTime;
return $this;
}
/**
* @return mixed
*/
public function getDeliveryEstimate()
{
return $this->deliveryEstimate;
}
/**
* @param DateTime $deliveryEstimate
* @return $this
*/
public function setDeliveryEstimate(DateTime $deliveryEstimate)
{
$this->deliveryEstimate = $deliveryEstimate;
return $this;
}
}

View File

@ -1,108 +1,64 @@
<?php
namespace pdt256\Shipping;
use Exception;
abstract class RateAdapter
{
protected $isProduction;
protected $is_prod = FALSE;
/** @var Shipment */
protected $shipment;
protected $data;
protected $response;
protected $rates;
protected $shipment;
protected $data;
protected $response;
protected $rates = [];
/** @var @var RateRequest\Adapter */
protected $rateRequest;
protected $rate_request;
/**
* Make sure all necessary fields are set
* @return self
*/
abstract protected function validate();
abstract protected function prepare(); // Prepare XML
abstract protected function execute(); // Curl Request
abstract protected function process(); // Convert to shipping rates array
/**
* Prepare XML
* @return self
*/
abstract protected function prepare();
public function __construct($options = [])
{
if (isset($options['prod'])) {
$this->is_prod = (bool) $options['prod'];
}
/**
* Curl Request
* @return self
*/
abstract protected function execute();
if (isset($options['shipment'])) {
$this->shipment = $options['shipment'];
}
/**
* Convert to shipping rates array
* @return self
*/
abstract protected function process();
if (empty($this->shipment['to'])) {
throw new Exception('Shipment "to" missing');
}
/**
* @throws \LogicException
* To be called from validate() when packages have to have 3 dimensions and weight
*/
protected function validatePackages()
{
foreach ($this->shipment->getPackages() as $package) {
Validator::checkIfNull($package->getWeight(), 'weight');
Validator::checkIfNull($package->getLength(), 'length');
Validator::checkIfNull($package->getHeight(), 'height');
Validator::checkIfNull($package->getWidth(), 'width');
}
}
public function __construct($options = [])
{
$this->rates = [];
if (empty($this->shipment['from'])) {
throw new Exception('Shipment "from" missing');
}
$this->isProduction = (bool) Arr::get($options, 'prod', false);
$this->shipment = Arr::get($options, 'shipment');
}
if (empty($this->shipment['dimensions'])) {
throw new Exception('Shipment "dimensions" missing');
}
}
public function setRequestAdapter(RateRequest\Adapter $rateRequest)
{
$this->rateRequest = $rateRequest;
}
public function set_request_adapter(RateRequest\Adapter $rate_request)
{
$this->rate_request = $rate_request;
}
public function setShipment($shipment)
{
$this->shipment = $shipment;
}
public function get_rates()
{
$this
->prepare()
->execute()
->process()
->sort_by_cost();
public function getShipment()
{
return $this->shipment;
}
return $this->rates;
}
public function setIsProduction($isProduction): void
{
$this->isProduction = $isProduction;
}
public function getIsProduction(): bool
{
return $this->isProduction;
}
/**
* @return Quote[]
*/
public function getRates(): array
{
$this
->validate()
->prepare()
->execute()
->process()
->sortByCost();
return array_values($this->rates);
}
protected function sortByCost(): void
{
uasort($this->rates, static function (Quote $a, Quote $b) {
return ($a->getCost() > $b->getCost());
});
}
protected function sort_by_cost()
{
uasort($this->rates, create_function('$a, $b', 'return ($a["cost"] > $b["cost"]);'));
}
}

View File

@ -3,8 +3,8 @@ namespace pdt256\Shipping\RateRequest;
abstract class Adapter
{
protected $curlConnectTimeoutInMilliseconds = 1500;
protected $curlDownloadTimeoutInSeconds = 50;
protected $curl_connect_timeout_ms = 1000; // milliseconds
protected $curl_dl_timeout = 11; // seconds
abstract public function execute($url, $data = null);
abstract public function execute($url, $data = NULL);
}

File diff suppressed because it is too large Load Diff

View File

@ -3,25 +3,20 @@ namespace pdt256\Shipping\RateRequest;
class Get extends Adapter
{
public function execute($url, $data = null)
{
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_HEADER, false);
curl_setopt($ch, CURLOPT_HTTPGET, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
//curl_setopt($ch, CURLOPT_SSL_CIPHER_LIST, 'TLSv1');
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT_MS, $this->curlConnectTimeoutInMilliseconds);
curl_setopt($ch, CURLOPT_TIMEOUT, $this->curlDownloadTimeoutInSeconds);
$response = curl_exec($ch);
if ($response === false) {
$error = curl_error($ch);
curl_close($ch);
throw new RequestException($error);
}
curl_close($ch);
return $response;
}
public function execute($url, $data = NULL)
{
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_HEADER, FALSE);
curl_setopt($ch, CURLOPT_HTTPGET, TRUE);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT_MS, $this->curl_connect_timeout_ms);
curl_setopt($ch, CURLOPT_TIMEOUT, $this->curl_dl_timeout);
$response = curl_exec($ch);
curl_close($ch);
return $response;
}
}

View File

@ -3,25 +3,21 @@ namespace pdt256\Shipping\RateRequest;
class Post extends Adapter
{
public function execute($url, $data = null)
{
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_HEADER, false);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
//curl_setopt($ch, CURLOPT_SSL_CIPHER_LIST, 'TLSv1');
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT_MS, $this->curlConnectTimeoutInMilliseconds);
curl_setopt($ch, CURLOPT_TIMEOUT, $this->curlDownloadTimeoutInSeconds);
$response = curl_exec($ch);
if ($response === false) {
throw new RequestException(curl_error($ch));
}
curl_close($ch);
public function execute($url, $data = NULL)
{
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_HEADER, FALSE);
curl_setopt($ch, CURLOPT_POST, TRUE);
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT_MS, $this->curl_connect_timeout_ms);
curl_setopt($ch, CURLOPT_TIMEOUT, $this->curl_dl_timeout);
$response = curl_exec($ch);
curl_close($ch);
return $response;
}
return $response;
}
}

View File

@ -1,6 +0,0 @@
<?php
namespace pdt256\Shipping\RateRequest;
class RequestException extends \Exception
{
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -3,19 +3,22 @@ namespace pdt256\Shipping\RateRequest;
class StubUSPS extends Adapter
{
private $artificialDelay = 0;
private $artificial_delay = 0;
public function __construct($artificial_delay = 0)
{
$this->artificialDelay = $artificial_delay;
}
public function __construct($artificial_delay = 0)
{
$this->artificial_delay = $artificial_delay;
}
public function execute($url, $data = null)
{
if ($this->artificialDelay > 0) {
sleep($this->artificialDelay);
}
public function execute($url, $data = NULL)
{
if ($this->artificial_delay > 0) {
sleep($this->artificial_delay);
}
return file_get_contents(__DIR__ . '/USPSResponse.xml');
}
$response = '<?xml version="1.0" encoding="UTF-8"?>
<RateV4Response><Package ID="1"><ZipOrigination>90401</ZipOrigination><ZipDestination>76667</ZipDestination><Pounds>3</Pounds><Ounces>0</Ounces><Size>LARGE</Size><Machinable>FALSE</Machinable><Zone>6</Zone><Postage CLASSID="3"><MailService>Priority Mail Express 2-Day&amp;lt;sup&amp;gt;&amp;#8482;&amp;lt;/sup&amp;gt;</MailService><Rate>42.25</Rate></Postage><Postage CLASSID="2"><MailService>Priority Mail Express 2-Day&amp;lt;sup&amp;gt;&amp;#8482;&amp;lt;/sup&amp;gt; Hold For Pickup</MailService><Rate>42.25</Rate></Postage><Postage CLASSID="1"><MailService>Priority Mail 2-Day&amp;lt;sup&amp;gt;&amp;#8482;&amp;lt;/sup&amp;gt;</MailService><Rate>12.20</Rate></Postage><Postage CLASSID="4"><MailService>Standard Post&amp;lt;sup&amp;gt;&amp;#174;&amp;lt;/sup&amp;gt;</MailService><Rate>10.01</Rate></Postage><Postage CLASSID="6"><MailService>Media Mail Parcel</MailService><Rate>3.65</Rate></Postage><Postage CLASSID="7"><MailService>Library Mail Parcel</MailService><Rate>3.48</Rate></Postage></Package></RateV4Response>';
return $response;
}
}

View File

@ -1,247 +0,0 @@
<?xml version="1.0"?>
<RatingServiceSelectionResponse>
<Response>
<ResponseStatusCode>1</ResponseStatusCode>
<ResponseStatusDescription>Success</ResponseStatusDescription>
</Response>
<RatedShipment>
<Service>
<Code>03</Code>
</Service>
<RatedShipmentWarning>Your invoice may vary from the displayed reference rates</RatedShipmentWarning>
<RatedShipmentWarning>Missing / Invalid Shipper Number. Returned rates are Retail Rates.</RatedShipmentWarning>
<BillingWeight>
<UnitOfMeasurement>
<Code>LBS</Code>
</UnitOfMeasurement>
<Weight>3.0</Weight>
</BillingWeight>
<TransportationCharges>
<CurrencyCode>USD</CurrencyCode>
<MonetaryValue>19.10</MonetaryValue>
</TransportationCharges>
<ServiceOptionsCharges>
<CurrencyCode>USD</CurrencyCode>
<MonetaryValue>0.00</MonetaryValue>
</ServiceOptionsCharges>
<TotalCharges>
<CurrencyCode>USD</CurrencyCode>
<MonetaryValue>19.10</MonetaryValue>
</TotalCharges>
<GuaranteedDaysToDelivery/>
<ScheduledDeliveryTime/>
<RatedPackage>
<TransportationCharges>
<CurrencyCode>USD</CurrencyCode>
<MonetaryValue>19.10</MonetaryValue>
</TransportationCharges>
<ServiceOptionsCharges>
<CurrencyCode>USD</CurrencyCode>
<MonetaryValue>0.00</MonetaryValue>
</ServiceOptionsCharges>
<TotalCharges>
<CurrencyCode>USD</CurrencyCode>
<MonetaryValue>19.10</MonetaryValue>
</TotalCharges>
<Weight>3.0</Weight>
<BillingWeight>
<UnitOfMeasurement>
<Code>LBS</Code>
</UnitOfMeasurement>
<Weight>3.0</Weight>
</BillingWeight>
</RatedPackage>
</RatedShipment>
<RatedShipment>
<Service>
<Code>12</Code>
</Service>
<RatedShipmentWarning>Your invoice may vary from the displayed reference rates</RatedShipmentWarning>
<RatedShipmentWarning>Missing / Invalid Shipper Number. Returned rates are Retail Rates.</RatedShipmentWarning>
<BillingWeight>
<UnitOfMeasurement>
<Code>LBS</Code>
</UnitOfMeasurement>
<Weight>5.0</Weight>
</BillingWeight>
<TransportationCharges>
<CurrencyCode>USD</CurrencyCode>
<MonetaryValue>37.18</MonetaryValue>
</TransportationCharges>
<ServiceOptionsCharges>
<CurrencyCode>USD</CurrencyCode>
<MonetaryValue>0.00</MonetaryValue>
</ServiceOptionsCharges>
<TotalCharges>
<CurrencyCode>USD</CurrencyCode>
<MonetaryValue>37.18</MonetaryValue>
</TotalCharges>
<GuaranteedDaysToDelivery>3</GuaranteedDaysToDelivery>
<ScheduledDeliveryTime/>
<RatedPackage>
<TransportationCharges>
<CurrencyCode>USD</CurrencyCode>
<MonetaryValue>37.18</MonetaryValue>
</TransportationCharges>
<ServiceOptionsCharges>
<CurrencyCode>USD</CurrencyCode>
<MonetaryValue>0.00</MonetaryValue>
</ServiceOptionsCharges>
<TotalCharges>
<CurrencyCode>USD</CurrencyCode>
<MonetaryValue>37.18</MonetaryValue>
</TotalCharges>
<Weight>3.0</Weight>
<BillingWeight>
<UnitOfMeasurement>
<Code>LBS</Code>
</UnitOfMeasurement>
<Weight>5.0</Weight>
</BillingWeight>
</RatedPackage>
</RatedShipment>
<RatedShipment>
<Service>
<Code>02</Code>
</Service>
<RatedShipmentWarning>Your invoice may vary from the displayed reference rates</RatedShipmentWarning>
<RatedShipmentWarning>Missing / Invalid Shipper Number. Returned rates are Retail Rates.</RatedShipmentWarning>
<BillingWeight>
<UnitOfMeasurement>
<Code>LBS</Code>
</UnitOfMeasurement>
<Weight>5.0</Weight>
</BillingWeight>
<TransportationCharges>
<CurrencyCode>USD</CurrencyCode>
<MonetaryValue>49.23</MonetaryValue>
</TransportationCharges>
<ServiceOptionsCharges>
<CurrencyCode>USD</CurrencyCode>
<MonetaryValue>0.00</MonetaryValue>
</ServiceOptionsCharges>
<TotalCharges>
<CurrencyCode>USD</CurrencyCode>
<MonetaryValue>49.23</MonetaryValue>
</TotalCharges>
<GuaranteedDaysToDelivery>2</GuaranteedDaysToDelivery>
<ScheduledDeliveryTime/>
<RatedPackage>
<TransportationCharges>
<CurrencyCode>USD</CurrencyCode>
<MonetaryValue>49.23</MonetaryValue>
</TransportationCharges>
<ServiceOptionsCharges>
<CurrencyCode>USD</CurrencyCode>
<MonetaryValue>0.00</MonetaryValue>
</ServiceOptionsCharges>
<TotalCharges>
<CurrencyCode>USD</CurrencyCode>
<MonetaryValue>49.23</MonetaryValue>
</TotalCharges>
<Weight>3.0</Weight>
<BillingWeight>
<UnitOfMeasurement>
<Code>LBS</Code>
</UnitOfMeasurement>
<Weight>5.0</Weight>
</BillingWeight>
</RatedPackage>
</RatedShipment>
<RatedShipment>
<Service>
<Code>13</Code>
</Service>
<RatedShipmentWarning>Your invoice may vary from the displayed reference rates</RatedShipmentWarning>
<RatedShipmentWarning>Missing / Invalid Shipper Number. Returned rates are Retail Rates.</RatedShipmentWarning>
<BillingWeight>
<UnitOfMeasurement>
<Code>LBS</Code>
</UnitOfMeasurement>
<Weight>5.0</Weight>
</BillingWeight>
<TransportationCharges>
<CurrencyCode>USD</CurrencyCode>
<MonetaryValue>89.54</MonetaryValue>
</TransportationCharges>
<ServiceOptionsCharges>
<CurrencyCode>USD</CurrencyCode>
<MonetaryValue>0.00</MonetaryValue>
</ServiceOptionsCharges>
<TotalCharges>
<CurrencyCode>USD</CurrencyCode>
<MonetaryValue>89.54</MonetaryValue>
</TotalCharges>
<GuaranteedDaysToDelivery>1</GuaranteedDaysToDelivery>
<ScheduledDeliveryTime/>
<RatedPackage>
<TransportationCharges>
<CurrencyCode>USD</CurrencyCode>
<MonetaryValue>89.54</MonetaryValue>
</TransportationCharges>
<ServiceOptionsCharges>
<CurrencyCode>USD</CurrencyCode>
<MonetaryValue>0.00</MonetaryValue>
</ServiceOptionsCharges>
<TotalCharges>
<CurrencyCode>USD</CurrencyCode>
<MonetaryValue>89.54</MonetaryValue>
</TotalCharges>
<Weight>3.0</Weight>
<BillingWeight>
<UnitOfMeasurement>
<Code>LBS</Code>
</UnitOfMeasurement>
<Weight>5.0</Weight>
</BillingWeight>
</RatedPackage>
</RatedShipment>
<RatedShipment>
<Service>
<Code>01</Code>
</Service>
<RatedShipmentWarning>Your invoice may vary from the displayed reference rates</RatedShipmentWarning>
<RatedShipmentWarning>Missing / Invalid Shipper Number. Returned rates are Retail Rates.</RatedShipmentWarning>
<BillingWeight>
<UnitOfMeasurement>
<Code>LBS</Code>
</UnitOfMeasurement>
<Weight>5.0</Weight>
</BillingWeight>
<TransportationCharges>
<CurrencyCode>USD</CurrencyCode>
<MonetaryValue>93.28</MonetaryValue>
</TransportationCharges>
<ServiceOptionsCharges>
<CurrencyCode>USD</CurrencyCode>
<MonetaryValue>0.00</MonetaryValue>
</ServiceOptionsCharges>
<TotalCharges>
<CurrencyCode>USD</CurrencyCode>
<MonetaryValue>93.28</MonetaryValue>
</TotalCharges>
<GuaranteedDaysToDelivery>1</GuaranteedDaysToDelivery>
<ScheduledDeliveryTime>12:00 Noon</ScheduledDeliveryTime>
<RatedPackage>
<TransportationCharges>
<CurrencyCode>USD</CurrencyCode>
<MonetaryValue>93.28</MonetaryValue>
</TransportationCharges>
<ServiceOptionsCharges>
<CurrencyCode>USD</CurrencyCode>
<MonetaryValue>0.00</MonetaryValue>
</ServiceOptionsCharges>
<TotalCharges>
<CurrencyCode>USD</CurrencyCode>
<MonetaryValue>93.28</MonetaryValue>
</TotalCharges>
<Weight>3.0</Weight>
<BillingWeight>
<UnitOfMeasurement>
<Code>LBS</Code>
</UnitOfMeasurement>
<Weight>5.0</Weight>
</BillingWeight>
</RatedPackage>
</RatedShipment>
</RatingServiceSelectionResponse>

View File

@ -1,37 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<RateV4Response>
<Package ID="1">
<ZipOrigination>90401</ZipOrigination>
<ZipDestination>76667</ZipDestination>
<Pounds>3</Pounds>
<Ounces>0</Ounces>
<Size>LARGE</Size>
<Machinable>FALSE</Machinable>
<Zone>6</Zone>
<Postage CLASSID="3">
<MailService>Priority Mail Express 2-Day&amp;lt;sup&amp;gt;&amp;#8482;&amp;lt;/sup&amp;gt;</MailService>
<Rate>42.25</Rate>
</Postage>
<Postage CLASSID="2">
<MailService>Priority Mail Express 2-Day&amp;lt;sup&amp;gt;&amp;#8482;&amp;lt;/sup&amp;gt; Hold For Pickup
</MailService>
<Rate>42.25</Rate>
</Postage>
<Postage CLASSID="1">
<MailService>Priority Mail 2-Day&amp;lt;sup&amp;gt;&amp;#8482;&amp;lt;/sup&amp;gt;</MailService>
<Rate>12.20</Rate>
</Postage>
<Postage CLASSID="4">
<MailService>Standard Post&amp;lt;sup&amp;gt;&amp;#174;&amp;lt;/sup&amp;gt;</MailService>
<Rate>10.01</Rate>
</Postage>
<Postage CLASSID="6">
<MailService>Media Mail Parcel</MailService>
<Rate>3.65</Rate>
</Postage>
<Postage CLASSID="7">
<MailService>Library Mail Parcel</MailService>
<Rate>3.48</Rate>
</Postage>
</Package>
</RateV4Response>

View File

@ -3,146 +3,145 @@ namespace pdt256\Shipping;
class Ship
{
protected $shipping_options = [
'Standard Shipping' => [
'ups' => [
'03' => '1-5 business days',
],
'fedex' => [
'FEDEX_EXPRESS_SAVER' => '1-3 business days',
'FEDEX_GROUND' => '1-5 business days',
'GROUND_HOME_DELIVERY' => '1-5 business days',
],
'usps' => [
'1' => '1-3 business days',
'4' => '2-8 business days',
],
],
'Two-Day Shipping' => [
'ups' => [
'02' => '2 business days',
],
'fedex' => [
'FEDEX_2_DAY' => '2 business days',
],
],
'One-Day Shipping' => [
'ups' => [
'01' => 'next business day 10:30am',
'13' => 'next business day by 3pm',
'14' => 'next business day by 8am',
],
'fedex' => [
'STANDARD_OVERNIGHT' => 'overnight',
],
],
];
protected $shipping_options = [
'Standard Shipping' => [
'ups' => [
'03' => '1-5 business days',
],
'fedex' => [
'FEDEX_EXPRESS_SAVER' => '1-3 business days',
'FEDEX_GROUND' => '1-5 business days',
'GROUND_HOME_DELIVERY' => '1-5 business days',
],
'usps' => [
'1' => '1-3 business days',
'4' => '2-8 business days',
],
],
'Two-Day Shipping' => [
'ups' => [
'02' => '2 business days',
],
'fedex' => [
'FEDEX_2_DAY' => '2 business days',
],
],
'One-Day Shipping' => [
'ups' => [
'01' => 'next business day 10:30am',
'13' => 'next business day by 3pm',
'14' => 'next business day by 8am',
],
'fedex' => [
'STANDARD_OVERNIGHT' => 'overnight',
],
],
];
public static function factory($shipping_options = [])
{
$object = new self();
public static function factory($shipping_options = [])
{
$object = new self();
if (!empty($shipping_options)) {
$object->shipping_options = $shipping_options;
}
if ( ! empty($shipping_options)) {
$object->shipping_options = $shipping_options;
}
return $object;
}
return $object;
}
/**
* @return array
*/
public function getApprovedCodes($carrier = null)
{
$approvedCodes = [];
public function get_approved_codes($carrier = NULL) {
$approved_codes = [];
// Build approvedCodes
foreach ($this->shipping_options as $shipping_group => $row) {
foreach ($row as $_carrier => $row2) {
if (!isset($approvedCodes[$_carrier])) {
$approvedCodes[$_carrier] = [];
}
// Build approved_codes
foreach ($this->shipping_options as $shipping_group => $row) {
foreach ($row2 as $code => $display) {
$approvedCodes[$_carrier][] = $code;
}
}
}
foreach ($row as $_carrier => $row2) {
if ( ! isset($approved_codes[$_carrier])) {
$approved_codes[$_carrier] = [];
}
if ($carrier !== null && isset($approvedCodes[$carrier])) {
return $approvedCodes[$carrier];
}
foreach ($row2 as $code => $display) {
$approved_codes[$_carrier][] = $code;
}
}
}
return $approvedCodes;
}
if ($carrier !== NULL AND isset($approved_codes[$carrier])) {
return $approved_codes[$carrier];
}
public function getDisplayRates($rates)
{
// Build output array with cheapest shipping option for each group
$display_rates = [];
foreach ($this->shipping_options as $shipping_group => $row) {
$display_rates[$shipping_group] = [];
$cheapest_row = null;
return $approved_codes;
}
foreach ($row as $carrier => $row2) {
$group_codes = array_keys($row2);
public function get_display_rates($rates)
{
// Build output array with cheapest shipping option for each group
$display_rates = [];
foreach ($this->shipping_options as $shipping_group => $row) {
$display_rates[$shipping_group] = [];
$cheapest_row = NULL;
if (! empty($rates[$carrier])) {
foreach ($rates[$carrier] as $row3) {
if (in_array($row3->getCode(), $group_codes)) {
$row3->setCarrier($carrier);
foreach ($row as $carrier => $row2) {
$group_codes = array_keys($row2);
if ($cheapest_row === null) {
$cheapest_row = $row3;
} else {
if ($row3->getCost() < $cheapest_row->getCost()) {
$cheapest_row = $row3;
}
}
}
}
}
}
if ( ! empty($rates[$carrier])) {
// Add row if it exists
if (! empty($cheapest_row)) {
$display_rates[$shipping_group][] = $cheapest_row;
}
}
foreach ($rates[$carrier] as $row3) {
return $display_rates;
}
if (in_array($row3['code'], $group_codes)) {
$row3['carrier'] = $carrier;
public function getAllDisplayRates($rates)
{
// Build output array listing all group options
$display_rates = [];
foreach ($this->shipping_options as $shipping_group => $row) {
$display_rates[$shipping_group] = [];
if ($cheapest_row === NULL) {
$cheapest_row = $row3;
} else {
if ($row3['cost'] < $cheapest_row['cost']) {
$cheapest_row = $row3;
}
}
}
}
}
}
foreach ($row as $carrier => $row2) {
$group_codes = array_keys($row2);
// Add row if it exists
if ( ! empty($cheapest_row)) {
$display_rates[$shipping_group][] = $cheapest_row;
}
}
if (!empty($rates[$carrier])) {
foreach ($rates[$carrier] as $row3) {
if (in_array($row3->getCode(), $group_codes)) {
$row3->setCarrier($carrier);
$display_rates[$shipping_group][] = $row3;
}
}
}
}
return $display_rates;
}
$this->sortByCost($display_rates[$shipping_group]);
}
public function get_all_display_rates($rates)
{
// Build output array listing all group options
$display_rates = [];
foreach ($this->shipping_options as $shipping_group => $row) {
$display_rates[$shipping_group] = [];
return $display_rates;
}
foreach ($row as $carrier => $row2) {
$group_codes = array_keys($row2);
protected function sortByCost(&$rates)
{
uasort($rates, function ($a, $b) {
return ($a->getCost() > $b->getCost());
});
}
if ( ! empty($rates[$carrier])) {
foreach ($rates[$carrier] as $row3) {
if (in_array($row3['code'], $group_codes)) {
$row3['carrier'] = $carrier;
$display_rates[$shipping_group][] = $row3;
}
}
}
}
$this->sort_by_cost($display_rates[$shipping_group]);
}
return $display_rates;
}
protected function sort_by_cost( & $rates)
{
uasort($rates, create_function('$a, $b', 'return ($a["cost"] > $b["cost"]);'));
}
}

View File

@ -1,170 +0,0 @@
<?php namespace pdt256\Shipping;
class Shipment
{
/** @var Package[] */
protected $packages = [];
/** @var bool */
protected $fromIsResidential;
protected $fromPostalCode;
protected $fromCountryCode;
protected $fromStateProvince;
/** @var bool */
protected $toIsResidential;
protected $toPostalCode;
protected $toCountryCode;
/**
* @param Package $package
* @return $this
*/
public function addPackage(Package $package)
{
$this->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->fromPostalCode;
}
/**
* @param mixed $fromPostalCode
* @return $this
*/
public function setFromPostalCode($fromPostalCode)
{
$this->fromPostalCode = $fromPostalCode;
return $this;
}
/**
* @return mixed
*/
public function getFromCountryCode()
{
return $this->fromCountryCode;
}
/**
* @param mixed $fromCountryCode
* @return $this
*/
public function setFromCountryCode($fromCountryCode)
{
$this->fromCountryCode = $fromCountryCode;
return $this;
}
/**
* @return mixed
*/
public function getToPostalCode()
{
return $this->toPostalCode;
}
/**
* @param mixed $toPostalCode
* @return $this
*/
public function setToPostalCode($toPostalCode)
{
$this->toPostalCode = $toPostalCode;
return $this;
}
/**
* @return mixed
*/
public function getToCountryCode()
{
return $this->toCountryCode;
}
/**
* @param mixed $toCountryCode
* @return $this
*/
public function setToCountryCode($toCountryCode)
{
$this->toCountryCode = $toCountryCode;
return $this;
}
/**
* @return boolean
*/
public function getToIsResidential()
{
return $this->toIsResidential;
}
/**
* @param boolean $toIsResidential
* @return $this
*/
public function setToIsResidential($toIsResidential)
{
$this->toIsResidential = $toIsResidential;
return $this;
}
/**
* @return bool
*/
public function getFromIsResidential()
{
return $this->fromIsResidential;
}
/**
* @param $fromIsResidential
* @return $this
*/
public function setFromIsResidential($fromIsResidential)
{
$this->fromIsResidential = $fromIsResidential;
return $this;
}
/**
* @return mixed
*/
public function getFromStateProvinceCode()
{
return $this->fromStateProvince;
}
/**
* @param $fromStateProvince
* @return $this
*/
public function setFromStateProvinceCode($fromStateProvince)
{
$this->fromStateProvince = $fromStateProvince;
return $this;
}
}

View File

@ -1,266 +1,247 @@
<?php
namespace pdt256\Shipping\UPS;
use pdt256\Ship;
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 = 'https://wwwcie.ups.com/ups.app/xml/Rate';
private $urlProd = 'https://www.ups.com/ups.app/xml/Rate';
private $url_dev = 'https://wwwcie.ups.com/ups.app/xml/Rate';
private $url_prod = 'https://www.ups.com/ups.app/xml/Rate';
private $accessKey;
private $userId;
private $password;
private $shipperNumber;
/**
* Codes of appropriate shipping types. Default value is specified in __construct.
*/
public $approvedCodes;
private $access_key = 'XXX';
private $user_id = 'XXX';
private $password = 'XXX';
private $shipper_number = 'XXX';
private $shippingCodes = [
'US' => [ // United States
'01' => 'UPS Next Day Air',
'02' => 'UPS 2nd Day Air',
'03' => 'UPS Ground',
'07' => 'UPS Worldwide Express',
'08' => 'UPS Worldwide Expedited',
'11' => 'UPS Standard',
'12' => 'UPS 3 Day Select',
'13' => 'UPS Next Day Air Saver',
'14' => 'UPS Next Day Air Early A.M.',
'54' => 'UPS Worldwide Express Plus',
'59' => 'UPS 2nd Day Air A.M.',
'65' => 'UPS Saver',
],
'CA' => [ // Canada
'01' => 'UPS Express',
'02' => 'UPS Expedited',
'07' => 'UPS Worldwide Express',
'08' => 'UPS Worldwide Expedited',
'11' => 'UPS Standard',
'12' => 'UPS 3 Day Select',
'13' => 'UPS Saver',
'14' => 'UPS Express Early A.M.',
'54' => 'UPS Worldwide Express Plus',
'65' => 'UPS Saver',
],
'EU' => [ // European Union
'07' => 'UPS Express',
'08' => 'UPS Expedited',
'11' => 'UPS Standard',
'54' => 'UPS Worldwide Express Plus',
'65' => 'UPS Saver',
'82' => 'UPS Today Standard',
'83' => 'UPS Today Dedicated Courier',
'84' => 'UPS Today Intercity',
'85' => 'UPS Today Express',
'86' => 'UPS Today Express Saver',
'01' => 'UPS Next Day Air',
'02' => 'UPS 2nd Day Air',
'03' => 'UPS Ground',
'14' => 'UPS Next Day Air Early A.M.',
],
'MX' => [ // Mexico
'07' => 'UPS Express',
'08' => 'UPS Expedited',
'54' => 'UPS Express Plus',
'65' => 'UPS Saver',
],
'other' => [ // Other
'07' => 'UPS Express',
'08' => 'UPS Worldwide Expedited',
'11' => 'UPS Standard',
'54' => 'UPS Worldwide Express Plus',
'65' => 'UPS Saver',
],
];
public $approved_codes = [
'03',
'12',
];
public function __construct($options = [])
{
parent::__construct($options);
private $shipping_codes = [
'US' => [ // United States
'01' => 'UPS Next Day Air',
'02' => 'UPS 2nd Day Air',
'03' => 'UPS Ground',
'07' => 'UPS Worldwide Express',
'08' => 'UPS Worldwide Expedited',
'11' => 'UPS Standard',
'12' => 'UPS 3 Day Select',
'13' => 'UPS Next Day Air Saver',
'14' => 'UPS Next Day Air Early A.M.',
'54' => 'UPS Worldwide Express Plus',
'59' => 'UPS 2nd Day Air A.M.',
'65' => 'UPS Saver',
],
'CA' => [ // Canada
'01' => 'UPS Express',
'02' => 'UPS Expedited',
'07' => 'UPS Worldwide Express',
'08' => 'UPS Worldwide Expedited',
'11' => 'UPS Standard',
'12' => 'UPS 3 Day Select',
'13' => 'UPS Saver',
'14' => 'UPS Express Early A.M.',
'54' => 'UPS Worldwide Express Plus',
'65' => 'UPS Saver',
],
'EU' => [ // European Union
'07' => 'UPS Express',
'08' => 'UPS Expedited',
'11' => 'UPS Standard',
'54' => 'UPS Worldwide Express Plus',
'65' => 'UPS Saver',
'82' => 'UPS Today Standard',
'83' => 'UPS Today Dedicated Courier',
'84' => 'UPS Today Intercity',
'85' => 'UPS Today Express',
'86' => 'UPS Today Express Saver',
'01' => 'UPS Next Day Air',
'02' => 'UPS 2nd Day Air',
'03' => 'UPS Ground',
'14' => 'UPS Next Day Air Early A.M.',
],
'MX' => [ // Mexico
'07' => 'UPS Express',
'08' => 'UPS Expedited',
'54' => 'UPS Express Plus',
'65' => 'UPS Saver',
],
'other' => [ // Other
'07' => 'UPS Express',
'08' => 'UPS Worldwide Expedited',
'11' => 'UPS Standard',
'54' => 'UPS Worldwide Express Plus',
'65' => 'UPS Saver',
],
];
$this->accessKey = Arr::get($options, 'accessKey');
$this->userId = Arr::get($options, 'userId');
$this->password = Arr::get($options, 'password');
$this->shipperNumber = Arr::get($options, 'shipperNumber');
$this->approvedCodes = Arr::get($options, 'approvedCodes', [
'03',
'12',
]);
public function __construct($options = [])
{
parent::__construct($options);
$this->setRequestAdapter(Arr::get($options, 'requestAdapter', new RateRequest\Post()));
}
if (isset($options['access_key'])) {
$this->access_key = $options['access_key'];
}
protected function validate()
{
$this->validatePackages();
Validator::checkIfNull($this->accessKey, 'accessKey');
Validator::checkIfNull($this->userId, 'userId');
Validator::checkIfNull($this->password, 'password');
Validator::checkIfNull($this->shipperNumber, 'shipperNumber');
Validator::checkIfNull($this->shipment->getFromPostalCode(), 'fromPostalCode');
Validator::checkIfNull($this->shipment->getFromCountryCode(), 'fromCountryCode');
Validator::checkIfNull($this->shipment->getFromIsResidential(), 'fromIsResidential');
Validator::checkIfNull($this->shipment->getToPostalCode(), 'toPostalCode');
Validator::checkIfNull($this->shipment->getToCountryCode(), 'toCountryCode');
Validator::checkIfNull($this->shipment->getToIsResidential(), 'toIsResidential');
if (isset($options['user_id'])) {
$this->user_id = $options['user_id'];
}
return $this;
}
protected function prepare()
{
$service_code = '03';
if (isset($options['password'])) {
$this->password = $options['password'];
}
$this->data = '<?xml version="1.0"?>' . "\n" .
'<AccessRequest xml:lang="en-US">' .
'<AccessLicenseNumber>' . $this->accessKey . '</AccessLicenseNumber>'.
'<UserId>' . $this->userId . '</UserId>' .
'<Password>' . $this->password . '</Password>' .
'</AccessRequest>' .
'<RatingServiceSelectionRequest xml:lang="en-US">' .
'<Request>' .
'<RequestAction>Rate</RequestAction>' .
'<RequestOption>shop</RequestOption>' .
'</Request>' .
'<Shipment>' .
'<Shipper>' .
'<Address>' .
'<PostalCode>' . $this->shipment->getFromPostalCode() . '</PostalCode>' .
'<CountryCode>' . $this->shipment->getFromCountryCode() . '</CountryCode>' .
(
$this->shipment->getFromIsResidential() ?
'<ResidentialAddressIndicator>1</ResidentialAddressIndicator>' :
''
) .
'</Address>' .
'<ShipperNumber>' . $this->shipperNumber . '</ShipperNumber>' .
'</Shipper>' .
'<ShipTo>' .
'<Address>' .
'<PostalCode>' . $this->shipment->getToPostalCode() . '</PostalCode>' .
'<CountryCode>' . $this->shipment->getToCountryCode() . '</CountryCode>' .
(
$this->shipment->getToIsResidential() ?
'<ResidentialAddressIndicator>1</ResidentialAddressIndicator>' :
''
) .
'</Address>' .
'</ShipTo>' .
'<ShipFrom>' .
'<Address>' .
'<StateProvinceCode>' .
$this->shipment->getFromStateProvinceCode() .
'</StateProvinceCode>' .
'<PostalCode>' . $this->shipment->getFromPostalCode() . '</PostalCode>' .
'<CountryCode>' . $this->shipment->getFromCountryCode() . '</CountryCode>' .
(
$this->shipment->getFromIsResidential() ?
'<ResidentialAddressIndicator>1</ResidentialAddressIndicator>' :
''
) .
'</Address>' .
'</ShipFrom>' .
'<Service>' .
'<Code>' . $service_code . '</Code>' .
'</Service>' .
$this->getPackagesXmlString() .
'<RateInformation>' .
'<NegotiatedRatesIndicator/>' .
'</RateInformation>' .
'</Shipment>' .
'</RatingServiceSelectionRequest>';
if (isset($options['shipper_number'])) {
$this->shipper_number = $options['shipper_number'];
}
return $this;
}
if (isset($options['approved_codes'])) {
$this->approved_codes = $options['approved_codes'];
}
protected function getPackagesXmlString()
{
$packages = '';
foreach ($this->shipment->getPackages() as $p) {
$packages .=
'<Package>' .
'<PackagingType>' .
'<Code>02</Code>' .
'</PackagingType>' .
'<Dimensions>' .
'<UnitOfMeasurement>' .
'<Code>IN</Code>' .
'</UnitOfMeasurement>' .
'<Length>' . $p->getLength() . '</Length>' .
'<Width>' . $p->getWidth() . '</Width>' .
'<Height>' . $p->getHeight() . '</Height>' .
'</Dimensions>' .
'<PackageWeight>' .
'<UnitOfMeasurement>' .
'<Code>LBS</Code>' .
'</UnitOfMeasurement>' .
'<Weight>' . $p->getWeight() . '</Weight>' .
'</PackageWeight>' .
'</Package>';
}
if (isset($options['request_adapter'])) {
$this->set_request_adapter($options['request_adapter']);
} else {
$this->set_request_adapter(new RateRequest\Post());
}
}
return $packages;
}
protected function prepare()
{
$to = Arr::get($this->shipment, 'to');
$shipper = Arr::get($this->shipment, 'from');
$dimensions = Arr::get($this->shipment, 'dimensions');
protected function execute()
{
if ($this->isProduction) {
$url = $this->urlProd;
} else {
$url = $this->urlDev;
}
$pounds = (int) Arr::get($this->shipment, 'weight');
$ounces = 0;
$this->response = $this->rateRequest->execute($url, $this->data);
if ($pounds < 1) {
throw new Exception('Weight missing');
}
return $this;
}
$service_code = '03';
protected function process()
{
try {
$dom = new DOMDocument('1.0', 'UTF-8');
$dom->loadXml($this->response);
$this->data =
'<?xml version="1.0"?>
<AccessRequest xml:lang="en-US">
<AccessLicenseNumber>' . $this->access_key . '</AccessLicenseNumber>
<UserId>' . $this->user_id . '</UserId>
<Password>' . $this->password . '</Password>
</AccessRequest>
<RatingServiceSelectionRequest xml:lang="en-US">
<Request>
<RequestAction>Rate</RequestAction>
<RequestOption>shop</RequestOption>
</Request>
<Shipment>
<Shipper>
<Address>
<PostalCode>' . Arr::get($shipper, 'postal_code') . '</PostalCode>
<CountryCode>' . Arr::get($shipper, 'country_code') . '</CountryCode>
' . ((Arr::get($shipper, 'is_residential')) ? '<ResidentialAddressIndicator>1</ResidentialAddressIndicator>' : '') . '
</Address>
<ShipperNumber>' . $this->shipper_number . '</ShipperNumber>
</Shipper>
<ShipTo>
<Address>
<PostalCode>' . Arr::get($to, 'postal_code') . '</PostalCode>
<CountryCode>' . Arr::get($to, 'country_code') . '</CountryCode>
' . ((Arr::get($to, 'is_residential')) ? '<ResidentialAddressIndicator>1</ResidentialAddressIndicator>' : '') . '
</Address>
</ShipTo>
<ShipFrom>
<Address>
<PostalCode>' . Arr::get($shipper, 'postal_code') . '</PostalCode>
<CountryCode>' . Arr::get($shipper, 'country_code') . '</CountryCode>
' . ((Arr::get($shipper, 'is_residential')) ? '<ResidentialAddressIndicator>1</ResidentialAddressIndicator>' : '') . '
</Address>
</ShipFrom>
<Service>
<Code>' . $service_code . '</Code>
</Service>
<Package>
<PackagingType>
<Code>02</Code>
</PackagingType>
<Dimensions>
<UnitOfMeasurement>
<Code>IN</Code>
</UnitOfMeasurement>
<Length>' . Arr::get($dimensions, 'length') . '</Length>
<Width>' . Arr::get($dimensions, 'width') . '</Width>
<Height>' . Arr::get($dimensions, 'height') . '</Height>
</Dimensions>
<PackageWeight>
<UnitOfMeasurement>
<Code>LBS</Code>
</UnitOfMeasurement>
<Weight>' . $pounds . '</Weight>
</PackageWeight>
</Package>
</Shipment>
</RatingServiceSelectionRequest>';
$rate_list = $dom->getElementsByTagName('RatedShipment');
return $this;
}
if (empty($rate_list->length)) {
throw new Exception('Unable to get UPS Rates.');
}
} catch (Exception $e) {
echo $this->response;
throw $e;
}
protected function execute()
{
if ($this->is_prod) {
$url = $this->url_prod;
} else {
$url = $this->url_dev;
}
foreach ($rate_list as $rate) {
$code = @$rate
->getElementsByTagName('Service')->item(0)
->getElementsByTagName('Code')->item(0)->nodeValue;
$this->response = $this->rate_request->execute($url, $this->data);
$name = Arr::get($this->shippingCodes['US'], $code);
return $this;
}
$cost = @$rate
->getElementsByTagName('TotalCharges')->item(0)
->getElementsByTagName('MonetaryValue')->item(0)->nodeValue;
protected function process()
{
try {
$dom = new DOMDocument('1.0', 'UTF-8');
$dom->loadXml($this->response);
if (! empty($this->approvedCodes) && ! in_array($code, $this->approvedCodes)) {
continue;
}
$rate_list = @$dom->getElementsByTagName('RatedShipment');
$quote = new Quote;
$quote
->setCarrier('ups')
->setCode($code)
->setName($name)
->setCost($cost * 100);
$this->rates[] = $quote;
}
if (empty($rate_list->length)) {
throw new Exception('Unable to get UPS Rates.');
}
} catch (Exception $e) {
// StatsD::increment('error.shipping.get_ups_rate');
// Kohana::$log->add(Log::ERROR, $e)->write();
throw $e;
}
return $this;
}
foreach ($rate_list as $rate) {
$code = @$rate
->getElementsByTagName('Service')->item(0)
->getElementsByTagName('Code')->item(0)->nodeValue;
$name = Arr::get($this->shipping_codes['US'], $code);
$cost = @$rate
->getElementsByTagName('TotalCharges')->item(0)
->getElementsByTagName('MonetaryValue')->item(0)->nodeValue;
if ( ! empty($this->approved_codes) AND ! in_array($code, $this->approved_codes)) {
continue;
}
$this->rates[] = array(
'code' => $code,
'name' => $name,
'cost' => (int) ($cost * 100),
);
}
return $this;
}
}

View File

@ -1,206 +1,182 @@
<?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 {
class Rate extends RateAdapter
{
private $url_dev = 'http://production.shippingapis.com/ShippingAPI.dll';
private $url_prod = 'http://production.shippingapis.com/ShippingAPI.dll';
private $urlDev = 'http://production.shippingapis.com/ShippingAPI.dll';
private $urlProd = 'http://production.shippingapis.com/ShippingAPI.dll';
private $username;
private $password;
private $username = 'XXX';
private $password = 'XXX';
/**
* 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 $approved_codes = [
'1',
'4',
];
public function __construct($options = []) {
parent::__construct($options);
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',
],
];
$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()));
}
public function __construct($options = [])
{
parent::__construct($options);
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');
if (isset($options['username'])) {
$this->username = $options['username'];
}
return $this;
}
if (isset($options['password'])) {
$this->password = $options['password'];
}
protected function prepare() {
$packages = '';
$sequence_number = 0;
foreach ($this->shipment->getPackages() as $p) {
$sequence_number++;
if (isset($options['username'])) {
$this->username = $options['username'];
}
/**
* 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 (isset($options['approved_codes'])) {
$this->approved_codes = $options['approved_codes'];
}
*/
if ($p->getWidth() > 12 or $p->getLength() > 12 or $p->getHeight() > 12) {
$size = 'LARGE';
$container = 'RECTANGULAR';
} else {
$size = 'REGULAR';
$container = 'VARIABLE';
}
if (isset($options['request_adapter'])) {
$this->set_request_adapter($options['request_adapter']);
} else {
$this->set_request_adapter(new RateRequest\Get());
}
}
$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>';
}
protected function prepare()
{
$to = Arr::get($this->shipment, 'to');
$shipper = Arr::get($this->shipment, 'from');
$dimensions = Arr::get($this->shipment, 'dimensions');
$this->data = '<RateV4Request USERID="' . $this->username . '">' .
'<Revision/>' .
$packages .
'</RateV4Request>';
// https://www.usps.com/business/web-tools-apis/rate-calculators-v1-7a.htm
$pounds = (int) Arr::get($this->shipment, 'weight');
$ounces = 0;
return $this;
}
if ($pounds < 1) {
throw new Exception('Weight missing');
}
protected function execute() {
if ($this->isProduction) {
$url = $this->urlProd;
} else {
$url = $this->urlDev;
}
$this->data =
'<RateV4Request USERID="' . $this->username . '">
<Revision/>
<Package ID="1">
<Service>ALL</Service>
<ZipOrigination>' . Arr::get($shipper, 'postal_code') . '</ZipOrigination>
<ZipDestination>' . Arr::get($to, 'postal_code') . '</ZipDestination>
<Pounds>' . $pounds . '</Pounds>
<Ounces>' . $ounces . '</Ounces>
<Container>' . Arr::get($this->shipment, 'container') . '</Container>
<Size>' . Arr::get($this->shipment, 'size') . '</Size>
<Width>' . Arr::get($dimensions, 'width') . '</Width>
<Length>' . Arr::get($dimensions, 'length') . '</Length>
<Height>' . Arr::get($dimensions, 'height') . '</Height>
<Machinable>' . 'False' . '</Machinable>
</Package>
</RateV4Request>';
$url_request = $url . '?API=RateV4&XML=' . rawurlencode($this->data);
return $this;
}
$this->response = $this->rateRequest->execute($url_request);
protected function execute()
{
if ($this->is_prod) {
$url = $this->url_prod;
} else {
$url = $this->url_dev;
}
return $this;
}
$url_request = $url . '?API=RateV4&XML=' . rawurlencode($this->data);
protected function process() {
try {
$dom = new DOMDocument('1.0', 'UTF-8');
$dom->loadXml($this->response);
$this->response = $this->rate_request->execute($url_request);
$postage_list = @$dom->getElementsByTagName('Postage');
return $this;
}
if (empty($postage_list)) {
throw new Exception('Unable to get USPS Rates.');
}
} catch (Exception $e) {
throw $e;
}
protected function process()
{
try {
$dom = new DOMDocument('1.0', 'UTF-8');
$dom->loadXml($this->response);
/** @var Quote[] $rates */
$rates = [];
$postage_list = @$dom->getElementsByTagName('Postage');
foreach ($postage_list as $postage) {
$code = @$postage->getAttribute('CLASSID');
$cost = @$postage->getElementsByTagName('Rate')->item(0)->nodeValue;
if (empty($postage_list)) {
throw new Exception('Unable to get USPS Rates.');
}
} catch (Exception $e) {
// StatsD::increment('error.shipping.get_usps_rate');
// Kohana::$log->add(Log::ERROR, $e)->write();
throw $e;
}
$name = Arr::get($this->shipping_codes['domestic'], $code);
foreach ($postage_list as $postage) {
$code = @$postage->getAttribute('CLASSID');
$cost = @$postage->getElementsByTagName('Rate')->item(0)->nodeValue;
if (!empty($this->approvedCodes) && !in_array($code, $this->approvedCodes)) {
continue;
}
$name = Arr::get($this->shipping_codes['domestic'], $code);
if (array_key_exists($code, $rates)) {
$cost = $rates[$code]->getCost() + ($cost * 100);
} else {
$cost = $cost * 100;
}
if ( ! empty($this->approved_codes) AND ! in_array($code, $this->approved_codes)) {
continue;
}
$quote = new Quote;
$quote
->setCarrier('usps')
->setCode($code)
->setName($name)
->setCost((int) $cost);
$rates[$quote->getCode()] = $quote;
}
$this->rates = array_values($rates);
return $this;
}
$this->rates[] = array(
'code' => $code,
'name' => $name,
'cost' => (int) ($cost * 100),
);
}
return $this;
}
}

View File

@ -1,12 +0,0 @@
<?php
namespace pdt256\Shipping;
class Validator
{
public static function checkIfNull($value, $name)
{
if ($value === null) {
throw new \LogicException("$name is not set");
}
}
}

View File

@ -1,30 +0,0 @@
<?php
namespace pdt256\Shipping;
use PHPUnit\Framework\TestCase;
class ArrTest extends TestCase
{
public function providerGet()
{
return array(
array(array('uno', 'dos', 'tress'), 1, null, 'dos'),
array(array('we' => 'can', 'make' => 'change'), 'we', null, 'can'),
array(array('uno', 'dos', 'tress'), 10, null, null),
array(array('we' => 'can', 'make' => 'change'), 'he', null, null),
array(array('we' => 'can', 'make' => 'change'), 'he', 'who', 'who'),
array(array('we' => 'can', 'make' => 'change'), 'he', array('arrays'), array('arrays')),
);
}
/**
* @dataProvider providerGet()
*/
public function testGet(array $array, $key, $default, $expected)
{
$this->assertSame(
$expected,
Arr::get($array, $key, $default)
);
}
}

View File

@ -1,187 +0,0 @@
<?php
namespace pdt256\Shipping\Fedex;
use pdt256\Shipping\RateRequest\StubFedex;
use pdt256\Shipping\Ship;
use pdt256\Shipping\Package;
use pdt256\Shipping\Shipment;
use pdt256\Shipping\Quote;
use DateTime;
use PHPUnit\Framework\TestCase;
class RateTest extends TestCase
{
/** @var Shipment */
protected $shipment;
protected $approvedCodes = [];
public function setUp()
{
$ship = Ship::factory([
'Standard Shipping' => [
'fedex' => [
'FEDEX_EXPRESS_SAVER' => '1-3 business days',
'FEDEX_GROUND' => '1-5 business days',
'GROUND_HOME_DELIVERY' => '1-5 business days',
],
],
'Two-Day Shipping' => [
'fedex' => [
'FEDEX_2_DAY' => '2 business days',
],
],
'One-Day Shipping' => [
'fedex' => [
'STANDARD_OVERNIGHT' => 'overnight',
],
],
]);
$this->approvedCodes = $ship->getApprovedCodes('fedex');
$package = new Package;
$package->setWeight(3)
->setWidth(9)
->setLength(9)
->setHeight(9);
$this->shipment = new Shipment;
$this->shipment->setFromStateProvinceCode('CA')
->setFromPostalCode('90401')
->setFromCountryCode('US')
->setFromIsResidential(true)
->setToPostalCode('78703')
->setToCountryCode('US')
->setToIsResidential(true)
->addPackage($package);
}
public function testMockRates()
{
$rateAdapter = new Rate([
'prod' => false,
'key' => 'XXX',
'password' => 'XXX',
'accountNumber' => 'XXX',
'meterNumber' => 'XXX',
'dropOffType' => 'BUSINESS_SERVICE_CENTER',
'shipment' => $this->shipment,
'approvedCodes' => $this->approvedCodes,
'requestAdapter' => new StubFedex,
]);
$rates = $rateAdapter->getRates();
$ground = new Quote('fedex', 'GROUND_HOME_DELIVERY', 'Ground Home Delivery', 1655);
$ground->setTransitTime('THREE_DAYS');
$express = new Quote('fedex', 'FEDEX_EXPRESS_SAVER', 'Fedex Express Saver', 2989);
$express->setDeliveryEstimate(new DateTime('2014-09-30T20:00:00'));
$secondDay = new Quote('fedex', 'FEDEX_2_DAY', 'Fedex 2 Day', 4072);
$secondDay->setDeliveryEstimate(new DateTime('2014-09-29T20:00:00'));
$overnight = new Quote('fedex', 'STANDARD_OVERNIGHT', 'Standard Overnight', 7834);
$overnight->setDeliveryEstimate(new DateTime('2014-09-26T20:00:00'));
$expected = [$ground, $express, $secondDay, $overnight];
$this->assertEquals($expected, $rates);
}
public function testLiveRates()
{
if (getenv('FEDEX_KEY') === false) {
$this->markTestSkipped('Live Fedex credentials missing.');
}
$rateAdapter = new Rate([
'prod' => false,
'key' => getenv('FEDEX_KEY'),
'password' => getenv('FEDEX_PASSWORD'),
'account_number' => getenv('FEDEX_ACCOUNT_NUMBER'),
'meter_number' => getenv('FEDEX_METER_NUMBER'),
'drop_off_type' => 'BUSINESS_SERVICE_CENTER',
'shipment' => $this->shipment,
'approvedCodes' => $this->approvedCodes,
'requestAdapter' => new StubFedex,
]);
$rates = $rateAdapter->getRates();
$this->assertTrue(count($rates) > 0);
$this->assertTrue($rates[0] instanceof Quote);
}
/**
* @expectedException \LogicException
*/
public function testMissingKey()
{
$rateAdapter = new Rate([
'prod' => false,
'password' => 'XXX',
'accountNumber' => 'XXX',
'meterNumber' => 'XXX',
'dropOffType' => 'BUSINESS_SERVICE_CENTER',
'shipment' => $this->shipment,
'approvedCodes' => $this->approvedCodes,
'requestAdapter' => new StubFedex,
]);
$rateAdapter->getRates();
}
/**
* @expectedException \LogicException
*/
public function testMissingPassword()
{
$rateAdapter = new Rate([
'prod' => false,
'key' => 'XXX',
'accountNumber' => 'XXX',
'meterNumber' => 'XXX',
'dropOffType' => 'BUSINESS_SERVICE_CENTER',
'shipment' => $this->shipment,
'approvedCodes' => $this->approvedCodes,
'requestAdapter' => new StubFedex,
]);
$rateAdapter->getRates();
}
/**
* @expectedException \LogicException
*/
public function testMissingAccountNumber()
{
$rateAdapter = new Rate([
'prod' => false,
'key' => 'XXX',
'password' => 'XXX',
'meterNumber' => 'XXX',
'dropOffType' => 'BUSINESS_SERVICE_CENTER',
'shipment' => $this->shipment,
'approvedCodes' => $this->approvedCodes,
'requestAdapter' => new StubFedex,
]);
$rateAdapter->getRates();
}
/**
* @expectedException \LogicException
*/
public function testMissingMeterNumber()
{
$rateAdapter = new Rate([
'prod' => false,
'key' => 'XXX',
'password' => 'XXX',
'accountNumber' => 'XXX',
'dropOffType' => 'BUSINESS_SERVICE_CENTER',
'shipment' => $this->shipment,
'approvedCodes' => $this->approvedCodes,
'requestAdapter' => new StubFedex,
]);
$rateAdapter->getRates();
}
}

View File

@ -1,227 +0,0 @@
<?php
namespace pdt256\Shipping;
use pdt256\Shipping\RateRequest\StubFedex;
use pdt256\Shipping\RateRequest\StubUPS;
use pdt256\Shipping\RateRequest\StubUSPS;
use PHPUnit\Framework\TestCase;
class PackageDimensionsValidationTrait extends TestCase
{
protected function getNormalPackage()
{
$normalPackage = new Package();
$normalPackage
->setHeight(10)
->setWidth(6)
->setLength(10)
->setWeight(5)
;
return $normalPackage;
}
protected function getNoHeightPackage()
{
$noHeightPackage = new Package();
$noHeightPackage
->setWidth(6)
->setLength(10)
->setWeight(5)
;
return $noHeightPackage;
}
protected function getNoWidthPackage()
{
$noWidthPackage = new Package();
$noWidthPackage
->setHeight(10)
->setLength(10)
->setWeight(5)
;
return $noWidthPackage;
}
protected function getNoLengthPackage()
{
$noLengthPackage = new Package();
$noLengthPackage
->setHeight(10)
->setWidth(6)
->setWeight(5)
;
return $noLengthPackage;
}
protected function getNoWeightPackage()
{
$noWeightPackage = new Package();
$noWeightPackage
->setHeight(10)
->setWidth(10)
->setWidth(6)
;
return $noWeightPackage;
}
protected function getUSPSAdapter()
{
return new USPS\Rate([
'prod' => false,
'username' => 'XXXX',
'password' => 'XXXX',
'requestAdapter' => new StubUSPS(),
]);
}
protected function getUPSAdapter()
{
return new UPS\Rate([
'accessKey' => 'XXX',
'userId' => 'XXX',
'password' => 'XXX',
'shipperNumber' => 'XXX',
'prod' => false,
'requestAdapter' => new StubUPS(),
]);
}
protected function getFedexAdapter()
{
return new Fedex\Rate([
'prod' => false,
'key' => 'XXX',
'password' => 'XXX',
'accountNumber' => 'XXX',
'meterNumber' => 'XXX',
'dropOffType' => 'BUSINESS_SERVICE_CENTER',
'requestAdapter' => new StubFedex(),
]);
}
protected function validatePackage(Package $package, RateAdapter $adapter)
{
$shipment = new Shipment();
$shipment->setFromStateProvinceCode('CA')
->setFromPostalCode('90401')
->setFromCountryCode('US')
->setFromIsResidential(true)
->setToPostalCode('78703')
->setToCountryCode('US')
->setToIsResidential(true)
->addPackage($package);
$adapter->setShipment($shipment);
$adapter->getRates();
$this->assertEquals($shipment, $adapter->getShipment());
}
public function testNormalUSPS()
{
$this->validatePackage($this->getNormalPackage(), $this->getUSPSAdapter());
}
/**
* @expectedException \LogicException
*/
public function testNoHeightPackageUSPS()
{
$this->validatePackage($this->getNoHeightPackage(), $this->getUSPSAdapter());
}
/**
* @expectedException \LogicException
*/
public function testNoLengthPackageUSPS()
{
$this->validatePackage($this->getNoLengthPackage(), $this->getUSPSAdapter());
}
/**
* @expectedException \LogicException
*/
public function testNoWidthPackageUSPS()
{
$this->validatePackage($this->getNoWidthPackage(), $this->getUSPSAdapter());
}
/**
* @expectedException \LogicException
*/
public function testNoWeightPackageUSPS()
{
$this->validatePackage($this->getNoWeightPackage(), $this->getUSPSAdapter());
}
public function testNormalUPS()
{
$this->validatePackage($this->getNormalPackage(), $this->getUPSAdapter());
}
/**
* @expectedException \LogicException
*/
public function testNoHeightPackageUPS()
{
$this->validatePackage($this->getNoHeightPackage(), $this->getUPSAdapter());
}
/**
* @expectedException \LogicException
*/
public function testNoLengthPackageUPS()
{
$this->validatePackage($this->getNoLengthPackage(), $this->getUPSAdapter());
}
/**
* @expectedException \LogicException
*/
public function testNoWidthPackageUPS()
{
$this->validatePackage($this->getNoWidthPackage(), $this->getUPSAdapter());
}
/**
* @expectedException \LogicException
*/
public function testNoWeightPackageUPS()
{
$this->validatePackage($this->getNoWeightPackage(), $this->getUPSAdapter());
}
public function testNormalFedex()
{
$this->validatePackage($this->getNormalPackage(), $this->getFedexAdapter());
}
/**
* @expectedException \LogicException
*/
public function testNoHeightPackageFedex()
{
$this->validatePackage($this->getNoHeightPackage(), $this->getFedexAdapter());
}
/**
* @expectedException \LogicException
*/
public function testNoLengthPackageFedex()
{
$this->validatePackage($this->getNoLengthPackage(), $this->getFedexAdapter());
}
/**
* @expectedException \LogicException
*/
public function testNoWidthPackageFedex()
{
$this->validatePackage($this->getNoWidthPackage(), $this->getFedexAdapter());
}
/**
* @expectedException \LogicException
*/
public function testNoWeightPackageFedex()
{
$this->validatePackage($this->getNoWeightPackage(), $this->getFedexAdapter());
}
}

View File

@ -1,29 +0,0 @@
<?php
namespace pdt256\Shipping;
use PHPUnit\Framework\TestCase;
class PackageTest extends TestCase
{
public function testCreate()
{
$package = new Package;
$package->setWeight(5);
$package->setWidth(6);
$package->setLength(7);
$package->setHeight(8);
$this->assertEquals(5, $package->getWeight());
$this->assertEquals(5, $package->getPounds());
$this->assertEquals(0, $package->getOunces());
$this->assertEquals(6, $package->getWidth());
$this->assertEquals(7, $package->getLength());
$this->assertEquals(8, $package->getHeight());
$package->setPounds(3);
$package->setOunces(4);
$this->assertEquals(3, $package->getPounds());
$this->assertEquals(4, $package->getOunces());
$this->assertEquals(3.25, $package->getWeight());
}
}

View File

@ -1,26 +0,0 @@
<?php
namespace pdt256\Shipping;
use DateTime;
use PHPUnit\Framework\TestCase;
class QuoteTest extends TestCase
{
public function testCreate()
{
$quote = new Quote;
$quote->setCode('-code-');
$quote->setName('Test Name');
$quote->setCost(500);
$quote->setTransitTime('-transit-time-');
$quote->setDeliveryEstimate(new DateTime);
$quote->setCarrier('-carrier-');
$this->assertEquals('-code-', $quote->getCode());
$this->assertEquals('Test Name', $quote->getName());
$this->assertEquals(500, $quote->getCost());
$this->assertEquals('-transit-time-', $quote->getTransitTime());
$this->assertTrue($quote->getDeliveryEstimate() instanceof DateTime);
$this->assertEquals('-carrier-', $quote->getCarrier());
}
}

View File

@ -1,157 +1,425 @@
<?php
namespace pdt256\Shipping;
use pdt256\Shipping\Ship;
use pdt256\Shipping\USPS;
use pdt256\Shipping\UPS;
use pdt256\Shipping\Fedex;
use pdt256\Shipping\RateRequest;
use DateTime;
use PHPUnit\Framework\TestCase;
class ShipTest extends TestCase
class ShipTest extends PHPUnit_Framework_TestCase
{
/** @var Shipment */
public $shipment;
public $shipment = [
'weight' => 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,
],
];
public $shipping_options = [
'Standard Shipping' => [
'ups' => [
'03' => '1-5 business days',
],
'fedex' => [
'FEDEX_EXPRESS_SAVER' => '1-3 business days',
'FEDEX_GROUND' => '1-5 business days',
'GROUND_HOME_DELIVERY' => '1-5 business days',
],
'usps' => [
'1' => '1-3 business days',
'4' => '2-8 business days',
],
],
'Two-Day Shipping' => [
'ups' => [
'02' => '2 business days',
],
'fedex' => [
'FEDEX_2_DAY' => '2 business days',
],
],
'One-Day Shipping' => [
'ups' => [
'01' => 'next business day 10:30am',
'13' => 'next business day by 3pm',
'14' => 'next business day by 8am',
],
'fedex' => [
'STANDARD_OVERNIGHT' => 'overnight',
],
],
];
public $shipping_options = [
'Standard Shipping' => [
'ups' => [
'03' => '1-5 business days',
],
'fedex' => [
'FEDEX_EXPRESS_SAVER' => '1-3 business days',
'FEDEX_GROUND' => '1-5 business days',
'GROUND_HOME_DELIVERY' => '1-5 business days',
],
'usps' => [
'1' => '1-3 business days',
'4' => '2-8 business days',
],
],
'Two-Day Shipping' => [
'ups' => [
'02' => '2 business days',
],
'fedex' => [
'FEDEX_2_DAY' => '2 business days',
],
],
'One-Day Shipping' => [
'ups' => [
'01' => 'next business day 10:30am',
'13' => 'next business day by 3pm',
'14' => 'next business day by 8am',
],
'fedex' => [
'STANDARD_OVERNIGHT' => 'overnight',
],
],
];
public function setUp()
{
$s = new Shipment;
$s->setFromStateProvinceCode('CA')
->setFromPostalCode('90401')
->setFromCountryCode('US')
->setFromIsResidential(true)
->setToPostalCode('78703')
->setToCountryCode('US')
->setToIsResidential(true);
private function getUSPSOptions()
{
$ship = Ship::factory($this->shipping_options);
$approved_codes = $ship->get_approved_codes('usps');
$p = new Package;
$p->setWeight(3)
->setWidth(9)
->setLength(9)
->setHeight(9);
return [
'prod' => FALSE,
'username' => 'XXXX',
'password' => 'XXXX',
'shipment' => array_merge($this->shipment, [
'size' => 'LARGE',
'container' => 'RECTANGULAR',
]),
'approved_codes' => $approved_codes,
'request_adapter' => new RateRequest\StubUSPS(),
];
}
$s->addPackage($p);
private function getUPSOptions()
{
$ship = Ship::factory($this->shipping_options);
$approved_codes = $ship->get_approved_codes('ups');
$this->shipment = $s;
}
return [
'prod' => FALSE,
'access_key' => 'XXXX',
'user_id' => 'XXXX',
'password' => 'XXXX',
'shipper_number' => 'XXXX',
'shipment' => $this->shipment,
'approved_codes' => $approved_codes,
'request_adapter' => new RateRequest\StubUPS(),
];
}
private function getUSPSOptions()
{
$ship = Ship::factory($this->shipping_options);
$approvedCodes = $ship->getApprovedCodes('usps');
private function getFedexOptions()
{
$ship = Ship::factory($this->shipping_options);
$approved_codes = $ship->get_approved_codes('fedex');
return [
'prod' => false,
'username' => 'XXXX',
'password' => 'XXXX',
'shipment' => $this->shipment,
'approvedCodes' => $approvedCodes,
'requestAdapter' => new RateRequest\StubUSPS(),
];
}
return [
'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' => $approved_codes,
'request_adapter' => new RateRequest\StubFedex(),
];
}
private function getUPSOptions()
{
$ship = Ship::factory($this->shipping_options);
$approvedCodes = $ship->getApprovedCodes('ups');
public function testUSPSRate()
{
$usps = new USPS\Rate($this->getUSPSOptions());
$usps_rates = $usps->get_rates();
return [
'prod' => false,
'accessKey' => 'XXXX',
'userId' => 'XXXX',
'password' => 'XXXX',
'shipperNumber' => 'XXXX',
'shipment' => $this->shipment,
'approvedCodes' => $approvedCodes,
'requestAdapter' => new RateRequest\StubUPS(),
];
}
$this->assertEquals(json_encode([
1 => [
'code' => '4',
'name' => 'Parcel Post',
'cost' => 1001,
],
0 => [
'code' => '1',
'name' => 'Priority Mail',
'cost' => 1220,
],
]), json_encode($usps_rates));
}
private function getFedexOptions()
{
$ship = Ship::factory($this->shipping_options);
$approvedCodes = $ship->getApprovedCodes('fedex');
public function testUPSRate()
{
$ups = new UPS\Rate($this->getUPSOptions());
$ups_rates = $ups->get_rates();
return [
'prod' => false,
'key' => 'XXXX',
'password' => 'XXXX',
'accountNumber' => 'XXXX',
'meterNumber' => 'XXXX',
'dropOffType' => 'BUSINESS_SERVICE_CENTER',
'shipment' => $this->shipment,
'approvedCodes' => $approvedCodes,
'requestAdapter' => new RateRequest\StubFedex(),
];
}
$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));
}
public function testDisplayOptions()
{
$rates = [];
public function testFedexRate()
{
$fedex = new Fedex\Rate($this->getFedexOptions());
$fedex_rates = $fedex->get_rates();
$usps = new USPS\Rate($this->getUSPSOptions());
$rates['usps'] = $usps->getRates();
$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));
}
$ups = new UPS\Rate($this->getUPSOptions());
$rates['ups'] = $ups->getRates();
public function testDisplayOptions()
{
$rates = [];
$fedex = new Fedex\Rate($this->getFedexOptions());
$rates['fedex'] = $fedex->getRates();
$usps = new USPS\Rate($this->getUSPSOptions());
$rates['usps'] = $usps->get_rates();
$ship = Ship::factory($this->shipping_options);
$rates = $ship->getDisplayRates($rates);
$ups = new UPS\Rate($this->getUPSOptions());
$rates['ups'] = $ups->get_rates();
$post = new Quote('usps', '4', 'Parcel Post', 1001);
$fedex = new Fedex\Rate($this->getFedexOptions());
$rates['fedex'] = $fedex->get_rates();
$fedexTwoDay = new Quote('fedex', 'FEDEX_2_DAY', 'Fedex 2 Day', 4072);
$fedexTwoDay->setDeliveryEstimate(new DateTime('2014-09-29T20:00:00'));
$ship = Ship::factory($this->shipping_options);
$display_rates = $ship->get_display_rates($rates);
$overnight = new Quote('fedex', 'STANDARD_OVERNIGHT', 'Standard Overnight', 7834);
$overnight->setDeliveryEstimate(new DateTime('2014-09-26T20:00:00'));
$this->assertEquals(json_encode([
'Standard Shipping' => [
0 => [
'code' => '4',
'name' => 'Parcel Post',
'cost' => 1001,
'carrier' => 'usps',
],
],
'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',
],
],
'One-Day Shipping' => [
0 => [
'code' => 'STANDARD_OVERNIGHT',
'name' => 'Standard Overnight',
'cost' => 7834,
'delivery_ts' => '2014-09-26T20:00:00',
'transit_time' => NULL,
'carrier' => 'fedex',
],
],
]), json_encode($display_rates));
}
$expected = [
'Standard Shipping' => [
$post,
],
'Two-Day Shipping' => [
$fedexTwoDay,
],
'One-Day Shipping' => [
$overnight,
],
];
/**
* @expectedException Exception
*/
public function testUSPSRateMissingTo()
{
$usps_options = $this->getUSPSOptions();
unset($usps_options['shipment']['to']);
$this->assertEquals($expected, $rates);
}
$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()
// {
// $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);
// }
}

View File

@ -1,129 +0,0 @@
<?php
namespace pdt256\Shipping;
use PHPUnit\Framework\TestCase;
class ShipmentTest extends TestCase
{
public function testCreate()
{
$shipment = new Shipment;
$shipment->addPackage(new Package);
$shipment->setFromIsResidential(false);
$shipment->setFromPostalCode('90401');
$shipment->setFromCountryCode('US');
$shipment->setFromStateProvinceCode('CA');
$shipment->setToIsResidential(true);
$shipment->setToPostalCode('90210');
$shipment->setToCountryCode('US');
$this->assertTrue($shipment->getPackages()[0] instanceof Package);
$this->assertEquals(1, $shipment->packageCount());
$this->assertFalse($shipment->getFromIsResidential());
$this->assertEquals('90401', $shipment->getFromPostalCode());
$this->assertEquals('US', $shipment->getFromCountryCode());
$this->assertEquals('CA', $shipment->getFromStateProvinceCode());
$this->assertTrue($shipment->getToIsResidential());
$this->assertEquals('90210', $shipment->getToPostalCode());
$this->assertEquals('US', $shipment->getToCountryCode());
}
private function getShipment()
{
$shipment = new Shipment;
$shipment
->setFromIsResidential(false)
->setFromStateProvinceCode('IN')
->setFromPostalCode('46205')
->setFromCountryCode('US')
->setToIsResidential(true)
->setToPostalCode('20101')
->setToCountryCode('US');
$package = new Package;
$package
->setLength(12)
->setWidth(4)
->setHeight(3)
->setWeight(3);
$shipment->addPackage($package);
return $shipment;
}
public function xtestUPSStubForReadme()
{
$shipment = $this->getShipment();
$ups = new UPS\Rate([
'prod' => false,
'accessKey' => 'XXXX',
'userId' => 'XXXX',
'password' => 'XXXX',
'shipperNumber' => 'XXXX',
'shipment' => $shipment,
'approvedCodes' => [
'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
],
'requestAdapter' => new RateRequest\StubUPS(),
]);
$rates = $ups->getRates();
var_export($rates);
}
public function xtestUSPSStubForReadme()
{
$shipment = $this->getShipment();
$usps = new USPS\Rate([
'prod' => false,
'username' => 'XXXX',
'password' => 'XXXX',
'shipment' => $shipment,
'approvedCodes' => [
'1', // 1-3 business days
'4', // 2-8 business days
],
'requestAdapter' => new RateRequest\StubUSPS(),
]);
$rates = $usps->getRates();
var_export($rates);
}
public function xtestFedexStubForReadme()
{
$shipment = $this->getShipment();
$fedex = new Fedex\Rate([
'prod' => false,
'key' => 'XXXX',
'password' => 'XXXX',
'accountNumber' => 'XXXX',
'meterNumber' => 'XXXX',
'dropOffType' => 'BUSINESS_SERVICE_CENTER',
'shipment' => $shipment,
'approvedCodes' => [
'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
],
'requestAdapter' => new RateRequest\StubFedex(),
]);
$rates = $fedex->getRates();
var_export($rates);
}
}

View File

@ -1,156 +0,0 @@
<?php
namespace pdt256\Shipping\UPS;
use pdt256\Shipping\RateRequest\StubUPS;
use pdt256\Shipping\Ship;
use pdt256\Shipping\Package;
use pdt256\Shipping\Shipment;
use pdt256\Shipping\Quote;
use PHPUnit\Framework\TestCase;
class RateTest extends TestCase
{
/** @var Shipment */
protected $shipment;
protected $approvedCodes = [];
public function setUp()
{
$ship = Ship::factory([
'Standard Shipping' => [
'ups' => [
'03' => '1-5 business days',
],
],
'Two-Day Shipping' => [
'ups' => [
'02' => '2 business days',
],
],
'One-Day Shipping' => [
'ups' => [
'01' => 'next business day 10:30am',
'13' => 'next business day by 3pm',
'14' => 'next business day by 8am',
],
],
]);
$this->approvedCodes = $ship->getApprovedCodes('ups');
$package = new Package;
$package->setWeight(3)
->setWidth(9)
->setLength(9)
->setHeight(9);
$this->shipment = new Shipment;
$this->shipment->setFromStateProvinceCode('CA')
->setFromPostalCode('90401')
->setFromCountryCode('US')
->setFromIsResidential(true)
->setToPostalCode('78703')
->setToCountryCode('US')
->setToIsResidential(true)
->addPackage($package);
}
public function testMockRates()
{
$rateAdapter = new Rate([
'accessKey' => 'XXX',
'userId' => 'XXX',
'password' => 'XXX',
'shipperNumber' => 'XXX',
'prod' => false,
'shipment' => $this->shipment,
'approvedCodes' => $this->approvedCodes,
'requestAdapter' => new StubUPS,
]);
$rates = $rateAdapter->getRates();
$expected = [
new Quote('ups', '03', 'UPS Ground', 1910),
new Quote('ups', '02', 'UPS 2nd Day Air', 4923),
new Quote('ups', '13', 'UPS Next Day Air Saver', 8954),
new Quote('ups', '01', 'UPS Next Day Air', 9328),
];
$this->assertEquals($expected, $rates);
}
public function testLiveRates()
{
if (getenv('UPS_ACCESS_KEY') === false) {
$this->markTestSkipped('Live UPS credentials missing.');
}
$rateAdapter = new Rate([
'prod' => false,
'accessKey' => getenv('UPS_ACCESS_KEY'),
'userId' => getenv('UPS_USER_ID'),
'password' => getenv('UPS_PASSWORD'),
'shipperNumber' => getenv('UPS_SHIPPER_NUMBER'),
'shipment' => $this->shipment,
'approvedCodes' => $this->approvedCodes,
]);
$rates = $rateAdapter->getRates();
$this->assertTrue(count($rates) > 0);
$this->assertTrue($rates[0] instanceof Quote);
}
/**
* @expectedException \LogicException
*/
public function testMissingAccessKey()
{
$rateAdapter = new Rate([
'userId' => 'XXX',
'password' => 'XXX',
'shipperNumber' => 'XXX',
'prod' => false,
'shipment' => $this->shipment,
'approvedCodes' => $this->approvedCodes,
'requestAdapter' => new StubUPS,
]);
$rateAdapter->getRates();
}
/**
* @expectedException \LogicException
*/
public function testMissingPassword()
{
$rateAdapter = new Rate([
'accessKey' => 'XXX',
'userId' => 'XXX',
'shipperNumber' => 'XXX',
'prod' => false,
'shipment' => $this->shipment,
'approvedCodes' => $this->approvedCodes,
'requestAdapter' => new StubUPS,
]);
$rateAdapter->getRates();
}
/**
* @expectedException \LogicException
*/
public function testMissingShipperNumber()
{
$rateAdapter = new Rate([
'accessKey' => 'XXX',
'userId' => 'XXX',
'password' => 'XXX',
'prod' => false,
'shipment' => $this->shipment,
'approvedCodes' => $this->approvedCodes,
'requestAdapter' => new StubUPS,
]);
$rateAdapter->getRates();
}
}

View File

@ -1,118 +0,0 @@
<?php
namespace pdt256\Shipping\USPS;
use pdt256\Shipping\RateRequest\StubUSPS;
use pdt256\Shipping\Ship;
use pdt256\Shipping\Package;
use pdt256\Shipping\Shipment;
use pdt256\Shipping\Quote;
use PHPUnit\Framework\TestCase;
class RateTest extends TestCase
{
/** @var Shipment */
protected $shipment;
protected $approvedCodes = [];
public function setUp()
{
$ship = Ship::factory([
'Standard Shipping' => [
'usps' => [
'1' => '1-3 business days',
'4' => '2-8 business days',
],
],
]);
$this->approvedCodes = $ship->getApprovedCodes('usps');
$package = new Package;
$package->setWeight(3)
->setWidth(9)
->setLength(9)
->setHeight(9);
$this->shipment = new Shipment;
$this->shipment->setFromStateProvinceCode('CA')
->setFromPostalCode('90401')
->setFromCountryCode('US')
->setToPostalCode('78703')
->setToCountryCode('US')
->setToIsResidential(true)
->addPackage($package);
}
public function testMockRates()
{
$rateAdapter = new Rate([
'prod' => false,
'username' => 'XXXX',
'password' => 'XXXX',
'shipment' => $this->shipment,
'approvedCodes' => $this->approvedCodes,
'requestAdapter' => new StubUSPS,
]);
$rates = $rateAdapter->getRates();
$expected = [
new Quote('usps', '4', 'Parcel Post', 1001),
new Quote('usps', '1', 'Priority Mail', 1220),
];
$this->assertEquals($expected, $rates);
}
public function testLiveRates()
{
if (getenv('USPS_USERNAME') === false) {
$this->markTestSkipped('Live USPS credentials missing.');
}
$rateAdapter = new Rate([
'prod' => false,
'username' => getenv('USPS_USERNAME'),
'password' => getenv('USPS_PASSWORD'),
'shipment' => $this->shipment,
'approvedCodes' => $this->approvedCodes,
]);
$rates = $rateAdapter->getRates();
$this->assertTrue(count($rates) > 0);
$this->assertTrue($rates[0] instanceof Quote);
}
/**
* @expectedException \LogicException
*/
public function testMissingUserName()
{
$rateAdapter = new Rate([
'prod' => false,
'password' => 'XXXX',
'shipment' => $this->shipment,
'approvedCodes' => $this->approvedCodes,
'requestAdapter' => new StubUSPS,
]);
$rateAdapter->getRates();
}
/**
* @expectedException \LogicException
*/
public function testMissingPassword()
{
$rateAdapter = new Rate([
'prod' => false,
'username' => 'XXX',
'shipment' => $this->shipment,
'approvedCodes' => $this->approvedCodes,
'requestAdapter' => new StubUSPS,
]);
$rateAdapter->getRates();
}
}

View File

@ -1,26 +0,0 @@
<?php
namespace pdt256\Shipping;
use PHPUnit\Framework\TestCase;
use stdClass;
class ValidatorTest extends TestCase
{
/**
* @expectedException \LogicException
*/
public function testNull()
{
Validator::checkIfNull(null, 'null');
}
public function testNotNull()
{
Validator::checkIfNull('XXX', 'notNullValue');
Validator::checkIfNull([], 'notNullValue');
Validator::checkIfNull(new stdClass(), 'notNullValue');
Validator::checkIfNull(function () {
}, 'notNullValue');
$this->assertTrue(true);
}
}