*
* $Id: USPSRequest.class.php 502 2009-02-10 22:09:53Z erikwinn $
*@version 0.1
*
*@copyright (C) 2008 by Erik Winn
*@license GPL v.2
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA
*
*@package Quasi
* @subpackage Classes
*/
class USPSRequest extends ShippingRequest
{
/**
*@var string Indicates enumeration value for size (REGULAR, LARGE, OVERSIZE)
*/
protected $strSize = "REGULAR";
/**
*@var string Indicates enumeration value for FIRST CLASS "type" [LETTER | FLAT | PARCEL]
*/
protected $strFirstClassMailType = "FLAT";
/**
*@var ShippingRequest
*/
protected $objEndiciaRequest;
/**
* USPSRequest Constructor
*
* @param ShippingMethod objShippingMethod - the method for which to obtain estimate
*/
public function __construct(ShippingMethod $objShippingMethod)
{
try {
parent::__construct($objShippingMethod);
} catch (QCallerException $objExc) {
$objExc->IncrementOffset();
throw $objExc;
}
///@todo this is currently defined in quasi_config - fixme!!
$this->RemoteAccountId = USPS_USERID;
$this->RemotePassword = USPS_PASSWORD;
if($this->blnTestMode)
{
$this->strRemoteDomainName = 'testing.shippingapis.com';
$this->strRemoteCgiUrl = '/ShippingAPITest.dll?';
}
else
{
$this->strRemoteDomainName = 'production.shippingapis.com';
$this->strRemoteCgiUrl = '/ShippingAPI.dll?';
}
$this->UseSsl = false;
}
//Public interface ..
/**
* Returns a shipping label for this method to the order address
* Note that we use the Endicia label server for this - it must be enabled
* and you must have a configured account with Endicia for this to work!
*@return resource gd image object containing label image
*/
public function GetLabel()
{
$this->objEndiciaRequest = new EndiciaRequest($this->objShippingMethod);
$this->objShippingLabelImage = $this->objEndiciaRequest->GetLabel();
$this->blnHasErrors = $this->objEndiciaRequest->HasErrors;
$this->strErrors = $this->objEndiciaRequest->Errors;
$this->aryExtraDocumentImages = $this->objEndiciaRequest->ExtraDocumentImages;
$this->aryCustomsFormImages = $this->objEndiciaRequest->CustomsFormImages;
return $this->objShippingLabelImage;
}
/**
* Returns a shipping rate for the order for this method
*@return image object containing the image code
*/
public function GetRate()
{
$this->createRequest(ShippingRequestType::Rate, WebRequestType::GET);
$this->submitRequest();
return $this->Rate;
}
//Request string creators
/**
* Creates a rate request - if the shipping is international this call createIntlRateRequest instead ..
*/
protected function createRateRequest()
{
if($this->Order->IsInternational)
return $this->createIntlRateRequest();
$this->strApiName = 'API=RateV3';
if($this->blnTestMode)
{
$this->OriginZip = '10022';
$this->DestinationZip = '20008';
$this->Ounces = 5;
$this->Pounds = 10;
$this->Container = 'Flat Rate Box';
}
$this->strRequest = '&XML=';
$strXml = '';
$strXml .= '';
$strXml .= '' . $this->ServiceType . '';
$strXml .= '' . $this->strFirstClassMailType . '';
$strXml .= '' . $this->OriginZip . '';
$strXml .= '' . $this->DestinationZip . '';
$strXml .= '' . $this->Pounds . '';
$strXml .= '' . round($this->Ounces, 2) . '';
$strXml .= '' . $this->Container .'';
$strXml .= '' . $this->strSize . '';
$strXml .= '' . ($this->IsMachinable ? 'True' : 'False') . '';
$strXml .= '';
$strXml = urlencode($strXml);
$this->strRequest .= $strXml;
}
/**
* Creates an international shipping rate request
*/
protected function createIntlRateRequest()
{
//USPS testing servers do not support international - force to production ..
$this->strRemoteDomainName = 'production.shippingapis.com';
$this->strRemoteCgiUrl = '/ShippingAPI.dll?';
//neato - USPS has decided that it prefers "Great Britain" and not "United Kingdom" ..
$strCountry = strtoupper($this->DestinationCountry);
if($strCountry == "UNITED KINGDOM")
$strCountry = 'GREAT BRITAIN';
$this->strApiName = 'API=IntlRate';
$this->strRequest = '&XML=';
$strXml = '';
$strXml .= '';
$strXml .= '' . $this->Pounds . '';
$strXml .= '' . round($this->Ounces, 2) . '';
$strXml .= 'Package';
$strXml .= '' . $strCountry . '';
$strXml .= '';
$strXml = urlencode($strXml);
$this->strRequest .= $strXml;
}
//Response handlers
/**
* Handles a rate request response
*/
protected function handleRateResponse()
{
if ($this->objShippingMethod->Order->IsInternational)
$objDomDoc = $this->getDomDocument('IntlRateResponse');
else
$objDomDoc = $this->getDomDocument('RateV3Response');
if($objDomDoc)
{
$strErrorMessage = $this->requestErrors($objDomDoc);
if($strErrorMessage)
{
$this->blnIsAvailable = false;
$this->blnHasErrors = true;
$this->strErrors = $strErrorMessage;
$this->Rate = 0;
} else {
$this->blnIsAvailable = true;
if( $this->objShippingMethod->Order->IsInternational)
return $this->handleIntlRateResponse($objDomDoc);
$nodeList = $objDomDoc->getElementsByTagName('Postage');
$nodeList = $nodeList->item(0)->getElementsByTagName('Rate');
if($nodeList->length > 0)
$this->Rate = $nodeList->item(0)->nodeValue;
else
$this->Rate = 0;
}
} else {
$this->blnIsAvailable = false;
$this->HasErrors = true;
$this->Errors = 'Unknown USPS error ..Request:' . $this->strRequest . ' Response:' . $this->strResponse;
$this->Rate = 0;
}
}
/**
* Handles an International rate request response.
* USPS returns multiple rates for some areas (eg. Australia) and we need to parse the DOM to
* return the correct rate for the method (service type).
* @todo - more sophisticated and configurable matching by package type; currently we mostly grab the first match ..
* Here is a typical response for the Service nodes:
00.07PackageROMANIA
79.951 - 3 Days\
Global Express GuaranteedMax. length 46", width 35", height 46" and max. length plus girth 108"70
00.07PackageROMANIA
79.951 - 3 Days
Global Express Guaranteed Non-Document RectangularMax. length 46", width 35", height 46" and max. length plus girth 108"70
00.07PackageROMANIA
79.951 - 3 Days
Global Express Guaranteed Non-Document Non-RectangularMax. length 46", width 35", height 46" and max. length plus girth 108"70
00.07PackageROMANIA
79.951 - 3 Days
USPS GXG EnvelopesCardboard envelope has a dimension of 9 1/2" X 12 1/2" and GXG tyvek envelope has a dimension of 12 1/2" X 15 1/2"70
00.07PackageROMANIA
25.958 Days
Express Mail International (EMS)Max.length 36", max. length plus girth 79"70
00.07PackageROMANIA
25.958 Days
Express Mail International (EMS) Flat-Rate Envelope9 1/2" X 12 1/2"70
00.07PackageROMANIA
21.506 - 10 Days
Priority Mail InternationalMax. length 42", Max length plus girth combined 79"70
00.07PackageROMANIA
11.956 - 10 Days
Priority Mail International Flat-Rate EnvelopeUSPS-supplied Priority Mail flat-rate envelope 9 1/2" x 12 1/2." Maximum weight 4 pounds.4
00.07PackageROMANIA
38.956 - 10 Days
Priority Mail International Flat-Rate BoxUSPS-supplied Priority Mail flat-rate box. Maximum weight 20 pounds.20
00.07PackageROMANIA
49.956 - 10 Days
Priority Mail International Large Flat-Rate BoxUSPS-supplied Priority Mail Large flat-rate box. Maximum weight 20 pounds.20
00.07PackageROMANIA
0.94Varies
First Class Mail International LettersMax. length 11.5", height 6 1/8" or more than 1/4" thick0.2188
1.20Varies
First Class Mail International Large EnvelopeMax. length 15", height 12 or more than 3/4" thick4
00.07PackageROMANIA
1.40Varies
First Class Mail International PackageMax. length 24", max length, height and depth (thickness) combined 36"4
*
*/
protected function handleIntlRateResponse($objDomDoc)
{
$this->Rate = 0;
$nodeList = $objDomDoc->getElementsByTagName('Service');
if($nodeList->length > 0)
{
foreach($nodeList as $objNode)
{
$nodeSvcDescription = $objNode->getElementsByTagName('SvcDescription');
$nodePostage = $objNode->getElementsByTagName('Postage');
if($nodeSvcDescription->length > 0)
{
$strSvcDesc = $nodeSvcDescription->item(0)->nodeValue;
if(false !== stripos($strSvcDesc , $this->ServiceType ))
{
//these are examples - not written in stone (they just happen to work for me now ..):
if('First Class Mail International' == $this->ServiceType )
{
if(false === stripos($strSvcDesc , 'Large Envelope' ))
continue;
else
{
$this->Rate = $nodePostage->item(0)->nodeValue;
break;
}
}
if('Priority Mail International' == $this->ServiceType )
{
if(false === stripos($strSvcDesc , 'Flat-Rate Envelope' ))
continue;
else
{
$this->Rate = $nodePostage->item(0)->nodeValue;
break;
}
}
}
}
}
}
}
/**
* Utility function to check for request errors - returns either a string containing
* server error messages or false if there were none.
*@param DOMDocument objDomDoc - the server response ..
*@return string | boolean error messages or false if request succeeded.
*/
private function requestErrors($objDomDoc)
{
$mixToReturn = false;
$nodeListErrors = $objDomDoc->getElementsByTagName('Error');
if( $nodeListErrors->length > 0 )
{
$this->blnHasErrors = true;
$mixToReturn = 'Request: ' . $this->strRequest;
$nodeListErrorMessages = $objDomDoc->getElementsByTagName('Description');
if( $nodeListErrorMessages->length)
$mixToReturn .= ' Message: ' . $nodeListErrorMessages->item(0)->nodeValue;
}
return $mixToReturn;
}
/*************************************************************************************/
///@todo - implement me:
/**
* Returns an account status report
*@return string containing the status report
*/
public function GetAccountStatus()
{
throw new QCallerException(sprintf('USPSRequest: Shipping request type %s unsupported! ',
ShippingRequestType::ToString($this->ShippingRequestType)) );
}
/**
* Returns whether this method is available for the order address
*@return boolean true if method is available
*/
public function GetAvailability()
{
throw new QCallerException(sprintf('USPSRequest: Shipping request type %s unsupported! ',
ShippingRequestType::ToString($this->ShippingRequestType)) );
}
/**
* Submits an account credit payment
*@return boolean true on success
*/
public function CreditAccount()
{
throw new QCallerException(sprintf('USPSRequest: Shipping request type %s unsupported! ',
ShippingRequestType::ToString($this->ShippingRequestType)) );
}
//Request string creators
/**
* Creates a method available request
*/
protected function createAvailabilityRequest()
{
throw new QCallerException(sprintf('USPSRequest: Shipping request type %s unsupported! ',
ShippingRequestType::ToString($this->ShippingRequestType)) );
}
/**
* Creates a label printing request
*/
protected function createLabelRequest()
{
throw new QCallerException(sprintf('USPSRequest: Shipping request type %s unsupported! ',
ShippingRequestType::ToString($this->ShippingRequestType)) );
}
/**
* Creates a request submitting an account credit payment
*/
protected function createCreditAccountRequest()
{
throw new QCallerException(sprintf('USPSRequest: Shipping request type %s unsupported! ',
ShippingRequestType::ToString($this->ShippingRequestType)) );
}
/**
* Creates an account status request
*/
protected function createAccountStatusRequest()
{
throw new QCallerException(sprintf('USPSRequest: Shipping request type %s unsupported! ',
ShippingRequestType::ToString($this->ShippingRequestType)) );
}
/**
* Handles an account status request
*/
protected function handleAccountStatusResponse()
{
throw new QCallerException(sprintf('USPSRequest: Shipping request type %s unsupported! ',
ShippingRequestType::ToString($this->ShippingRequestType)) );
}
/**
* Handles a request submitting an account credit payment
*/
protected function handleCreditAccountResponse()
{
throw new QCallerException(sprintf('USPSRequest: Shipping request type %s unsupported! ',
ShippingRequestType::ToString($this->ShippingRequestType)) );
}
/**
* Handles a method available request
*/
protected function handleAvailabilityResponse()
{
throw new QCallerException(sprintf('USPSRequest: Shipping request type %s unsupported! ',
ShippingRequestType::ToString($this->ShippingRequestType)) );
}
/**
* Handles a label request
*/
protected function handleLabelResponse()
{
throw new QCallerException(sprintf('USPSRequest: Shipping request type %s unsupported! ',
ShippingRequestType::ToString($this->ShippingRequestType)) );
}
/*************************************************************************************/
}//end class
}//end define
?>