Compare commits
50 Commits
Author | SHA1 | Date | |
---|---|---|---|
b04134946d | |||
ef5bbc91dd | |||
|
9a9fca51d5 | ||
|
4139f52d14 | ||
|
8a4a7ebbdf | ||
|
8d1cd60d1a | ||
|
2e920b5449 | ||
|
0e115da493 | ||
|
2a5050632a | ||
|
a11a122c7e | ||
|
7a89fea6f6 | ||
|
0a494a591f | ||
|
190b1d74c9 | ||
|
0aa709e251 | ||
|
d1281805ea | ||
|
6233359c57 | ||
|
71a7383b73 | ||
|
053184f493 | ||
|
ae4552b0e0 | ||
|
49321237df | ||
|
dfd9f50c8f | ||
|
535db69152 | ||
|
51a8b8e331 | ||
|
04cae3c295 | ||
|
2938be5a2d | ||
|
6d6853cbda | ||
|
10f8bde7a2 | ||
|
5dafdf17a0 | ||
|
317155b8c2 | ||
|
3fb378c35e | ||
|
eb47cbd422 | ||
|
ccf447f755 | ||
|
01ddc321ce | ||
|
f04c23cb0c | ||
|
1b763a3656 | ||
|
fe2009a7fb | ||
|
0fdd82dd76 | ||
|
bfc91cd730 | ||
|
6a62d17a59 | ||
|
66d7f46d61 | ||
|
b911e8923d | ||
|
3dbfc3e135 | ||
|
c05c14bcc1 | ||
|
64dbeee35d | ||
|
1f98232ac0 | ||
|
6d42cd1273 | ||
|
14c35aa03f | ||
|
ad3c950d6d | ||
|
a89504e722 | ||
|
9d7c8335ff |
8
.gitignore
vendored
Normal file
8
.gitignore
vendored
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
vendor
|
||||||
|
composer.lock
|
||||||
|
coverage_report
|
||||||
|
.idea/*
|
||||||
|
!.idea/runConfigurations/
|
||||||
|
.DS_Store
|
||||||
|
live_phpunit.sh
|
||||||
|
/nbproject/private/
|
6
.idea/runConfigurations/All_Unit_Tests.xml
generated
Normal file
6
.idea/runConfigurations/All_Unit_Tests.xml
generated
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
<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>
|
13
.travis.yml
Normal file
13
.travis.yml
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
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
|
@ -1,6 +1,7 @@
|
|||||||
The MIT License (MIT)
|
The MIT License (MIT)
|
||||||
|
|
||||||
Copyright (c) 2014 Jamie Isaacs <pdt256@gmail.com>
|
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
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
250
README.md
250
README.md
@ -1,43 +1,44 @@
|
|||||||
## PHP Shipping API
|
## PHP Shipping API
|
||||||
|
|
||||||
[](https://packagist.org/packages/pdt256/shipping) [](https://packagist.org/packages/pdt256/shipping) [](https://packagist.org/packages/pdt256/shipping) [](https://packagist.org/packages/pdt256/shipping)
|

|
||||||
|
[](https://travis-ci.org/pdt256/shipping)
|
||||||
|
[](https://packagist.org/packages/pdt256/shipping)
|
||||||
|
[](https://github.com/pdt256/shipping/blob/master/LICENSE.txt)
|
||||||
|
|
||||||
A shipping rate wrapper for USPS, UPS, and Fedex.
|
A shipping rate wrapper for USPS, UPS, and Fedex.
|
||||||
|
|
||||||
## Installation
|
## Introduction
|
||||||
|
|
||||||
Add the following lines to your ``composer.json`` file.
|
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.
|
||||||
|
|
||||||
```JSON
|
|
||||||
{
|
|
||||||
"require": {
|
|
||||||
"pdt256/shipping": "dev-master"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## Example
|
## Example
|
||||||
|
|
||||||
Create a shipment object:
|
Create a shipment object:
|
||||||
|
|
||||||
```php
|
```php
|
||||||
$shipment = [
|
$shipment = new Shipment;
|
||||||
'weight' => 3, // lbs
|
$shipment
|
||||||
'dimensions' => [
|
->setFromIsResidential(false)
|
||||||
'width' => 9, // inches
|
->setFromStateProvinceCode('IN')
|
||||||
'length' => 9,
|
->setFromPostalCode('46205')
|
||||||
'height' => 9,
|
->setFromCountryCode('US')
|
||||||
],
|
->setToIsResidential(true)
|
||||||
'from' => [
|
->setToPostalCode('20101')
|
||||||
'postal_code' => '90401',
|
->setToCountryCode('US');
|
||||||
'country_code' => 'US',
|
|
||||||
],
|
$package = new Package;
|
||||||
'to' => [
|
$package
|
||||||
'postal_code' => '78703',
|
->setLength(12)
|
||||||
'country_code' => 'US',
|
->setWidth(4)
|
||||||
'is_residential' => TRUE,
|
->setHeight(3)
|
||||||
],
|
->setWeight(3);
|
||||||
];
|
|
||||||
|
$shipment->addPackage($package);
|
||||||
```
|
```
|
||||||
|
|
||||||
## UPS (Stub) Example
|
## UPS (Stub) Example
|
||||||
@ -48,7 +49,7 @@ 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.
|
You can immediately use this method in your code until you get an account with UPS.
|
||||||
|
|
||||||
```php
|
```php
|
||||||
'request_adapter' => new RateRequest\StubUPS(),
|
'requestAdapter' => new RateRequest\StubUPS(),
|
||||||
```
|
```
|
||||||
|
|
||||||
```php
|
```php
|
||||||
@ -56,23 +57,23 @@ use pdt256\Shipping\UPS;
|
|||||||
use pdt256\Shipping\RateRequest;
|
use pdt256\Shipping\RateRequest;
|
||||||
|
|
||||||
$ups = new UPS\Rate([
|
$ups = new UPS\Rate([
|
||||||
'prod' => FALSE,
|
'prod' => false,
|
||||||
'access_key' => 'XXXX',
|
'accessKey' => 'XXXX',
|
||||||
'user_id' => 'XXXX',
|
'userId' => 'XXXX',
|
||||||
'password' => 'XXXX',
|
'password' => 'XXXX',
|
||||||
'shipper_number' => 'XXXX',
|
'shipperNumber' => 'XXXX',
|
||||||
'shipment' => $shipment,
|
'shipment' => $shipment,
|
||||||
'approved_codes' => [
|
'approvedCodes' => [
|
||||||
'03', // 1-5 business days
|
'03', // 1-5 business days
|
||||||
'02', // 2 business days
|
'02', // 2 business days
|
||||||
'01', // next business day 10:30am
|
'01', // next business day 10:30am
|
||||||
'13', // next business day by 3pm
|
'13', // next business day by 3pm
|
||||||
'14', // next business day by 8am
|
'14', // next business day by 8am
|
||||||
],
|
],
|
||||||
'request_adapter' => new RateRequest\StubUPS(),
|
'requestAdapter' => new RateRequest\StubUPS(),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$ups_rates = $ups->get_rates();
|
$rates = $ups->getRates();
|
||||||
```
|
```
|
||||||
|
|
||||||
Output array sorted by cost: (in cents)
|
Output array sorted by cost: (in cents)
|
||||||
@ -80,29 +81,41 @@ Output array sorted by cost: (in cents)
|
|||||||
```php
|
```php
|
||||||
array (
|
array (
|
||||||
0 =>
|
0 =>
|
||||||
array (
|
pdt256\Shipping\Quote::__set_state(array(
|
||||||
'code' => '03',
|
'code' => '03',
|
||||||
'name' => 'UPS Ground',
|
'name' => 'UPS Ground',
|
||||||
'cost' => 1900,
|
'cost' => 1910,
|
||||||
),
|
'transitTime' => NULL,
|
||||||
|
'deliveryEstimate' => NULL,
|
||||||
|
'carrier' => 'ups',
|
||||||
|
)),
|
||||||
1 =>
|
1 =>
|
||||||
array (
|
pdt256\Shipping\Quote::__set_state(array(
|
||||||
'code' => '02',
|
'code' => '02',
|
||||||
'name' => 'UPS 2nd Day Air',
|
'name' => 'UPS 2nd Day Air',
|
||||||
'cost' => 4900,
|
'cost' => 4923,
|
||||||
),
|
'transitTime' => NULL,
|
||||||
|
'deliveryEstimate' => NULL,
|
||||||
|
'carrier' => 'ups',
|
||||||
|
)),
|
||||||
2 =>
|
2 =>
|
||||||
array (
|
pdt256\Shipping\Quote::__set_state(array(
|
||||||
'code' => '13',
|
'code' => '13',
|
||||||
'name' => 'UPS Next Day Air Saver',
|
'name' => 'UPS Next Day Air Saver',
|
||||||
'cost' => 8900,
|
'cost' => 8954,
|
||||||
),
|
'transitTime' => NULL,
|
||||||
|
'deliveryEstimate' => NULL,
|
||||||
|
'carrier' => 'ups',
|
||||||
|
)),
|
||||||
3 =>
|
3 =>
|
||||||
array (
|
pdt256\Shipping\Quote::__set_state(array(
|
||||||
'code' => '01',
|
'code' => '01',
|
||||||
'name' => 'UPS Next Day Air',
|
'name' => 'UPS Next Day Air',
|
||||||
'cost' => 9300,
|
'cost' => 9328,
|
||||||
),
|
'transitTime' => NULL,
|
||||||
|
'deliveryEstimate' => NULL,
|
||||||
|
'carrier' => 'ups',
|
||||||
|
)),
|
||||||
)
|
)
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -113,39 +126,42 @@ use pdt256\Shipping\USPS;
|
|||||||
use pdt256\Shipping\RateRequest;
|
use pdt256\Shipping\RateRequest;
|
||||||
|
|
||||||
$usps = new USPS\Rate([
|
$usps = new USPS\Rate([
|
||||||
'prod' => FALSE,
|
'prod' => false,
|
||||||
'username' => 'XXXX',
|
'username' => 'XXXX',
|
||||||
'password' => 'XXXX',
|
'password' => 'XXXX',
|
||||||
'shipment' => array_merge($shipment, [
|
'shipment' => $shipment,
|
||||||
'size' => 'LARGE',
|
'approvedCodes' => [
|
||||||
'container' => 'RECTANGULAR',
|
|
||||||
]),
|
|
||||||
'approved_codes' => [
|
|
||||||
'1', // 1-3 business days
|
'1', // 1-3 business days
|
||||||
'4', // 2-8 business days
|
'4', // 2-8 business days
|
||||||
],
|
],
|
||||||
'request_adapter' => new RateRequest\StubUSPS(),
|
'requestAdapter' => new RateRequest\StubUSPS(),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$usps_rates = $usps->get_rates();
|
$rates = $usps->getRates();
|
||||||
```
|
```
|
||||||
|
|
||||||
Output array sorted by cost: (in cents)
|
Output array sorted by cost: (in cents)
|
||||||
|
|
||||||
```php
|
```php
|
||||||
array (
|
array (
|
||||||
1 =>
|
0 =>
|
||||||
array (
|
pdt256\Shipping\Quote::__set_state(array(
|
||||||
'code' => '4',
|
'code' => '4',
|
||||||
'name' => 'Parcel Post',
|
'name' => 'Parcel Post',
|
||||||
'cost' => 1000,
|
'cost' => 1001,
|
||||||
),
|
'transitTime' => NULL,
|
||||||
0 =>
|
'deliveryEstimate' => NULL,
|
||||||
array (
|
'carrier' => 'usps',
|
||||||
|
)),
|
||||||
|
1 =>
|
||||||
|
pdt256\Shipping\Quote::__set_state(array(
|
||||||
'code' => '1',
|
'code' => '1',
|
||||||
'name' => 'Priority Mail',
|
'name' => 'Priority Mail',
|
||||||
'cost' => 1200,
|
'cost' => 1220,
|
||||||
),
|
'transitTime' => NULL,
|
||||||
|
'deliveryEstimate' => NULL,
|
||||||
|
'carrier' => 'usps',
|
||||||
|
)),
|
||||||
)
|
)
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -159,64 +175,106 @@ $fedex = new Fedex\Rate([
|
|||||||
'prod' => FALSE,
|
'prod' => FALSE,
|
||||||
'key' => 'XXXX',
|
'key' => 'XXXX',
|
||||||
'password' => 'XXXX',
|
'password' => 'XXXX',
|
||||||
'account_number' => 'XXXX',
|
'accountNumber' => 'XXXX',
|
||||||
'meter_number' => 'XXXX',
|
'meterNumber' => 'XXXX',
|
||||||
'drop_off_type' => 'BUSINESS_SERVICE_CENTER',
|
'dropOffType' => 'BUSINESS_SERVICE_CENTER',
|
||||||
'shipment' => array_merge($shipment, [
|
'shipment' => $shipment,
|
||||||
'packaging_type' => 'YOUR_PACKAGING',
|
'approvedCodes' => [
|
||||||
]),
|
|
||||||
'approved_codes' => [
|
|
||||||
'FEDEX_EXPRESS_SAVER', // 1-3 business days
|
'FEDEX_EXPRESS_SAVER', // 1-3 business days
|
||||||
'FEDEX_GROUND', // 1-5 business days
|
'FEDEX_GROUND', // 1-5 business days
|
||||||
'GROUND_HOME_DELIVERY', // 1-5 business days
|
'GROUND_HOME_DELIVERY', // 1-5 business days
|
||||||
'FEDEX_2_DAY', // 2 business days
|
'FEDEX_2_DAY', // 2 business days
|
||||||
'STANDARD_OVERNIGHT', // overnight
|
'STANDARD_OVERNIGHT', // overnight
|
||||||
],
|
],
|
||||||
'request_adapter' => new RateRequest\StubFedex(),
|
'requestAdapter' => new RateRequest\StubFedex(),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$fedex_rates = $fedex->get_rates();
|
$rates = $fedex->getRates();
|
||||||
```
|
```
|
||||||
|
|
||||||
Output array sorted by cost: (in cents)
|
Output array sorted by cost: (in cents)
|
||||||
|
|
||||||
```php
|
```php
|
||||||
array (
|
array (
|
||||||
3 =>
|
0 =>
|
||||||
array (
|
pdt256\Shipping\Quote::__set_state(array(
|
||||||
'code' => 'GROUND_HOME_DELIVERY',
|
'code' => 'GROUND_HOME_DELIVERY',
|
||||||
'name' => 'Ground Home Delivery',
|
'name' => 'Ground Home Delivery',
|
||||||
'cost' => 1600,
|
'cost' => 1655,
|
||||||
'delivery_ts' => NULL,
|
'transitTime' => 'THREE_DAYS',
|
||||||
'transit_time' => 'THREE_DAYS',
|
'deliveryEstimate' => NULL,
|
||||||
),
|
'carrier' => 'fedex',
|
||||||
2 =>
|
)),
|
||||||
array (
|
1 =>
|
||||||
|
pdt256\Shipping\Quote::__set_state(array(
|
||||||
'code' => 'FEDEX_EXPRESS_SAVER',
|
'code' => 'FEDEX_EXPRESS_SAVER',
|
||||||
'name' => 'Fedex Express Saver',
|
'name' => 'Fedex Express Saver',
|
||||||
'cost' => 2900,
|
'cost' => 2989,
|
||||||
'delivery_ts' => '2014-09-30T20:00:00',
|
'transitTime' => NULL,
|
||||||
'transit_time' => NULL,
|
'deliveryEstimate' =>
|
||||||
),
|
DateTime::__set_state(array(
|
||||||
1 =>
|
'date' => '2014-09-30 20:00:00',
|
||||||
array (
|
'timezone_type' => 3,
|
||||||
|
'timezone' => 'UTC',
|
||||||
|
)),
|
||||||
|
'carrier' => 'fedex',
|
||||||
|
)),
|
||||||
|
2 =>
|
||||||
|
pdt256\Shipping\Quote::__set_state(array(
|
||||||
'code' => 'FEDEX_2_DAY',
|
'code' => 'FEDEX_2_DAY',
|
||||||
'name' => 'Fedex 2 Day',
|
'name' => 'Fedex 2 Day',
|
||||||
'cost' => 4000,
|
'cost' => 4072,
|
||||||
'delivery_ts' => '2014-09-29T20:00:00',
|
'transitTime' => NULL,
|
||||||
'transit_time' => NULL,
|
'deliveryEstimate' =>
|
||||||
),
|
DateTime::__set_state(array(
|
||||||
0 =>
|
'date' => '2014-09-29 20:00:00',
|
||||||
array (
|
'timezone_type' => 3,
|
||||||
|
'timezone' => 'UTC',
|
||||||
|
)),
|
||||||
|
'carrier' => 'fedex',
|
||||||
|
)),
|
||||||
|
3 =>
|
||||||
|
pdt256\Shipping\Quote::__set_state(array(
|
||||||
'code' => 'STANDARD_OVERNIGHT',
|
'code' => 'STANDARD_OVERNIGHT',
|
||||||
'name' => 'Standard Overnight',
|
'name' => 'Standard Overnight',
|
||||||
'cost' => 7800,
|
'cost' => 7834,
|
||||||
'delivery_ts' => '2014-09-26T20:00:00',
|
'transitTime' => NULL,
|
||||||
'transit_time' => NULL,
|
'deliveryEstimate' =>
|
||||||
),
|
DateTime::__set_state(array(
|
||||||
|
'date' => '2014-09-26 20:00:00',
|
||||||
|
'timezone_type' => 3,
|
||||||
|
'timezone' => 'UTC',
|
||||||
|
)),
|
||||||
|
'carrier' => 'fedex',
|
||||||
|
)),
|
||||||
)
|
)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## 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
|
### License
|
||||||
|
|
||||||
The MIT License (MIT)
|
The MIT License (MIT)
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"name": "pdt256/shipping",
|
"name": "netsyms/shippingrates",
|
||||||
"description": "Shipping Rate API",
|
"description": "Shipping Rate API",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"keywords": ["ship", "ups", "usps", "fedex"],
|
"keywords": ["ship", "ups", "usps", "fedex"],
|
||||||
@ -7,11 +7,23 @@
|
|||||||
{
|
{
|
||||||
"name": "Jamie Isaacs",
|
"name": "Jamie Isaacs",
|
||||||
"email": "pdt256@gmail.com"
|
"email": "pdt256@gmail.com"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Netsyms Technologies",
|
||||||
|
"email": "opensource@netsyms.com"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"require": {},
|
"extra": {
|
||||||
|
"branch-alias": {
|
||||||
|
"dev-master": "1.0.x-dev"
|
||||||
|
}
|
||||||
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"phpunit/phpunit": "4.0.*"
|
"phpunit/phpunit": "7.0.*",
|
||||||
|
"squizlabs/php_codesniffer": "3.5.*"
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"php": ">=7.1"
|
||||||
},
|
},
|
||||||
"autoload": {
|
"autoload": {
|
||||||
"psr-4": {
|
"psr-4": {
|
||||||
|
16
live_phpunit.sh.example
Executable file
16
live_phpunit.sh.example
Executable file
@ -0,0 +1,16 @@
|
|||||||
|
#!/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
|
22
nbproject/project.properties
Normal file
22
nbproject/project.properties
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
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=.
|
9
nbproject/project.xml
Normal file
9
nbproject/project.xml
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
<?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>
|
@ -14,4 +14,9 @@
|
|||||||
<directory suffix=".php">./tests</directory>
|
<directory suffix=".php">./tests</directory>
|
||||||
</testsuite>
|
</testsuite>
|
||||||
</testsuites>
|
</testsuites>
|
||||||
|
<filter>
|
||||||
|
<whitelist>
|
||||||
|
<directory>./src</directory>
|
||||||
|
</whitelist>
|
||||||
|
</filter>
|
||||||
</phpunit>
|
</phpunit>
|
||||||
|
@ -3,7 +3,7 @@ namespace pdt256\Shipping;
|
|||||||
|
|
||||||
class Arr
|
class Arr
|
||||||
{
|
{
|
||||||
public static function get($array, $key, $default = NULL)
|
public static function get($array, $key, $default = null)
|
||||||
{
|
{
|
||||||
return isset($array[$key]) ? $array[$key] : $default;
|
return isset($array[$key]) ? $array[$key] : $default;
|
||||||
}
|
}
|
||||||
|
@ -1,33 +1,35 @@
|
|||||||
<?php
|
<?php
|
||||||
namespace pdt256\Shipping\Fedex;
|
namespace pdt256\Shipping\Fedex;
|
||||||
|
|
||||||
|
use DateTime;
|
||||||
use pdt256\Shipping;
|
use pdt256\Shipping;
|
||||||
use pdt256\Shipping\Arr;
|
use pdt256\Shipping\Arr;
|
||||||
|
use pdt256\Shipping\Quote;
|
||||||
use pdt256\Shipping\RateAdapter;
|
use pdt256\Shipping\RateAdapter;
|
||||||
use pdt256\Shipping\RateRequest;
|
use pdt256\Shipping\RateRequest;
|
||||||
|
use pdt256\Shipping\Validator;
|
||||||
use DOMDocument;
|
use DOMDocument;
|
||||||
use Exception;
|
use Exception;
|
||||||
|
|
||||||
class Rate extends RateAdapter
|
class Rate extends RateAdapter
|
||||||
{
|
{
|
||||||
private $url_dev = 'https://gatewaybeta.fedex.com/web-services/';
|
private $urlDev = 'https://gatewaybeta.fedex.com/web-services/';
|
||||||
private $url_prod = 'https://gateway.fedex.com/web-services/';
|
private $urlProd = 'https://gateway.fedex.com/web-services/';
|
||||||
|
|
||||||
private $key = 'XXX';
|
private $key;
|
||||||
private $password = 'XXX';
|
private $password;
|
||||||
private $account_number = 'XXX';
|
private $accountNumber;
|
||||||
private $meter_number = 'XXX';
|
private $meterNumber;
|
||||||
private $drop_off_type = 'BUSINESS_SERVICE_CENTER';
|
/**
|
||||||
|
* 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;
|
||||||
|
|
||||||
public $approved_codes = [
|
private $shippingCodes = [
|
||||||
'PRIORITY_OVERNIGHT',
|
|
||||||
'FEDEX_2_DAY',
|
|
||||||
'FEDEX_EXPRESS_SAVER',
|
|
||||||
'FEDEX_GROUND',
|
|
||||||
'GROUND_HOME_DELIVERY',
|
|
||||||
];
|
|
||||||
|
|
||||||
private $shipping_codes = [
|
|
||||||
'EUROPE_FIRST_INTERNATIONAL_PRIORITY' => 'Europe First International Priority',
|
'EUROPE_FIRST_INTERNATIONAL_PRIORITY' => 'Europe First International Priority',
|
||||||
'FEDEX_1_DAY_FREIGHT' => 'Fedex 1 Day Freight',
|
'FEDEX_1_DAY_FREIGHT' => 'Fedex 1 Day Freight',
|
||||||
'FEDEX_2_DAY' => 'Fedex 2 Day',
|
'FEDEX_2_DAY' => 'Fedex 2 Day',
|
||||||
@ -55,50 +57,39 @@ class Rate extends RateAdapter
|
|||||||
{
|
{
|
||||||
parent::__construct($options);
|
parent::__construct($options);
|
||||||
|
|
||||||
if (isset($options['key'])) {
|
$this->key = Arr::get($options, 'key');
|
||||||
$this->key = $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');
|
||||||
|
|
||||||
if (isset($options['password'])) {
|
$this->setRequestAdapter(Arr::get($options, 'requestAdapter', new RateRequest\Post()));
|
||||||
$this->password = $options['password'];
|
|
||||||
}
|
}
|
||||||
|
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['account_number'])) {
|
return $this;
|
||||||
$this->account_number = $options['account_number'];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isset($options['meter_number'])) {
|
|
||||||
$this->meter_number = $options['meter_number'];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isset($options['approved_codes'])) {
|
|
||||||
$this->approved_codes = $options['approved_codes'];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isset($options['drop_off_type'])) {
|
|
||||||
$this->drop_off_type = $options['drop_off_type'];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isset($options['request_adapter'])) {
|
|
||||||
$this->set_request_adapter($options['request_adapter']);
|
|
||||||
} else {
|
|
||||||
$this->set_request_adapter(new RateRequest\Post());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function prepare()
|
protected function prepare()
|
||||||
{
|
{
|
||||||
$to = Arr::get($this->shipment, 'to');
|
|
||||||
$shipper = Arr::get($this->shipment, 'from');
|
|
||||||
$dimensions = Arr::get($this->shipment, 'dimensions');
|
|
||||||
|
|
||||||
$pounds = (int) Arr::get($this->shipment, 'weight');
|
|
||||||
$ounces = 0;
|
|
||||||
|
|
||||||
if ($pounds < 1) {
|
|
||||||
throw new Exception('Weight missing');
|
|
||||||
}
|
|
||||||
|
|
||||||
$date = time();
|
$date = time();
|
||||||
$day_name = date('l', $date);
|
$day_name = date('l', $date);
|
||||||
|
|
||||||
@ -109,81 +100,98 @@ class Rate extends RateAdapter
|
|||||||
}
|
}
|
||||||
|
|
||||||
// http://www.fedex.com/templates/components/apps/wpor/secure/downloads/pdf/Aug13/PropDevGuide.pdf
|
// 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
|
// http://www.fedex.com/us/developer/product/WebServices/MyWebHelp_August2010/Content/
|
||||||
|
// Proprietary_Developer_Guide/Rate_Services_conditionalized.htm
|
||||||
|
|
||||||
$this->data =
|
$packages = '';
|
||||||
'<?xml version="1.0"?>
|
$sequence_number = 0;
|
||||||
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns="http://fedex.com/ws/rate/v13">
|
foreach ($this->shipment->getPackages() as $package) {
|
||||||
<SOAP-ENV:Body>
|
$sequence_number++;
|
||||||
<RateRequest>
|
|
||||||
<WebAuthenticationDetail>
|
$packages .=
|
||||||
<UserCredential>
|
'<RequestedPackageLineItems>' .
|
||||||
<Key>' . $this->key . '</Key>
|
'<SequenceNumber>' . $sequence_number . '</SequenceNumber>' .
|
||||||
<Password>' . $this->password . '</Password>
|
'<GroupPackageCount>1</GroupPackageCount>' .
|
||||||
</UserCredential>
|
'<Weight>' .
|
||||||
</WebAuthenticationDetail>
|
'<Units>LB</Units>' .
|
||||||
<ClientDetail>
|
'<Value>' . $package->getWeight() . '</Value>' .
|
||||||
<AccountNumber>' . $this->account_number . '</AccountNumber>
|
'</Weight>' .
|
||||||
<MeterNumber>' . $this->meter_number . '</MeterNumber>
|
'<Dimensions>' .
|
||||||
</ClientDetail>
|
'<Length>' . $package->getLength() . '</Length>' .
|
||||||
<Version>
|
'<Width>' . $package->getWidth() . '</Width>' .
|
||||||
<ServiceId>crs</ServiceId>
|
'<Height>' . $package->getHeight() . '</Height>' .
|
||||||
<Major>13</Major>
|
'<Units>IN</Units>' .
|
||||||
<Intermediate>0</Intermediate>
|
'</Dimensions>' .
|
||||||
<Minor>0</Minor>
|
'</RequestedPackageLineItems>';
|
||||||
</Version>
|
}
|
||||||
<ReturnTransitAndCommit>true</ReturnTransitAndCommit>
|
$this->data = '<?xml version="1.0"?>' .
|
||||||
<RequestedShipment>
|
'<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" ' .
|
||||||
<ShipTimestamp>' . date('c') . '</ShipTimestamp>
|
'xmlns="http://fedex.com/ws/rate/v13">' .
|
||||||
<DropoffType>' . $this->drop_off_type . '</DropoffType>
|
'<SOAP-ENV:Body>' .
|
||||||
<PackagingType>' . Arr::get($this->shipment, 'packaging_type') . '</PackagingType>
|
'<RateRequest>' .
|
||||||
<Shipper>
|
'<WebAuthenticationDetail>' .
|
||||||
<Address>
|
'<UserCredential>' .
|
||||||
<PostalCode>' . Arr::get($shipper, 'postal_code') . '</PostalCode>
|
'<Key>' . $this->key . '</Key>' .
|
||||||
<CountryCode>' . Arr::get($shipper, 'country_code') . '</CountryCode>
|
'<Password>' . $this->password . '</Password>' .
|
||||||
' . ((Arr::get($shipper, 'is_residential')) ? '<Residential>1</Residential>' : '') . '
|
'</UserCredential>' .
|
||||||
</Address>
|
'</WebAuthenticationDetail>' .
|
||||||
</Shipper>
|
'<ClientDetail>' .
|
||||||
<Recipient>
|
'<AccountNumber>' . $this->accountNumber . '</AccountNumber>' .
|
||||||
<Address>
|
'<MeterNumber>' . $this->meterNumber . '</MeterNumber>' .
|
||||||
<PostalCode>' . Arr::get($to, 'postal_code') . '</PostalCode>
|
'</ClientDetail>' .
|
||||||
<CountryCode>' . Arr::get($to, 'country_code') . '</CountryCode>
|
'<Version>' .
|
||||||
' . ((Arr::get($to, 'is_residential')) ? '<Residential>1</Residential>' : '') . '
|
'<ServiceId>crs</ServiceId>' .
|
||||||
</Address>
|
'<Major>13</Major>' .
|
||||||
</Recipient>
|
'<Intermediate>0</Intermediate>' .
|
||||||
<RateRequestTypes>LIST</RateRequestTypes>
|
'<Minor>0</Minor>' .
|
||||||
<PackageCount>1</PackageCount>
|
'</Version>' .
|
||||||
<RequestedPackageLineItems>
|
'<ReturnTransitAndCommit>true</ReturnTransitAndCommit>' .
|
||||||
<SequenceNumber>1</SequenceNumber>
|
'<RequestedShipment>' .
|
||||||
<GroupPackageCount>1</GroupPackageCount>
|
'<ShipTimestamp>' . date('c') . '</ShipTimestamp>' .
|
||||||
<Weight>
|
'<DropoffType>' . $this->dropOffType . '</DropoffType>' .
|
||||||
<Units>LB</Units>
|
'<PackagingType>YOUR_PACKAGING</PackagingType>' .
|
||||||
<Value>' . $pounds . '</Value>
|
'<Shipper>' .
|
||||||
</Weight>
|
'<Address>' .
|
||||||
<Dimensions>
|
'<PostalCode>' . $this->shipment->getFromPostalCode() . '</PostalCode>' .
|
||||||
<Length>' . Arr::get($dimensions, 'length') . '</Length>
|
'<CountryCode>' . $this->shipment->getFromCountryCode() . '</CountryCode>' .
|
||||||
<Width>' . Arr::get($dimensions, 'width') . '</Width>
|
(
|
||||||
<Height>' . Arr::get($dimensions, 'height') . '</Height>
|
$this->shipment->getFromIsResidential() ?
|
||||||
<Units>IN</Units>
|
'<Residential>1</Residential>' :
|
||||||
</Dimensions>
|
''
|
||||||
</RequestedPackageLineItems>
|
) .
|
||||||
</RequestedShipment>
|
'</Address>' .
|
||||||
</RateRequest>
|
'</Shipper>' .
|
||||||
</SOAP-ENV:Body>
|
'<Recipient>' .
|
||||||
</SOAP-ENV:Envelope>';
|
'<Address>' .
|
||||||
|
'<PostalCode>' . $this->shipment->getToPostalCode() . '</PostalCode>' .
|
||||||
|
'<CountryCode>' . $this->shipment->getToCountryCode() . '</CountryCode>' .
|
||||||
|
(
|
||||||
|
$this->shipment->getToIsResidential() ?
|
||||||
|
'<Residential>1</Residential>' :
|
||||||
|
''
|
||||||
|
) .
|
||||||
|
'</Address>' .
|
||||||
|
'</Recipient>' .
|
||||||
|
'<RateRequestTypes>LIST</RateRequestTypes>' .
|
||||||
|
'<PackageCount>' . $this->shipment->packageCount() . '</PackageCount>' .
|
||||||
|
$packages .
|
||||||
|
'</RequestedShipment>' .
|
||||||
|
'</RateRequest>' .
|
||||||
|
'</SOAP-ENV:Body>' .
|
||||||
|
'</SOAP-ENV:Envelope>';
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function execute()
|
protected function execute()
|
||||||
{
|
{
|
||||||
if ($this->is_prod) {
|
if ($this->isProduction) {
|
||||||
$url = $this->url_prod;
|
$url = $this->urlProd;
|
||||||
} else {
|
} else {
|
||||||
$url = $this->url_dev;
|
$url = $this->urlDev;
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->response = $this->rate_request->execute($url, $this->data);
|
$this->response = $this->rateRequest->execute($url, $this->data);
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
@ -207,11 +215,11 @@ class Rate extends RateAdapter
|
|||||||
foreach ($rate_reply as $rate) {
|
foreach ($rate_reply as $rate) {
|
||||||
$code = $rate->getElementsByTagName('ServiceType')->item(0)->nodeValue;
|
$code = $rate->getElementsByTagName('ServiceType')->item(0)->nodeValue;
|
||||||
|
|
||||||
if ( ! empty($this->approved_codes) AND ! in_array($code, $this->approved_codes)) {
|
if (! empty($this->approvedCodes) && ! in_array($code, $this->approvedCodes)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
$name = Arr::get($this->shipping_codes, $code);
|
$name = Arr::get($this->shippingCodes, $code);
|
||||||
|
|
||||||
$delivery_ts = @$rate->getElementsByTagName('DeliveryTimestamp')->item(0)->nodeValue;
|
$delivery_ts = @$rate->getElementsByTagName('DeliveryTimestamp')->item(0)->nodeValue;
|
||||||
$transit_time = @$rate->getElementsByTagName('TransitTime')->item(0)->nodeValue;
|
$transit_time = @$rate->getElementsByTagName('TransitTime')->item(0)->nodeValue;
|
||||||
@ -222,13 +230,18 @@ class Rate extends RateAdapter
|
|||||||
->getElementsByTagName('TotalNetCharge')->item(0)
|
->getElementsByTagName('TotalNetCharge')->item(0)
|
||||||
->getElementsByTagName('Amount')->item(0)->nodeValue;
|
->getElementsByTagName('Amount')->item(0)->nodeValue;
|
||||||
|
|
||||||
$this->rates[] = array(
|
$quote = new Quote;
|
||||||
'code' => $code,
|
$quote
|
||||||
'name' => $name,
|
->setCarrier('fedex')
|
||||||
'cost' => (int) ($cost * 100),
|
->setCode($code)
|
||||||
'delivery_ts' => $delivery_ts,
|
->setName($name)
|
||||||
'transit_time' => $transit_time,
|
->setCost((int) ($cost * 100))
|
||||||
);
|
->setTransitTime($transit_time);
|
||||||
|
if ($delivery_ts) {
|
||||||
|
$quote->setDeliveryEstimate(new DateTime($delivery_ts));
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->rates[] = $quote;
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
|
105
src/Package.php
Normal file
105
src/Package.php
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
<?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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
131
src/Quote.php
Normal file
131
src/Quote.php
Normal file
@ -0,0 +1,131 @@
|
|||||||
|
<?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;
|
||||||
|
}
|
||||||
|
}
|
@ -1,64 +1,108 @@
|
|||||||
<?php
|
<?php
|
||||||
namespace pdt256\Shipping;
|
namespace pdt256\Shipping;
|
||||||
|
|
||||||
use Exception;
|
|
||||||
|
|
||||||
abstract class RateAdapter
|
abstract class RateAdapter
|
||||||
{
|
{
|
||||||
protected $is_prod = FALSE;
|
protected $isProduction;
|
||||||
|
|
||||||
|
/** @var Shipment */
|
||||||
protected $shipment;
|
protected $shipment;
|
||||||
protected $data;
|
protected $data;
|
||||||
protected $response;
|
protected $response;
|
||||||
protected $rates = [];
|
protected $rates;
|
||||||
|
|
||||||
protected $rate_request;
|
/** @var @var RateRequest\Adapter */
|
||||||
|
protected $rateRequest;
|
||||||
|
|
||||||
abstract protected function prepare(); // Prepare XML
|
/**
|
||||||
abstract protected function execute(); // Curl Request
|
* Make sure all necessary fields are set
|
||||||
abstract protected function process(); // Convert to shipping rates array
|
* @return self
|
||||||
|
*/
|
||||||
|
abstract protected function validate();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prepare XML
|
||||||
|
* @return self
|
||||||
|
*/
|
||||||
|
abstract protected function prepare();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Curl Request
|
||||||
|
* @return self
|
||||||
|
*/
|
||||||
|
abstract protected function execute();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert to shipping rates array
|
||||||
|
* @return self
|
||||||
|
*/
|
||||||
|
abstract protected function process();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @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 = [])
|
public function __construct($options = [])
|
||||||
{
|
{
|
||||||
if (isset($options['prod'])) {
|
$this->rates = [];
|
||||||
$this->is_prod = (bool) $options['prod'];
|
|
||||||
|
$this->isProduction = (bool) Arr::get($options, 'prod', false);
|
||||||
|
$this->shipment = Arr::get($options, 'shipment');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isset($options['shipment'])) {
|
public function setRequestAdapter(RateRequest\Adapter $rateRequest)
|
||||||
$this->shipment = $options['shipment'];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (empty($this->shipment['to'])) {
|
|
||||||
throw new Exception('Shipment "to" missing');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (empty($this->shipment['from'])) {
|
|
||||||
throw new Exception('Shipment "from" missing');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (empty($this->shipment['dimensions'])) {
|
|
||||||
throw new Exception('Shipment "dimensions" missing');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public function set_request_adapter(RateRequest\Adapter $rate_request)
|
|
||||||
{
|
{
|
||||||
$this->rate_request = $rate_request;
|
$this->rateRequest = $rateRequest;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function get_rates()
|
public function setShipment($shipment)
|
||||||
|
{
|
||||||
|
$this->shipment = $shipment;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getShipment()
|
||||||
|
{
|
||||||
|
return $this->shipment;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setIsProduction($isProduction): void
|
||||||
|
{
|
||||||
|
$this->isProduction = $isProduction;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getIsProduction(): bool
|
||||||
|
{
|
||||||
|
return $this->isProduction;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Quote[]
|
||||||
|
*/
|
||||||
|
public function getRates(): array
|
||||||
{
|
{
|
||||||
$this
|
$this
|
||||||
|
->validate()
|
||||||
->prepare()
|
->prepare()
|
||||||
->execute()
|
->execute()
|
||||||
->process()
|
->process()
|
||||||
->sort_by_cost();
|
->sortByCost();
|
||||||
|
|
||||||
return $this->rates;
|
return array_values($this->rates);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function sort_by_cost()
|
protected function sortByCost(): void
|
||||||
{
|
{
|
||||||
uasort($this->rates, create_function('$a, $b', 'return ($a["cost"] > $b["cost"]);'));
|
uasort($this->rates, static function (Quote $a, Quote $b) {
|
||||||
|
return ($a->getCost() > $b->getCost());
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,8 +3,8 @@ namespace pdt256\Shipping\RateRequest;
|
|||||||
|
|
||||||
abstract class Adapter
|
abstract class Adapter
|
||||||
{
|
{
|
||||||
protected $curl_connect_timeout_ms = 1000; // milliseconds
|
protected $curlConnectTimeoutInMilliseconds = 1500;
|
||||||
protected $curl_dl_timeout = 11; // seconds
|
protected $curlDownloadTimeoutInSeconds = 50;
|
||||||
|
|
||||||
abstract public function execute($url, $data = NULL);
|
abstract public function execute($url, $data = null);
|
||||||
}
|
}
|
||||||
|
3440
src/RateRequest/FedexResponse.xml
Normal file
3440
src/RateRequest/FedexResponse.xml
Normal file
File diff suppressed because it is too large
Load Diff
@ -3,20 +3,25 @@ namespace pdt256\Shipping\RateRequest;
|
|||||||
|
|
||||||
class Get extends Adapter
|
class Get extends Adapter
|
||||||
{
|
{
|
||||||
public function execute($url, $data = NULL)
|
public function execute($url, $data = null)
|
||||||
{
|
{
|
||||||
$ch = curl_init();
|
$ch = curl_init();
|
||||||
curl_setopt($ch, CURLOPT_URL, $url);
|
curl_setopt($ch, CURLOPT_URL, $url);
|
||||||
curl_setopt($ch, CURLOPT_HEADER, FALSE);
|
curl_setopt($ch, CURLOPT_HEADER, false);
|
||||||
curl_setopt($ch, CURLOPT_HTTPGET, TRUE);
|
curl_setopt($ch, CURLOPT_HTTPGET, true);
|
||||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
|
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||||
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
|
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
|
||||||
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
|
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
|
||||||
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT_MS, $this->curl_connect_timeout_ms);
|
//curl_setopt($ch, CURLOPT_SSL_CIPHER_LIST, 'TLSv1');
|
||||||
curl_setopt($ch, CURLOPT_TIMEOUT, $this->curl_dl_timeout);
|
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT_MS, $this->curlConnectTimeoutInMilliseconds);
|
||||||
|
curl_setopt($ch, CURLOPT_TIMEOUT, $this->curlDownloadTimeoutInSeconds);
|
||||||
$response = curl_exec($ch);
|
$response = curl_exec($ch);
|
||||||
|
if ($response === false) {
|
||||||
|
$error = curl_error($ch);
|
||||||
|
curl_close($ch);
|
||||||
|
throw new RequestException($error);
|
||||||
|
}
|
||||||
curl_close($ch);
|
curl_close($ch);
|
||||||
|
|
||||||
return $response;
|
return $response;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,19 +3,23 @@ namespace pdt256\Shipping\RateRequest;
|
|||||||
|
|
||||||
class Post extends Adapter
|
class Post extends Adapter
|
||||||
{
|
{
|
||||||
public function execute($url, $data = NULL)
|
public function execute($url, $data = null)
|
||||||
{
|
{
|
||||||
$ch = curl_init();
|
$ch = curl_init();
|
||||||
curl_setopt($ch, CURLOPT_URL, $url);
|
curl_setopt($ch, CURLOPT_URL, $url);
|
||||||
curl_setopt($ch, CURLOPT_HEADER, FALSE);
|
curl_setopt($ch, CURLOPT_HEADER, false);
|
||||||
curl_setopt($ch, CURLOPT_POST, TRUE);
|
curl_setopt($ch, CURLOPT_POST, true);
|
||||||
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
|
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
|
||||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
|
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||||
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
|
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
|
||||||
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
|
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
|
||||||
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT_MS, $this->curl_connect_timeout_ms);
|
//curl_setopt($ch, CURLOPT_SSL_CIPHER_LIST, 'TLSv1');
|
||||||
curl_setopt($ch, CURLOPT_TIMEOUT, $this->curl_dl_timeout);
|
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT_MS, $this->curlConnectTimeoutInMilliseconds);
|
||||||
|
curl_setopt($ch, CURLOPT_TIMEOUT, $this->curlDownloadTimeoutInSeconds);
|
||||||
$response = curl_exec($ch);
|
$response = curl_exec($ch);
|
||||||
|
if ($response === false) {
|
||||||
|
throw new RequestException(curl_error($ch));
|
||||||
|
}
|
||||||
curl_close($ch);
|
curl_close($ch);
|
||||||
|
|
||||||
return $response;
|
return $response;
|
||||||
|
6
src/RateRequest/RequestException.php
Normal file
6
src/RateRequest/RequestException.php
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
<?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
@ -3,22 +3,19 @@ namespace pdt256\Shipping\RateRequest;
|
|||||||
|
|
||||||
class StubUSPS extends Adapter
|
class StubUSPS extends Adapter
|
||||||
{
|
{
|
||||||
private $artificial_delay = 0;
|
private $artificialDelay = 0;
|
||||||
|
|
||||||
public function __construct($artificial_delay = 0)
|
public function __construct($artificial_delay = 0)
|
||||||
{
|
{
|
||||||
$this->artificial_delay = $artificial_delay;
|
$this->artificialDelay = $artificial_delay;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function execute($url, $data = NULL)
|
public function execute($url, $data = null)
|
||||||
{
|
{
|
||||||
if ($this->artificial_delay > 0) {
|
if ($this->artificialDelay > 0) {
|
||||||
sleep($this->artificial_delay);
|
sleep($this->artificialDelay);
|
||||||
}
|
}
|
||||||
|
|
||||||
$response = '<?xml version="1.0" encoding="UTF-8"?>
|
return file_get_contents(__DIR__ . '/USPSResponse.xml');
|
||||||
<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&lt;sup&gt;&#8482;&lt;/sup&gt;</MailService><Rate>42.25</Rate></Postage><Postage CLASSID="2"><MailService>Priority Mail Express 2-Day&lt;sup&gt;&#8482;&lt;/sup&gt; Hold For Pickup</MailService><Rate>42.25</Rate></Postage><Postage CLASSID="1"><MailService>Priority Mail 2-Day&lt;sup&gt;&#8482;&lt;/sup&gt;</MailService><Rate>12.20</Rate></Postage><Postage CLASSID="4"><MailService>Standard Post&lt;sup&gt;&#174;&lt;/sup&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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
247
src/RateRequest/UPSResponse.xml
Normal file
247
src/RateRequest/UPSResponse.xml
Normal file
@ -0,0 +1,247 @@
|
|||||||
|
<?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>
|
37
src/RateRequest/USPSResponse.xml
Normal file
37
src/RateRequest/USPSResponse.xml
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
<?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&lt;sup&gt;&#8482;&lt;/sup&gt;</MailService>
|
||||||
|
<Rate>42.25</Rate>
|
||||||
|
</Postage>
|
||||||
|
<Postage CLASSID="2">
|
||||||
|
<MailService>Priority Mail Express 2-Day&lt;sup&gt;&#8482;&lt;/sup&gt; Hold For Pickup
|
||||||
|
</MailService>
|
||||||
|
<Rate>42.25</Rate>
|
||||||
|
</Postage>
|
||||||
|
<Postage CLASSID="1">
|
||||||
|
<MailService>Priority Mail 2-Day&lt;sup&gt;&#8482;&lt;/sup&gt;</MailService>
|
||||||
|
<Rate>12.20</Rate>
|
||||||
|
</Postage>
|
||||||
|
<Postage CLASSID="4">
|
||||||
|
<MailService>Standard Post&lt;sup&gt;&#174;&lt;/sup&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>
|
53
src/Ship.php
53
src/Ship.php
@ -49,52 +49,53 @@ class Ship
|
|||||||
return $object;
|
return $object;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function get_approved_codes($carrier = NULL) {
|
/**
|
||||||
$approved_codes = [];
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getApprovedCodes($carrier = null)
|
||||||
|
{
|
||||||
|
$approvedCodes = [];
|
||||||
|
|
||||||
// Build approved_codes
|
// Build approvedCodes
|
||||||
foreach ($this->shipping_options as $shipping_group => $row) {
|
foreach ($this->shipping_options as $shipping_group => $row) {
|
||||||
|
|
||||||
foreach ($row as $_carrier => $row2) {
|
foreach ($row as $_carrier => $row2) {
|
||||||
if ( ! isset($approved_codes[$_carrier])) {
|
if (!isset($approvedCodes[$_carrier])) {
|
||||||
$approved_codes[$_carrier] = [];
|
$approvedCodes[$_carrier] = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach ($row2 as $code => $display) {
|
foreach ($row2 as $code => $display) {
|
||||||
$approved_codes[$_carrier][] = $code;
|
$approvedCodes[$_carrier][] = $code;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($carrier !== NULL AND isset($approved_codes[$carrier])) {
|
if ($carrier !== null && isset($approvedCodes[$carrier])) {
|
||||||
return $approved_codes[$carrier];
|
return $approvedCodes[$carrier];
|
||||||
}
|
}
|
||||||
|
|
||||||
return $approved_codes;
|
return $approvedCodes;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function get_display_rates($rates)
|
public function getDisplayRates($rates)
|
||||||
{
|
{
|
||||||
// Build output array with cheapest shipping option for each group
|
// Build output array with cheapest shipping option for each group
|
||||||
$display_rates = [];
|
$display_rates = [];
|
||||||
foreach ($this->shipping_options as $shipping_group => $row) {
|
foreach ($this->shipping_options as $shipping_group => $row) {
|
||||||
$display_rates[$shipping_group] = [];
|
$display_rates[$shipping_group] = [];
|
||||||
$cheapest_row = NULL;
|
$cheapest_row = null;
|
||||||
|
|
||||||
foreach ($row as $carrier => $row2) {
|
foreach ($row as $carrier => $row2) {
|
||||||
$group_codes = array_keys($row2);
|
$group_codes = array_keys($row2);
|
||||||
|
|
||||||
if (! empty($rates[$carrier])) {
|
if (! empty($rates[$carrier])) {
|
||||||
|
|
||||||
foreach ($rates[$carrier] as $row3) {
|
foreach ($rates[$carrier] as $row3) {
|
||||||
|
if (in_array($row3->getCode(), $group_codes)) {
|
||||||
|
$row3->setCarrier($carrier);
|
||||||
|
|
||||||
if (in_array($row3['code'], $group_codes)) {
|
if ($cheapest_row === null) {
|
||||||
$row3['carrier'] = $carrier;
|
|
||||||
|
|
||||||
if ($cheapest_row === NULL) {
|
|
||||||
$cheapest_row = $row3;
|
$cheapest_row = $row3;
|
||||||
} else {
|
} else {
|
||||||
if ($row3['cost'] < $cheapest_row['cost']) {
|
if ($row3->getCost() < $cheapest_row->getCost()) {
|
||||||
$cheapest_row = $row3;
|
$cheapest_row = $row3;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -112,7 +113,7 @@ class Ship
|
|||||||
return $display_rates;
|
return $display_rates;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function get_all_display_rates($rates)
|
public function getAllDisplayRates($rates)
|
||||||
{
|
{
|
||||||
// Build output array listing all group options
|
// Build output array listing all group options
|
||||||
$display_rates = [];
|
$display_rates = [];
|
||||||
@ -123,25 +124,25 @@ class Ship
|
|||||||
$group_codes = array_keys($row2);
|
$group_codes = array_keys($row2);
|
||||||
|
|
||||||
if (!empty($rates[$carrier])) {
|
if (!empty($rates[$carrier])) {
|
||||||
|
|
||||||
foreach ($rates[$carrier] as $row3) {
|
foreach ($rates[$carrier] as $row3) {
|
||||||
|
if (in_array($row3->getCode(), $group_codes)) {
|
||||||
if (in_array($row3['code'], $group_codes)) {
|
$row3->setCarrier($carrier);
|
||||||
$row3['carrier'] = $carrier;
|
|
||||||
$display_rates[$shipping_group][] = $row3;
|
$display_rates[$shipping_group][] = $row3;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->sort_by_cost($display_rates[$shipping_group]);
|
$this->sortByCost($display_rates[$shipping_group]);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $display_rates;
|
return $display_rates;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function sort_by_cost( & $rates)
|
protected function sortByCost(&$rates)
|
||||||
{
|
{
|
||||||
uasort($rates, create_function('$a, $b', 'return ($a["cost"] > $b["cost"]);'));
|
uasort($rates, function ($a, $b) {
|
||||||
|
return ($a->getCost() > $b->getCost());
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
170
src/Shipment.php
Normal file
170
src/Shipment.php
Normal file
@ -0,0 +1,170 @@
|
|||||||
|
<?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;
|
||||||
|
}
|
||||||
|
}
|
263
src/UPS/Rate.php
263
src/UPS/Rate.php
@ -1,29 +1,29 @@
|
|||||||
<?php
|
<?php
|
||||||
namespace pdt256\Shipping\UPS;
|
namespace pdt256\Shipping\UPS;
|
||||||
|
|
||||||
use pdt256\Ship;
|
|
||||||
use pdt256\Shipping\Arr;
|
use pdt256\Shipping\Arr;
|
||||||
|
use pdt256\Shipping\Quote;
|
||||||
use pdt256\Shipping\RateAdapter;
|
use pdt256\Shipping\RateAdapter;
|
||||||
use pdt256\Shipping\RateRequest;
|
use pdt256\Shipping\RateRequest;
|
||||||
|
use pdt256\Shipping\Validator;
|
||||||
use DOMDocument;
|
use DOMDocument;
|
||||||
use Exception;
|
use Exception;
|
||||||
|
|
||||||
class Rate extends RateAdapter
|
class Rate extends RateAdapter
|
||||||
{
|
{
|
||||||
private $url_dev = 'https://wwwcie.ups.com/ups.app/xml/Rate';
|
private $urlDev = 'https://wwwcie.ups.com/ups.app/xml/Rate';
|
||||||
private $url_prod = 'https://www.ups.com/ups.app/xml/Rate';
|
private $urlProd = 'https://www.ups.com/ups.app/xml/Rate';
|
||||||
|
|
||||||
private $access_key = 'XXX';
|
private $accessKey;
|
||||||
private $user_id = 'XXX';
|
private $userId;
|
||||||
private $password = 'XXX';
|
private $password;
|
||||||
private $shipper_number = 'XXX';
|
private $shipperNumber;
|
||||||
|
/**
|
||||||
|
* Codes of appropriate shipping types. Default value is specified in __construct.
|
||||||
|
*/
|
||||||
|
public $approvedCodes;
|
||||||
|
|
||||||
public $approved_codes = [
|
private $shippingCodes = [
|
||||||
'03',
|
|
||||||
'12',
|
|
||||||
];
|
|
||||||
|
|
||||||
private $shipping_codes = [
|
|
||||||
'US' => [ // United States
|
'US' => [ // United States
|
||||||
'01' => 'UPS Next Day Air',
|
'01' => 'UPS Next Day Air',
|
||||||
'02' => 'UPS 2nd Day Air',
|
'02' => 'UPS 2nd Day Air',
|
||||||
@ -85,120 +85,138 @@ class Rate extends RateAdapter
|
|||||||
{
|
{
|
||||||
parent::__construct($options);
|
parent::__construct($options);
|
||||||
|
|
||||||
if (isset($options['access_key'])) {
|
$this->accessKey = Arr::get($options, 'accessKey');
|
||||||
$this->access_key = $options['access_key'];
|
$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',
|
||||||
|
]);
|
||||||
|
|
||||||
|
$this->setRequestAdapter(Arr::get($options, 'requestAdapter', new RateRequest\Post()));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isset($options['user_id'])) {
|
protected function validate()
|
||||||
$this->user_id = $options['user_id'];
|
{
|
||||||
}
|
$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['password'])) {
|
return $this;
|
||||||
$this->password = $options['password'];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isset($options['shipper_number'])) {
|
|
||||||
$this->shipper_number = $options['shipper_number'];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isset($options['approved_codes'])) {
|
|
||||||
$this->approved_codes = $options['approved_codes'];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isset($options['request_adapter'])) {
|
|
||||||
$this->set_request_adapter($options['request_adapter']);
|
|
||||||
} else {
|
|
||||||
$this->set_request_adapter(new RateRequest\Post());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function prepare()
|
protected function prepare()
|
||||||
{
|
{
|
||||||
$to = Arr::get($this->shipment, 'to');
|
|
||||||
$shipper = Arr::get($this->shipment, 'from');
|
|
||||||
$dimensions = Arr::get($this->shipment, 'dimensions');
|
|
||||||
|
|
||||||
$pounds = (int) Arr::get($this->shipment, 'weight');
|
|
||||||
$ounces = 0;
|
|
||||||
|
|
||||||
if ($pounds < 1) {
|
|
||||||
throw new Exception('Weight missing');
|
|
||||||
}
|
|
||||||
|
|
||||||
$service_code = '03';
|
$service_code = '03';
|
||||||
|
|
||||||
$this->data =
|
$this->data = '<?xml version="1.0"?>' . "\n" .
|
||||||
'<?xml version="1.0"?>
|
'<AccessRequest xml:lang="en-US">' .
|
||||||
<AccessRequest xml:lang="en-US">
|
'<AccessLicenseNumber>' . $this->accessKey . '</AccessLicenseNumber>'.
|
||||||
<AccessLicenseNumber>' . $this->access_key . '</AccessLicenseNumber>
|
'<UserId>' . $this->userId . '</UserId>' .
|
||||||
<UserId>' . $this->user_id . '</UserId>
|
'<Password>' . $this->password . '</Password>' .
|
||||||
<Password>' . $this->password . '</Password>
|
'</AccessRequest>' .
|
||||||
</AccessRequest>
|
'<RatingServiceSelectionRequest xml:lang="en-US">' .
|
||||||
<RatingServiceSelectionRequest xml:lang="en-US">
|
'<Request>' .
|
||||||
<Request>
|
'<RequestAction>Rate</RequestAction>' .
|
||||||
<RequestAction>Rate</RequestAction>
|
'<RequestOption>shop</RequestOption>' .
|
||||||
<RequestOption>shop</RequestOption>
|
'</Request>' .
|
||||||
</Request>
|
'<Shipment>' .
|
||||||
<Shipment>
|
'<Shipper>' .
|
||||||
<Shipper>
|
'<Address>' .
|
||||||
<Address>
|
'<PostalCode>' . $this->shipment->getFromPostalCode() . '</PostalCode>' .
|
||||||
<PostalCode>' . Arr::get($shipper, 'postal_code') . '</PostalCode>
|
'<CountryCode>' . $this->shipment->getFromCountryCode() . '</CountryCode>' .
|
||||||
<CountryCode>' . Arr::get($shipper, 'country_code') . '</CountryCode>
|
(
|
||||||
' . ((Arr::get($shipper, 'is_residential')) ? '<ResidentialAddressIndicator>1</ResidentialAddressIndicator>' : '') . '
|
$this->shipment->getFromIsResidential() ?
|
||||||
</Address>
|
'<ResidentialAddressIndicator>1</ResidentialAddressIndicator>' :
|
||||||
<ShipperNumber>' . $this->shipper_number . '</ShipperNumber>
|
''
|
||||||
</Shipper>
|
) .
|
||||||
<ShipTo>
|
'</Address>' .
|
||||||
<Address>
|
'<ShipperNumber>' . $this->shipperNumber . '</ShipperNumber>' .
|
||||||
<PostalCode>' . Arr::get($to, 'postal_code') . '</PostalCode>
|
'</Shipper>' .
|
||||||
<CountryCode>' . Arr::get($to, 'country_code') . '</CountryCode>
|
'<ShipTo>' .
|
||||||
' . ((Arr::get($to, 'is_residential')) ? '<ResidentialAddressIndicator>1</ResidentialAddressIndicator>' : '') . '
|
'<Address>' .
|
||||||
</Address>
|
'<PostalCode>' . $this->shipment->getToPostalCode() . '</PostalCode>' .
|
||||||
</ShipTo>
|
'<CountryCode>' . $this->shipment->getToCountryCode() . '</CountryCode>' .
|
||||||
<ShipFrom>
|
(
|
||||||
<Address>
|
$this->shipment->getToIsResidential() ?
|
||||||
<PostalCode>' . Arr::get($shipper, 'postal_code') . '</PostalCode>
|
'<ResidentialAddressIndicator>1</ResidentialAddressIndicator>' :
|
||||||
<CountryCode>' . Arr::get($shipper, 'country_code') . '</CountryCode>
|
''
|
||||||
' . ((Arr::get($shipper, 'is_residential')) ? '<ResidentialAddressIndicator>1</ResidentialAddressIndicator>' : '') . '
|
) .
|
||||||
</Address>
|
'</Address>' .
|
||||||
</ShipFrom>
|
'</ShipTo>' .
|
||||||
<Service>
|
'<ShipFrom>' .
|
||||||
<Code>' . $service_code . '</Code>
|
'<Address>' .
|
||||||
</Service>
|
'<StateProvinceCode>' .
|
||||||
<Package>
|
$this->shipment->getFromStateProvinceCode() .
|
||||||
<PackagingType>
|
'</StateProvinceCode>' .
|
||||||
<Code>02</Code>
|
'<PostalCode>' . $this->shipment->getFromPostalCode() . '</PostalCode>' .
|
||||||
</PackagingType>
|
'<CountryCode>' . $this->shipment->getFromCountryCode() . '</CountryCode>' .
|
||||||
<Dimensions>
|
(
|
||||||
<UnitOfMeasurement>
|
$this->shipment->getFromIsResidential() ?
|
||||||
<Code>IN</Code>
|
'<ResidentialAddressIndicator>1</ResidentialAddressIndicator>' :
|
||||||
</UnitOfMeasurement>
|
''
|
||||||
<Length>' . Arr::get($dimensions, 'length') . '</Length>
|
) .
|
||||||
<Width>' . Arr::get($dimensions, 'width') . '</Width>
|
'</Address>' .
|
||||||
<Height>' . Arr::get($dimensions, 'height') . '</Height>
|
'</ShipFrom>' .
|
||||||
</Dimensions>
|
'<Service>' .
|
||||||
<PackageWeight>
|
'<Code>' . $service_code . '</Code>' .
|
||||||
<UnitOfMeasurement>
|
'</Service>' .
|
||||||
<Code>LBS</Code>
|
$this->getPackagesXmlString() .
|
||||||
</UnitOfMeasurement>
|
'<RateInformation>' .
|
||||||
<Weight>' . $pounds . '</Weight>
|
'<NegotiatedRatesIndicator/>' .
|
||||||
</PackageWeight>
|
'</RateInformation>' .
|
||||||
</Package>
|
'</Shipment>' .
|
||||||
</Shipment>
|
'</RatingServiceSelectionRequest>';
|
||||||
</RatingServiceSelectionRequest>';
|
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function execute()
|
protected function getPackagesXmlString()
|
||||||
{
|
{
|
||||||
if ($this->is_prod) {
|
$packages = '';
|
||||||
$url = $this->url_prod;
|
foreach ($this->shipment->getPackages() as $p) {
|
||||||
} else {
|
$packages .=
|
||||||
$url = $this->url_dev;
|
'<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>';
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->response = $this->rate_request->execute($url, $this->data);
|
return $packages;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function execute()
|
||||||
|
{
|
||||||
|
if ($this->isProduction) {
|
||||||
|
$url = $this->urlProd;
|
||||||
|
} else {
|
||||||
|
$url = $this->urlDev;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->response = $this->rateRequest->execute($url, $this->data);
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
@ -209,14 +227,13 @@ class Rate extends RateAdapter
|
|||||||
$dom = new DOMDocument('1.0', 'UTF-8');
|
$dom = new DOMDocument('1.0', 'UTF-8');
|
||||||
$dom->loadXml($this->response);
|
$dom->loadXml($this->response);
|
||||||
|
|
||||||
$rate_list = @$dom->getElementsByTagName('RatedShipment');
|
$rate_list = $dom->getElementsByTagName('RatedShipment');
|
||||||
|
|
||||||
if (empty($rate_list->length)) {
|
if (empty($rate_list->length)) {
|
||||||
throw new Exception('Unable to get UPS Rates.');
|
throw new Exception('Unable to get UPS Rates.');
|
||||||
}
|
}
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
// StatsD::increment('error.shipping.get_ups_rate');
|
echo $this->response;
|
||||||
// Kohana::$log->add(Log::ERROR, $e)->write();
|
|
||||||
throw $e;
|
throw $e;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -225,21 +242,23 @@ class Rate extends RateAdapter
|
|||||||
->getElementsByTagName('Service')->item(0)
|
->getElementsByTagName('Service')->item(0)
|
||||||
->getElementsByTagName('Code')->item(0)->nodeValue;
|
->getElementsByTagName('Code')->item(0)->nodeValue;
|
||||||
|
|
||||||
$name = Arr::get($this->shipping_codes['US'], $code);
|
$name = Arr::get($this->shippingCodes['US'], $code);
|
||||||
|
|
||||||
$cost = @$rate
|
$cost = @$rate
|
||||||
->getElementsByTagName('TotalCharges')->item(0)
|
->getElementsByTagName('TotalCharges')->item(0)
|
||||||
->getElementsByTagName('MonetaryValue')->item(0)->nodeValue;
|
->getElementsByTagName('MonetaryValue')->item(0)->nodeValue;
|
||||||
|
|
||||||
if ( ! empty($this->approved_codes) AND ! in_array($code, $this->approved_codes)) {
|
if (! empty($this->approvedCodes) && ! in_array($code, $this->approvedCodes)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->rates[] = array(
|
$quote = new Quote;
|
||||||
'code' => $code,
|
$quote
|
||||||
'name' => $name,
|
->setCarrier('ups')
|
||||||
'cost' => (int) ($cost * 100),
|
->setCode($code)
|
||||||
);
|
->setName($name)
|
||||||
|
->setCost($cost * 100);
|
||||||
|
$this->rates[] = $quote;
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
|
@ -1,26 +1,27 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
namespace pdt256\Shipping\USPS;
|
namespace pdt256\Shipping\USPS;
|
||||||
|
|
||||||
use pdt256\Shipping;
|
use pdt256\Shipping;
|
||||||
use pdt256\Shipping\Arr;
|
use pdt256\Shipping\Arr;
|
||||||
|
use pdt256\Shipping\Quote;
|
||||||
use pdt256\Shipping\RateAdapter;
|
use pdt256\Shipping\RateAdapter;
|
||||||
use pdt256\Shipping\RateRequest;
|
use pdt256\Shipping\RateRequest;
|
||||||
|
use pdt256\Shipping\Validator;
|
||||||
use DOMDocument;
|
use DOMDocument;
|
||||||
use Exception;
|
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 $username = 'XXX';
|
private $urlDev = 'http://production.shippingapis.com/ShippingAPI.dll';
|
||||||
private $password = 'XXX';
|
private $urlProd = 'http://production.shippingapis.com/ShippingAPI.dll';
|
||||||
|
private $username;
|
||||||
public $approved_codes = [
|
private $password;
|
||||||
'1',
|
|
||||||
'4',
|
|
||||||
];
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Codes of appropriate shipping types. Default value is specified in __construct.
|
||||||
|
*/
|
||||||
|
public $approvedCodes;
|
||||||
private $shipping_codes = [
|
private $shipping_codes = [
|
||||||
'domestic' => [
|
'domestic' => [
|
||||||
'00' => 'First-Class Mail Parcel',
|
'00' => 'First-Class Mail Parcel',
|
||||||
@ -66,85 +67,95 @@ class Rate extends RateAdapter
|
|||||||
],
|
],
|
||||||
];
|
];
|
||||||
|
|
||||||
public function __construct($options = [])
|
public function __construct($options = []) {
|
||||||
{
|
|
||||||
parent::__construct($options);
|
parent::__construct($options);
|
||||||
|
|
||||||
if (isset($options['username'])) {
|
$this->username = Arr::get($options, 'username');
|
||||||
$this->username = $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()));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isset($options['password'])) {
|
protected function validate() {
|
||||||
$this->password = $options['password'];
|
$this->validatePackages();
|
||||||
}
|
Validator::checkIfNull($this->username, 'username');
|
||||||
|
Validator::checkIfNull($this->password, 'password');
|
||||||
if (isset($options['username'])) {
|
Validator::checkIfNull($this->shipment->getFromPostalCode(), 'fromPostalCode');
|
||||||
$this->username = $options['username'];
|
Validator::checkIfNull($this->shipment->getToPostalCode(), 'toPostalCode');
|
||||||
}
|
|
||||||
|
|
||||||
if (isset($options['approved_codes'])) {
|
|
||||||
$this->approved_codes = $options['approved_codes'];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isset($options['request_adapter'])) {
|
|
||||||
$this->set_request_adapter($options['request_adapter']);
|
|
||||||
} else {
|
|
||||||
$this->set_request_adapter(new RateRequest\Get());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function prepare()
|
|
||||||
{
|
|
||||||
$to = Arr::get($this->shipment, 'to');
|
|
||||||
$shipper = Arr::get($this->shipment, 'from');
|
|
||||||
$dimensions = Arr::get($this->shipment, 'dimensions');
|
|
||||||
|
|
||||||
// https://www.usps.com/business/web-tools-apis/rate-calculators-v1-7a.htm
|
|
||||||
$pounds = (int) Arr::get($this->shipment, 'weight');
|
|
||||||
$ounces = 0;
|
|
||||||
|
|
||||||
if ($pounds < 1) {
|
|
||||||
throw new Exception('Weight missing');
|
|
||||||
}
|
|
||||||
|
|
||||||
$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>';
|
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function execute()
|
protected function prepare() {
|
||||||
{
|
$packages = '';
|
||||||
if ($this->is_prod) {
|
$sequence_number = 0;
|
||||||
$url = $this->url_prod;
|
foreach ($this->shipment->getPackages() as $p) {
|
||||||
|
$sequence_number++;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* RateV4Request / Package / Size
|
||||||
|
* required once
|
||||||
|
* Defined as follows:
|
||||||
|
*
|
||||||
|
* REGULAR: Package dimensions are 12’’ or less;
|
||||||
|
* LARGE: Any package dimension is larger than 12’’.
|
||||||
|
*
|
||||||
|
* For example: <Size>REGULAR</Size>
|
||||||
|
* string
|
||||||
|
* whiteSpace=collapse
|
||||||
|
* enumeration=LARGE
|
||||||
|
* enumeration=REGULAR
|
||||||
|
|
||||||
|
*/
|
||||||
|
if ($p->getWidth() > 12 or $p->getLength() > 12 or $p->getHeight() > 12) {
|
||||||
|
$size = 'LARGE';
|
||||||
|
$container = 'RECTANGULAR';
|
||||||
} else {
|
} else {
|
||||||
$url = $this->url_dev;
|
$size = 'REGULAR';
|
||||||
|
$container = 'VARIABLE';
|
||||||
|
}
|
||||||
|
|
||||||
|
$packages .= '<Package ID="' . $sequence_number . '">' .
|
||||||
|
'<Service>ALL</Service>' .
|
||||||
|
'<ZipOrigination>' . $this->shipment->getFromPostalCode() . '</ZipOrigination>' .
|
||||||
|
'<ZipDestination>' . $this->shipment->getToPostalCode() . '</ZipDestination>' .
|
||||||
|
'<Pounds>' . $p->getPounds() . '</Pounds>' .
|
||||||
|
'<Ounces>' . $p->getOunces() . '</Ounces>' .
|
||||||
|
'<Container>' . $container . '</Container>' .
|
||||||
|
'<Size>' . $size . '</Size>' .
|
||||||
|
'<Width>' . $p->getWidth() . '</Width>' .
|
||||||
|
'<Length>' . $p->getLength() . '</Length>' .
|
||||||
|
'<Height>' . $p->getHeight() . '</Height>' .
|
||||||
|
'<Machinable>' . 'False' . '</Machinable>' .
|
||||||
|
'</Package>';
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->data = '<RateV4Request USERID="' . $this->username . '">' .
|
||||||
|
'<Revision/>' .
|
||||||
|
$packages .
|
||||||
|
'</RateV4Request>';
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function execute() {
|
||||||
|
if ($this->isProduction) {
|
||||||
|
$url = $this->urlProd;
|
||||||
|
} else {
|
||||||
|
$url = $this->urlDev;
|
||||||
}
|
}
|
||||||
|
|
||||||
$url_request = $url . '?API=RateV4&XML=' . rawurlencode($this->data);
|
$url_request = $url . '?API=RateV4&XML=' . rawurlencode($this->data);
|
||||||
|
|
||||||
$this->response = $this->rate_request->execute($url_request);
|
$this->response = $this->rateRequest->execute($url_request);
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function process()
|
protected function process() {
|
||||||
{
|
|
||||||
try {
|
try {
|
||||||
$dom = new DOMDocument('1.0', 'UTF-8');
|
$dom = new DOMDocument('1.0', 'UTF-8');
|
||||||
$dom->loadXml($this->response);
|
$dom->loadXml($this->response);
|
||||||
@ -155,28 +166,41 @@ class Rate extends RateAdapter
|
|||||||
throw new Exception('Unable to get USPS Rates.');
|
throw new Exception('Unable to get USPS Rates.');
|
||||||
}
|
}
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
// StatsD::increment('error.shipping.get_usps_rate');
|
|
||||||
// Kohana::$log->add(Log::ERROR, $e)->write();
|
|
||||||
throw $e;
|
throw $e;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @var Quote[] $rates */
|
||||||
|
$rates = [];
|
||||||
|
|
||||||
foreach ($postage_list as $postage) {
|
foreach ($postage_list as $postage) {
|
||||||
$code = @$postage->getAttribute('CLASSID');
|
$code = @$postage->getAttribute('CLASSID');
|
||||||
$cost = @$postage->getElementsByTagName('Rate')->item(0)->nodeValue;
|
$cost = @$postage->getElementsByTagName('Rate')->item(0)->nodeValue;
|
||||||
|
|
||||||
$name = Arr::get($this->shipping_codes['domestic'], $code);
|
$name = Arr::get($this->shipping_codes['domestic'], $code);
|
||||||
|
|
||||||
if ( ! empty($this->approved_codes) AND ! in_array($code, $this->approved_codes)) {
|
if (!empty($this->approvedCodes) && !in_array($code, $this->approvedCodes)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->rates[] = array(
|
if (array_key_exists($code, $rates)) {
|
||||||
'code' => $code,
|
$cost = $rates[$code]->getCost() + ($cost * 100);
|
||||||
'name' => $name,
|
} else {
|
||||||
'cost' => (int) ($cost * 100),
|
$cost = $cost * 100;
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$quote = new Quote;
|
||||||
|
$quote
|
||||||
|
->setCarrier('usps')
|
||||||
|
->setCode($code)
|
||||||
|
->setName($name)
|
||||||
|
->setCost((int) $cost);
|
||||||
|
|
||||||
|
$rates[$quote->getCode()] = $quote;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->rates = array_values($rates);
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
12
src/Validator.php
Normal file
12
src/Validator.php
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
<?php
|
||||||
|
namespace pdt256\Shipping;
|
||||||
|
|
||||||
|
class Validator
|
||||||
|
{
|
||||||
|
public static function checkIfNull($value, $name)
|
||||||
|
{
|
||||||
|
if ($value === null) {
|
||||||
|
throw new \LogicException("$name is not set");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
30
tests/ArrTest.php
Normal file
30
tests/ArrTest.php
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
<?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)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
187
tests/Fedex/FedexTest.php
Normal file
187
tests/Fedex/FedexTest.php
Normal file
@ -0,0 +1,187 @@
|
|||||||
|
<?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();
|
||||||
|
}
|
||||||
|
}
|
227
tests/PackageDimensionsValidationTrait.php
Normal file
227
tests/PackageDimensionsValidationTrait.php
Normal file
@ -0,0 +1,227 @@
|
|||||||
|
<?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());
|
||||||
|
}
|
||||||
|
}
|
29
tests/PackageTest.php
Normal file
29
tests/PackageTest.php
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
<?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());
|
||||||
|
}
|
||||||
|
}
|
26
tests/QuoteTest.php
Normal file
26
tests/QuoteTest.php
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
<?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());
|
||||||
|
}
|
||||||
|
}
|
@ -1,29 +1,13 @@
|
|||||||
<?php
|
<?php
|
||||||
use pdt256\Shipping\Ship;
|
namespace pdt256\Shipping;
|
||||||
use pdt256\Shipping\USPS;
|
|
||||||
use pdt256\Shipping\UPS;
|
|
||||||
use pdt256\Shipping\Fedex;
|
|
||||||
use pdt256\Shipping\RateRequest;
|
|
||||||
|
|
||||||
class ShipTest extends PHPUnit_Framework_TestCase
|
use DateTime;
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
|
||||||
|
class ShipTest extends TestCase
|
||||||
{
|
{
|
||||||
public $shipment = [
|
/** @var Shipment */
|
||||||
'weight' => 3, // lbs
|
public $shipment;
|
||||||
'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 = [
|
public $shipping_options = [
|
||||||
'Standard Shipping' => [
|
'Standard Shipping' => [
|
||||||
@ -60,366 +44,114 @@ class ShipTest extends PHPUnit_Framework_TestCase
|
|||||||
],
|
],
|
||||||
];
|
];
|
||||||
|
|
||||||
|
public function setUp()
|
||||||
|
{
|
||||||
|
$s = new Shipment;
|
||||||
|
$s->setFromStateProvinceCode('CA')
|
||||||
|
->setFromPostalCode('90401')
|
||||||
|
->setFromCountryCode('US')
|
||||||
|
->setFromIsResidential(true)
|
||||||
|
->setToPostalCode('78703')
|
||||||
|
->setToCountryCode('US')
|
||||||
|
->setToIsResidential(true);
|
||||||
|
|
||||||
|
$p = new Package;
|
||||||
|
$p->setWeight(3)
|
||||||
|
->setWidth(9)
|
||||||
|
->setLength(9)
|
||||||
|
->setHeight(9);
|
||||||
|
|
||||||
|
$s->addPackage($p);
|
||||||
|
|
||||||
|
$this->shipment = $s;
|
||||||
|
}
|
||||||
|
|
||||||
private function getUSPSOptions()
|
private function getUSPSOptions()
|
||||||
{
|
{
|
||||||
$ship = Ship::factory($this->shipping_options);
|
$ship = Ship::factory($this->shipping_options);
|
||||||
$approved_codes = $ship->get_approved_codes('usps');
|
$approvedCodes = $ship->getApprovedCodes('usps');
|
||||||
|
|
||||||
return [
|
return [
|
||||||
'prod' => FALSE,
|
'prod' => false,
|
||||||
'username' => 'XXXX',
|
'username' => 'XXXX',
|
||||||
'password' => 'XXXX',
|
'password' => 'XXXX',
|
||||||
'shipment' => array_merge($this->shipment, [
|
'shipment' => $this->shipment,
|
||||||
'size' => 'LARGE',
|
'approvedCodes' => $approvedCodes,
|
||||||
'container' => 'RECTANGULAR',
|
'requestAdapter' => new RateRequest\StubUSPS(),
|
||||||
]),
|
|
||||||
'approved_codes' => $approved_codes,
|
|
||||||
'request_adapter' => new RateRequest\StubUSPS(),
|
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
private function getUPSOptions()
|
private function getUPSOptions()
|
||||||
{
|
{
|
||||||
$ship = Ship::factory($this->shipping_options);
|
$ship = Ship::factory($this->shipping_options);
|
||||||
$approved_codes = $ship->get_approved_codes('ups');
|
$approvedCodes = $ship->getApprovedCodes('ups');
|
||||||
|
|
||||||
return [
|
return [
|
||||||
'prod' => FALSE,
|
'prod' => false,
|
||||||
'access_key' => 'XXXX',
|
'accessKey' => 'XXXX',
|
||||||
'user_id' => 'XXXX',
|
'userId' => 'XXXX',
|
||||||
'password' => 'XXXX',
|
'password' => 'XXXX',
|
||||||
'shipper_number' => 'XXXX',
|
'shipperNumber' => 'XXXX',
|
||||||
'shipment' => $this->shipment,
|
'shipment' => $this->shipment,
|
||||||
'approved_codes' => $approved_codes,
|
'approvedCodes' => $approvedCodes,
|
||||||
'request_adapter' => new RateRequest\StubUPS(),
|
'requestAdapter' => new RateRequest\StubUPS(),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
private function getFedexOptions()
|
private function getFedexOptions()
|
||||||
{
|
{
|
||||||
$ship = Ship::factory($this->shipping_options);
|
$ship = Ship::factory($this->shipping_options);
|
||||||
$approved_codes = $ship->get_approved_codes('fedex');
|
$approvedCodes = $ship->getApprovedCodes('fedex');
|
||||||
|
|
||||||
return [
|
return [
|
||||||
'prod' => FALSE,
|
'prod' => false,
|
||||||
'key' => 'XXXX',
|
'key' => 'XXXX',
|
||||||
'password' => 'XXXX',
|
'password' => 'XXXX',
|
||||||
'account_number' => 'XXXX',
|
'accountNumber' => 'XXXX',
|
||||||
'meter_number' => 'XXXX',
|
'meterNumber' => 'XXXX',
|
||||||
'drop_off_type' => 'BUSINESS_SERVICE_CENTER',
|
'dropOffType' => 'BUSINESS_SERVICE_CENTER',
|
||||||
'shipment' => array_merge($this->shipment, [
|
'shipment' => $this->shipment,
|
||||||
'packaging_type' => 'YOUR_PACKAGING',
|
'approvedCodes' => $approvedCodes,
|
||||||
]),
|
'requestAdapter' => new RateRequest\StubFedex(),
|
||||||
'approved_codes' => $approved_codes,
|
|
||||||
'request_adapter' => new RateRequest\StubFedex(),
|
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testUSPSRate()
|
|
||||||
{
|
|
||||||
$usps = new USPS\Rate($this->getUSPSOptions());
|
|
||||||
$usps_rates = $usps->get_rates();
|
|
||||||
|
|
||||||
$this->assertEquals(json_encode([
|
|
||||||
1 => [
|
|
||||||
'code' => '4',
|
|
||||||
'name' => 'Parcel Post',
|
|
||||||
'cost' => 1001,
|
|
||||||
],
|
|
||||||
0 => [
|
|
||||||
'code' => '1',
|
|
||||||
'name' => 'Priority Mail',
|
|
||||||
'cost' => 1220,
|
|
||||||
],
|
|
||||||
]), json_encode($usps_rates));
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testUPSRate()
|
|
||||||
{
|
|
||||||
$ups = new UPS\Rate($this->getUPSOptions());
|
|
||||||
$ups_rates = $ups->get_rates();
|
|
||||||
|
|
||||||
$this->assertEquals(json_encode([
|
|
||||||
0 => [
|
|
||||||
'code' => '03',
|
|
||||||
'name' => 'UPS Ground',
|
|
||||||
'cost' => 1910,
|
|
||||||
],
|
|
||||||
1 => [
|
|
||||||
'code' => '02',
|
|
||||||
'name' => 'UPS 2nd Day Air',
|
|
||||||
'cost' => 4923,
|
|
||||||
],
|
|
||||||
2 => [
|
|
||||||
'code' => '13',
|
|
||||||
'name' => 'UPS Next Day Air Saver',
|
|
||||||
'cost' => 8954,
|
|
||||||
],
|
|
||||||
3 => [
|
|
||||||
'code' => '01',
|
|
||||||
'name' => 'UPS Next Day Air',
|
|
||||||
'cost' => 9328,
|
|
||||||
],
|
|
||||||
]), json_encode($ups_rates));
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testFedexRate()
|
|
||||||
{
|
|
||||||
$fedex = new Fedex\Rate($this->getFedexOptions());
|
|
||||||
$fedex_rates = $fedex->get_rates();
|
|
||||||
|
|
||||||
$this->assertEquals(json_encode([
|
|
||||||
3 => [
|
|
||||||
'code' => 'GROUND_HOME_DELIVERY',
|
|
||||||
'name' => 'Ground Home Delivery',
|
|
||||||
'cost' => 1655,
|
|
||||||
'delivery_ts' => NULL,
|
|
||||||
'transit_time' => 'THREE_DAYS',
|
|
||||||
],
|
|
||||||
2 => [
|
|
||||||
'code' => 'FEDEX_EXPRESS_SAVER',
|
|
||||||
'name' => 'Fedex Express Saver',
|
|
||||||
'cost' => 2989,
|
|
||||||
'delivery_ts' => '2014-09-30T20:00:00',
|
|
||||||
'transit_time' => NULL,
|
|
||||||
],
|
|
||||||
1 => [
|
|
||||||
'code' => 'FEDEX_2_DAY',
|
|
||||||
'name' => 'Fedex 2 Day',
|
|
||||||
'cost' => 4072,
|
|
||||||
'delivery_ts' => '2014-09-29T20:00:00',
|
|
||||||
'transit_time' => NULL,
|
|
||||||
],
|
|
||||||
0 => [
|
|
||||||
'code' => 'STANDARD_OVERNIGHT',
|
|
||||||
'name' => 'Standard Overnight',
|
|
||||||
'cost' => 7834,
|
|
||||||
'delivery_ts' => '2014-09-26T20:00:00',
|
|
||||||
'transit_time' => NULL,
|
|
||||||
],
|
|
||||||
]), json_encode($fedex_rates));
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testDisplayOptions()
|
public function testDisplayOptions()
|
||||||
{
|
{
|
||||||
$rates = [];
|
$rates = [];
|
||||||
|
|
||||||
$usps = new USPS\Rate($this->getUSPSOptions());
|
$usps = new USPS\Rate($this->getUSPSOptions());
|
||||||
$rates['usps'] = $usps->get_rates();
|
$rates['usps'] = $usps->getRates();
|
||||||
|
|
||||||
$ups = new UPS\Rate($this->getUPSOptions());
|
$ups = new UPS\Rate($this->getUPSOptions());
|
||||||
$rates['ups'] = $ups->get_rates();
|
$rates['ups'] = $ups->getRates();
|
||||||
|
|
||||||
$fedex = new Fedex\Rate($this->getFedexOptions());
|
$fedex = new Fedex\Rate($this->getFedexOptions());
|
||||||
$rates['fedex'] = $fedex->get_rates();
|
$rates['fedex'] = $fedex->getRates();
|
||||||
|
|
||||||
$ship = Ship::factory($this->shipping_options);
|
$ship = Ship::factory($this->shipping_options);
|
||||||
$display_rates = $ship->get_display_rates($rates);
|
$rates = $ship->getDisplayRates($rates);
|
||||||
|
|
||||||
$this->assertEquals(json_encode([
|
$post = new Quote('usps', '4', 'Parcel Post', 1001);
|
||||||
|
|
||||||
|
$fedexTwoDay = new Quote('fedex', 'FEDEX_2_DAY', 'Fedex 2 Day', 4072);
|
||||||
|
$fedexTwoDay->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 = [
|
||||||
'Standard Shipping' => [
|
'Standard Shipping' => [
|
||||||
0 => [
|
$post,
|
||||||
'code' => '4',
|
|
||||||
'name' => 'Parcel Post',
|
|
||||||
'cost' => 1001,
|
|
||||||
'carrier' => 'usps',
|
|
||||||
],
|
|
||||||
],
|
],
|
||||||
'Two-Day Shipping' => [
|
'Two-Day Shipping' => [
|
||||||
0 => [
|
$fedexTwoDay,
|
||||||
'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' => [
|
'One-Day Shipping' => [
|
||||||
0 => [
|
$overnight,
|
||||||
'code' => 'STANDARD_OVERNIGHT',
|
|
||||||
'name' => 'Standard Overnight',
|
|
||||||
'cost' => 7834,
|
|
||||||
'delivery_ts' => '2014-09-26T20:00:00',
|
|
||||||
'transit_time' => NULL,
|
|
||||||
'carrier' => 'fedex',
|
|
||||||
],
|
],
|
||||||
],
|
];
|
||||||
]), json_encode($display_rates));
|
|
||||||
|
$this->assertEquals($expected, $rates);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @expectedException Exception
|
|
||||||
*/
|
|
||||||
public function testUSPSRateMissingTo()
|
|
||||||
{
|
|
||||||
$usps_options = $this->getUSPSOptions();
|
|
||||||
unset($usps_options['shipment']['to']);
|
|
||||||
|
|
||||||
$usps = new USPS\Rate($usps_options);
|
|
||||||
$usps_rates = $usps->get_rates();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @expectedException Exception
|
|
||||||
*/
|
|
||||||
public function testUSPSRateMissingFrom()
|
|
||||||
{
|
|
||||||
$usps_options = $this->getUSPSOptions();
|
|
||||||
unset($usps_options['shipment']['from']);
|
|
||||||
|
|
||||||
$usps = new USPS\Rate($usps_options);
|
|
||||||
$usps_rates = $usps->get_rates();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @expectedException Exception
|
|
||||||
*/
|
|
||||||
public function testUSPSRateMissingDimensions()
|
|
||||||
{
|
|
||||||
$usps_options = $this->getUSPSOptions();
|
|
||||||
unset($usps_options['shipment']['dimensions']);
|
|
||||||
|
|
||||||
$usps = new USPS\Rate($usps_options);
|
|
||||||
$usps_rates = $usps->get_rates();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @expectedException Exception
|
|
||||||
*/
|
|
||||||
public function testUPSRateMissingTo()
|
|
||||||
{
|
|
||||||
$ups_options = $this->getUPSOptions();
|
|
||||||
unset($ups_options['shipment']['to']);
|
|
||||||
|
|
||||||
$ups = new UPS\Rate($ups_options);
|
|
||||||
$ups_rates = $ups->get_rates();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @expectedException Exception
|
|
||||||
*/
|
|
||||||
public function testUPSRateMissingFrom()
|
|
||||||
{
|
|
||||||
$ups_options = $this->getUPSOptions();
|
|
||||||
unset($ups_options['shipment']['from']);
|
|
||||||
|
|
||||||
$ups = new UPS\Rate($ups_options);
|
|
||||||
$ups_rates = $ups->get_rates();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @expectedException Exception
|
|
||||||
*/
|
|
||||||
public function testUPSRateMissingDimensions()
|
|
||||||
{
|
|
||||||
$ups_options = $this->getUPSOptions();
|
|
||||||
unset($ups_options['shipment']['dimensions']);
|
|
||||||
|
|
||||||
$ups = new UPS\Rate($ups_options);
|
|
||||||
$ups_rates = $ups->get_rates();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @expectedException Exception
|
|
||||||
*/
|
|
||||||
public function testFedexRateMissingTo()
|
|
||||||
{
|
|
||||||
$fedex_options = $this->getFedexOptions();
|
|
||||||
unset($fedex_options['shipment']['to']);
|
|
||||||
|
|
||||||
$fedex = new Fedex\Rate($fedex_options);
|
|
||||||
$fedex_rates = $fedex->get_rates();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @expectedException Exception
|
|
||||||
*/
|
|
||||||
public function testFedexRateMissingFrom()
|
|
||||||
{
|
|
||||||
$fedex_options = $this->getFedexOptions();
|
|
||||||
unset($fedex_options['shipment']['from']);
|
|
||||||
|
|
||||||
$fedex = new Fedex\Rate($fedex_options);
|
|
||||||
$fedex_rates = $fedex->get_rates();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @expectedException Exception
|
|
||||||
*/
|
|
||||||
public function testFedexRateMissingDimensions()
|
|
||||||
{
|
|
||||||
$fedex_options = $this->getFedexOptions();
|
|
||||||
unset($fedex_options['shipment']['dimensions']);
|
|
||||||
|
|
||||||
$fedex = new Fedex\Rate($fedex_options);
|
|
||||||
$fedex_rates = $fedex->get_rates();
|
|
||||||
}
|
|
||||||
|
|
||||||
// // Readme Examples:
|
|
||||||
// public function testUSPSReadmeExample()
|
|
||||||
// {
|
|
||||||
// $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);
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
129
tests/ShipmentTest.php
Normal file
129
tests/ShipmentTest.php
Normal file
@ -0,0 +1,129 @@
|
|||||||
|
<?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);
|
||||||
|
}
|
||||||
|
}
|
156
tests/UPS/RateTest.php
Normal file
156
tests/UPS/RateTest.php
Normal file
@ -0,0 +1,156 @@
|
|||||||
|
<?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();
|
||||||
|
}
|
||||||
|
}
|
118
tests/USPS/RateTest.php
Normal file
118
tests/USPS/RateTest.php
Normal file
@ -0,0 +1,118 @@
|
|||||||
|
<?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();
|
||||||
|
}
|
||||||
|
}
|
26
tests/ValidatorTest.php
Normal file
26
tests/ValidatorTest.php
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
<?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);
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user