/**
  * Display a radio button list of shipping options
  * to the end user and process the chosen option
  *
  * @return void
  */
 public function actionShippingOptions()
 {
     $this->publishJS('shipping');
     $this->publishJS('zippo');
     $this->layout = '/layouts/checkout';
     $this->checkoutForm = MultiCheckoutForm::loadFromSessionOrNew();
     // Check whether the user has selected a shipping option.
     if (isset($_POST['MultiCheckoutForm'])) {
         $this->checkoutForm->attributes = $_POST['MultiCheckoutForm'];
         $this->checkoutForm->hasTaxModeChanged = false;
         $this->checkoutForm->setScenario('ShippingOptions');
         if ($this->checkoutForm->validate() === true) {
             $this->checkoutForm->saveFormToSession();
             // Update the cart shipping in the database.
             // Update shipping. If in-store pickup was chosen then we need to
             // ensure the cart shipping values are updated.
             $objShipping = CartShipping::getOrCreateCartShipping();
             if ($objShipping->hasErrors() === false) {
                 $objShipping->updateShipping();
                 $this->checkoutForm->addErrors($objShipping->getErrors());
             } else {
                 $this->checkoutForm->addErrors($objShipping->getErrors());
             }
             $this->checkoutForm->passedScenario = $this->checkoutForm->getScenario();
             $this->redirect($this->createUrl('/checkout/final'));
         } else {
             Yii::log(sprintf('Validation of the checkout form failed: %s', print_r($this->checkoutForm->getErrors(), true)), 'error', 'application.' . __CLASS__ . '.' . __FUNCTION__);
         }
     }
     // In the case where the destination does not have a defined tax code,
     // return to the shipping page with an error message.
     if (Checkout::verifyUserShippingDestination($this->checkoutForm) === false) {
         Yii::log(sprintf('Shipping destination is invalid: country=%s state=%s postal=%s', $this->checkoutForm->shippingCountryCode, $this->checkoutForm->shippingStateCode, $this->checkoutForm->shippingPostal), 'error', 'application.' . __CLASS__ . "." . __FUNCTION__);
         $this->redirect(array('/checkout/shipping', 'error-destination' => true));
         return;
     }
     // Update the cart taxes prior to updating the cart scenarios.
     Yii::app()->shoppingcart->setTaxCodeByCheckoutForm($this->checkoutForm);
     $arrCartScenario = Shipping::loadCartScenariosFromSession();
     // In the case where no shipping options are available, return to the
     // shipping page with an error message.
     // TODO: This isn't quite right. If store pickup is the only option, we
     // also want to display this error because store pickup is not shown
     // shown on the shipping options screen. See WS-3267.
     if ($arrCartScenario === null || count($arrCartScenario) === 0) {
         Yii::log(sprintf('No shipping options available: country=%s state=%s postal=%s', $this->checkoutForm->shippingCountryCode, $this->checkoutForm->shippingStateCode, $this->checkoutForm->shippingPostal), 'info', 'application.' . __CLASS__ . "." . __FUNCTION__);
         $this->redirect(array('/checkout/shipping', 'error-destination' => true));
         return;
     }
     // Render the shipping options.
     // The options themselves are loaded from the session.
     // The implication here is that before redirecting to this page, ensure
     // that the shipping options stored in the session are up to date.
     $this->render('shippingoptions', array('model' => $this->checkoutForm, 'arrCartScenario' => $arrCartScenario, 'error' => $this->formatErrors()));
 }
 /**
  * This is the method used by the advanced cart and checkout to retrieve
  * shipping options and their rates for the shipping estimator.
  * @return string JSON encoded array of shipping options ordered by price.
  */
 public function actionGetShippingRates()
 {
     $checkoutForm = MultiCheckoutForm::loadFromSessionOrNew();
     // If no CheckoutForm is posted, then the checkoutForm stored in the
     // session is used.  This is completely valid when we want updated
     // rates, but haven't modified (or perhaps don't know) the shipping
     // address.
     if (isset($_POST['CheckoutForm'])) {
         $checkoutForm->attributes = $_POST['CheckoutForm'];
     }
     // Transform the postcode as required by the shipping modules.
     // TODO Can we move this?
     $checkoutForm->shippingPostal = strtoupper(str_replace(' ', '', $checkoutForm->shippingPostal));
     // Minimal requirements for shipping: just address details.
     $checkoutForm->scenario = 'MinimalShipping';
     if ($checkoutForm->validate() === false) {
         return $this->renderJSON(array('result' => 'error', 'errors' => $checkoutForm->getErrors()));
     }
     try {
         $arrCartScenario = Shipping::getCartScenarios($checkoutForm);
     } catch (Exception $e) {
         return $this->renderJSON(array('result' => 'error', 'errormsg' => $e->getMessage()));
     }
     // Get the shipping estimator JavaScript options.
     $wsShippingEstimatorOptions = WsShippingEstimator::getShippingEstimatorOptions($arrCartScenario, $checkoutForm->shippingProvider, $checkoutForm->shippingPriority, $checkoutForm->shippingCity, $checkoutForm->shippingStateCode, $checkoutForm->shippingCountryCode);
     $shippingEstimatorMessage = findWhere($wsShippingEstimatorOptions['messages'], array('code' => 'WARN'));
     if ($shippingEstimatorMessage !== null) {
         $message = Yii::t('checkout', 'Your previous shipping selection is no longer available. Please choose an available shipping option.');
         Yii::app()->user->setFlash('error', $message);
     }
     // Save to session.
     Shipping::saveCartScenariosToSession($arrCartScenario);
     MultiCheckoutForm::saveToSession($checkoutForm);
     // Save to the database.
     $objShipping = CartShipping::getOrCreateCartShipping();
     $objShipping->updateShipping();
     return $this->renderJSON(array('result' => 'success', 'wsShippingEstimatorOptions' => $wsShippingEstimatorOptions, 'taxModeChangedMessage' => Yii::app()->user->getFlash('taxModeChange', null)));
 }