A QCodo powered CMS
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

328 lines
12 KiB

<?php
if(!defined('QUINTACMS') ) die("No quinta.");
if (!defined("SHIPPINGMODULE.CLASS.PHP")){
define("SHIPPINGMODULE.CLASS.PHP",1);
/**
* Class ShippingModule - a module to display a selection of ShippingMethods
*
* This class obtains any shipping methods flagged as active in the database and
* adds them to a radiobutton list which is the only display object. For each method
* a new ShippingCalculator is instantiated and GetEstimate is called to obtain a price
* for the order based on information in the OrderItems and the addresses (ie. weight,
* size and destination).
*
* @todo
* - check availability more gracefully
* - handle errors
*
*@author Erik Winn <sidewalksoftware@gmail.com>
*
*@version 0.3
*
*@package Quinta
* @subpackage Modules
*/
class ShippingModule extends QPanel{
public $blnDebug = false;
/**
* This is the main control block for this module - it is designed to be the CheckOutModule,
* but it may be used with other controllers as long as you pass an Order object as we obtain
* address information, weight, etc from the order ..
*@var QPanel objControlBlock - the main control block for this module, usually CheckOutModule
*/
protected $objControlBlock;
/**
*@var Order objOrder - a local reference to the Order
*/
protected $objOrder;
/**
*@var Address objAddress - a local reference to the Address
*/
protected $objAddress;
/**
*@var ShippingMethod objSelectedMethod - the selected method for this module
*/
protected $objSelectedMethod;
/**
*@var array aryShippingMethods - the active methods available for this module
*/
protected $aryShippingMethods;
protected $strDefaultCarrier;
protected $strDefaultServiceType;
protected $fltShippingTotal;
protected $blnHasActiveMethods=true;
protected $blnIsInternational=false;
protected $intPreviousAddressId;
/**
* This is a mapping of shipping provider to method. Each ShippingMethod has a title
* field, this is displayed at the top of a block showing each method active for a provider.
* The title field is used as the title of the block, so the map is in the form title => objShippingMethodController
* the view containing a radiobutton for the selection of that method.
*@var array aryShippingProviders - an array/map of Carriers to methods
*/
public $aryShippingProviders;
/**
*@var AddressSelectionModule objAddressSelectionModule - handles selecting the shipping address
*/
public $objAddressSelectionModule;
/**
*@var QTextBox txtNotes - customer comments added to order ..
*/
public $txtNotes;
/**
* Module constructor
*@param QPanel objControlBlock - the main control block for this module, usually CheckOutModule
*@param Order objOrder - the order to be shipped ...
*/
public function __construct($pnlParentObject, $objControlBlock, Order $objOrder, $blnDebug = false ){
try {
parent::__construct($pnlParentObject );
} catch (QCallerException $objExc) {
$objExc->IncrementOffset();
throw $objExc;
}
if($blnDebug)
$this->blnDebug = $blnDebug;
$this->strDefaultCarrier = DEFAULT_SHIPPING_CARRIER;
$this->strDefaultServiceType = DEFAULT_SHIPPING_SERVICE;
//normally refers to the CheckOutModule ..
$this->objControlBlock =& $objControlBlock;
$this->objOrder =& $objOrder;
$this->AutoRenderChildren = true;
$this->strTemplate = __QUINTA_CORE_VIEWS__ . '/ShippingModule.tpl.php';
$this->initMethodViews();
if( !empty($this->aryShippingMethods)){
$this->objAddressSelectionModule = new AddressSelectionModule($this,
'SelectAddress',
$this->objOrder->ShippingAddressId
);
$this->objAddress = $this->objAddressSelectionModule->Address;
}else
$this->blnHasActiveMethods = false;
$this->txtNotes = new QTextBox($this);
$this->txtNotes->TextMode = QTextMode::MultiLine;
$this->txtNotes->Columns = 30;
}
/**
* This function initializes the array of potential shipping methods
*@todo make the local pickup option configurable, currently you have to change the check here ..
*/
protected function initShippingMethods(){
if( $this->objOrder->IsInternational)
$this->aryShippingMethods = ShippingMethod::QueryArray( QQ::AndCondition(
QQ::Equal(QQN::ShippingMethod()->Active, true),
QQ::Equal(QQN::ShippingMethod()->IsInternational,true)
));
else
$this->aryShippingMethods = ShippingMethod::QueryArray(
QQ::Equal(QQN::ShippingMethod()->Active, true)
);
if(ZoneType::Colorado == $this->objOrder->ShippingZoneId )
$this->aryShippingMethods[] = ShippingMethod::Load(1);
}
/**
* This function creates a radio button to display for each active shipping method as
* appropriate - if the method is not international no button will be created for an international
* order and if a method is not available or returns a 0 rate charge it will also not be created.
* @todo
* - check availability
* - implement try/catch to handle errors, log them when not debugging.
*/
protected function initMethodViews(){
$this->initShippingMethods();
if( empty($this->aryShippingMethods))
return;
if( is_array($this->aryShippingProviders) ){
foreach( $this->aryShippingProviders as $strName => &$aryMethodViews ){
foreach($aryMethodViews as $it => $objMethodView){
$strControlId = $objMethodView->ControlId;
$this->RemoveChildControl($strControlId, true);
unset($aryMethodViews[$it]);
}
unset($this->aryShippingProviders[$strName]);
}
$this->aryShippingProviders = array();
}
foreach($this->aryShippingMethods as $objShippingMethod){
//Fedex Ground international only goes for Canada
if($this->objOrder->IsInternational && CountryType::Canada != $this->objOrder->ShippingCountryId
&& false !== stripos( $objShippingMethod->ServiceType, 'FEDEX_GROUND' ) )
continue;
//Skip the Fedex international methods for domestic orders ..
if( !$this->objOrder->IsInternational
&& ( false !== stripos( $objShippingMethod->ServiceType, 'GLOBAL' )
|| false !== stripos( $objShippingMethod->ServiceType, 'INTERNATIONAL' )) )
continue;
$objShippingMethod->Init($this->objOrder);
///@todo check availability ..
/* if( ! $objShippingMethod->MethodAvailable() ) continue;*/
$objShippingMethod->GetRate();
/**
*@todo figure this out - USPS, eg. provides no clear way to determine availability (in fact i can't even
* find their !@#$ing error codes ..) so for now if there is no charge we assume it is not available ..
*/
if( ! $objShippingMethod->IsAvailable || $objShippingMethod->HasErrors || 0 == $objShippingMethod->Rate ){
// if($this->blnDebug && 'FEDEX_2_DAY' != $objShippingMethod->ServiceType)
if($this->blnDebug)
// exit(var_dump($objShippingMethod));
die($objShippingMethod->Title . ', '
. $objShippingMethod->ServiceType . '<br /> '
. $objShippingMethod->Errors );
else
continue;
}
//eh, could be a server error .. skip it. todo: make me smarter ..
if( ! is_numeric($objShippingMethod->Rate) )
continue;
$objShippingMethodController = new ShippingMethodController($this, $objShippingMethod);
//set the defaults here - note that if the default method is not active this leaves everything
//null until/unless the user selects a method; hence default should be properly configured.
if( $objShippingMethod->Carrier == $this->strDefaultCarrier
&& $objShippingMethod->ServiceType == $this->strDefaultServiceType )
{
$objShippingMethodController->Checked = true;
$this->objSelectedMethod = $objShippingMethod;
$this->objOrder->ShippingMethodId = $objShippingMethod->Id;
$this->objOrder->ShippingCharged = $objShippingMethod->Rate;
}
//store by title for the method display ..
$this->aryShippingProviders[$objShippingMethod->Title][] = $objShippingMethodController;
}
}
/**
* This Function is called when the user selects a method - it sets objSelectedMethod
* and updates ShippingMethodId and ShippingCharged in the Order ..
*@param integer intShippingMethodId - the id of the selected method
*/
public function SelectMethod($intShippingMethodId){
foreach($this->aryShippingMethods as $objMethod )
if($intShippingMethodId == $objMethod->Id){
//this is redundant .. todo: pick one way or the other?
$this->objSelectedMethod = $objMethod;
$this->objOrder->ShippingMethodId = $objMethod->Id;
$this->objOrder->ShippingCharged = $objMethod->Rate;
if($this->objControlBlock instanceof CheckOutModule)
$this->objControlBlock->RefreshOrderTotalsController();
break;
}
}
public function SelectAddress($intAddressId, $strParameter=null){
if( is_numeric($intAddressId) ){
$this->intPreviousAddressId = $intAddressId;
$this->objOrder->SetShippingAddress($this->objAddressSelectionModule->Address);
$this->objAddress = $this->objAddressSelectionModule->Address;
}
$this->objAddressSelectionModule->RemoveChildControls(true);
$this->RemoveChildControl($this->objAddressSelectionModule->ControlId, false);
if( 'Edit' == $strParameter )
$this->objAddressSelectionModule = new AddressSelectionModule($this, 'SelectAddress', $intAddressId, true);
elseif( 'New' == $strParameter )
$this->objAddressSelectionModule = new AddressSelectionModule($this, 'SelectAddress', null, true);
else{//Note: includes Save and Cancel .
if($intAddressId)
$this->objAddressSelectionModule = new AddressSelectionModule($this, 'SelectAddress', $intAddressId);
else
$this->objAddressSelectionModule = new AddressSelectionModule($this, 'SelectAddress', $this->intPreviousAddressId);
//Refresh the options listing ..
$this->initMethodViews();
}
$this->objAddressSelectionModule->Visible = true;
$this->AddChildControl($this->objAddressSelectionModule);
}
/**
* This Function is called when any input is sent - on failure the
* fields are redrawn with optional error messages.
*/
public function Validate(){
$blnToReturn = true;
// validate input here
return $blnToReturn;
}
public function __get($strName){
switch ($strName){
case 'Notes':
return $this->txtNotes->Text ;
case 'SelectedMethod':
return $this->objSelectedMethod ;
case 'Address':
return $this->objAddress ;
case 'HasActiveMethods':
return $this->blnHasActiveMethods ;
case 'IsInternational':
return $this->blnIsInternational ;
case 'DefaultCarrier':
return $this->strDefaultCarrier ;
case 'DefaultServiceType':
return $this->strDefaultServiceType ;
default:
try {
return parent::__get($strName);
} catch (QCallerException $objExc) {
$objExc->IncrementOffset();
throw $objExc;
}
}
}
public function __set($strName, $mixValue){
switch ($strName){
case 'IsInternational':
try {
return ($this->blnIsInternational = QType::Cast($mixValue, Qtype::Boolean ));
} catch (QInvalidCastException $objExc) {
$objExc->IncrementOffset();
throw $objExc;
}
case 'DefaultCarrier':
try {
return ($this->strDefaultCarrier = QType::Cast($mixValue, Qtype::String ));
} catch (QInvalidCastException $objExc) {
$objExc->IncrementOffset();
throw $objExc;
}
case 'DefaultServiceType':
try {
return ($this->strDefaultServiceType = QType::Cast($mixValue, Qtype::String ));
} catch (QInvalidCastException $objExc) {
$objExc->IncrementOffset();
throw $objExc;
}
default:
try {
return (parent::__set($strName, $mixValue));
} catch (QCallerException $objExc) {
$objExc->IncrementOffset();
throw $objExc;
}
}
}
}//end class
}//end define
?>