* *@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 . '
' . $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 ?>