oxbasket.php

Go to the documentation of this file.
00001 <?php
00002 
00005 class oxBasket extends oxSuperCfg
00006 {
00012     protected $_aBasketContents = array();
00013 
00019     protected $_iProductsCnt = 0;
00020 
00026     protected $_dItemsCnt = 0.0;
00027 
00033     protected $_dWeight = 0.0;
00034 
00040     protected $_oPrice = null;
00041 
00047     protected $_oProductsPriceList = null;
00048 
00054     protected $_aDiscounts = array();
00055 
00061     protected $_aItemDiscounts = array();
00062 
00068     protected $_sOrderId = null;
00069 
00075     protected $_aVouchers = array();
00076 
00082     protected $_aCosts = array();
00083 
00089     protected $_oDiscountProductsPriceList = null;
00090 
00096     protected $_oNotDiscountedProductsPriceList = null;
00097 
00103     protected $_blUpdateNeeded = true;
00104 
00110     protected $_aBasketSummary = null;
00111 
00117     protected $_sPaymentId = null;
00118 
00124     protected $_sShippingSetId = null;
00125 
00131     protected $_oUser = null;
00132 
00138     protected $_oTotalDiscount = null;
00139 
00145     protected $_oVoucherDiscount = null;
00146 
00152     protected $_oCurrency = null;
00153 
00159     protected $_blSkipVouchersAvailabilityChecking = null;
00160 
00166     protected $_dDiscountedProductNettoPrice = null;
00167 
00173     protected $_aDiscountedVats = null;
00174 
00180     protected $_blSkipDiscounts = false;
00181 
00187     protected $_oDeliveryPrice = null;
00188 
00194      protected $_blCheckStock = true;
00195 
00201     protected $_blCalcDiscounts = true;
00202 
00208     protected $_sBasketCategoryId = null;
00209 
00215     protected $_blShowCatChangeWarning = false;
00216 
00222     protected $_sTsProductId = null;
00223 
00229     public function isEnabled()
00230     {
00231         return !oxUtils::getInstance()->isSearchEngine();
00232     }
00233 
00243     protected function _changeBasketItemKey($sOldKey, $sNewKey, $value = null)
00244     {
00245         reset($this->_aBasketContents);
00246         $iOldKeyPlace = 0;
00247         while (key($this->_aBasketContents) != $sOldKey && next($this->_aBasketContents)) {
00248             ++$iOldKeyPlace;
00249         }
00250         $aNewCopy = array_merge(
00251             array_slice($this->_aBasketContents, 0, $iOldKeyPlace, true),
00252             array($sNewKey => $value),
00253             array_slice($this->_aBasketContents, $iOldKeyPlace+1, count($this->_aBasketContents)-$iOldKeyPlace, true)
00254         );
00255         $this->_aBasketContents = $aNewCopy;
00256     }
00257 
00273     public function addToBasket( $sProductID, $dAmount, $aSel = null, $aPersParam = null, $blOverride = false, $blBundle = false, $sOldBasketItemId = null )
00274     {
00275         // enabled ?
00276         if ( !$this->isEnabled() )
00277             return null;
00278 
00279         // basket exclude
00280         if ( $this->getConfig()->getConfigParam( 'blBasketExcludeEnabled' ) ) {
00281             if ( !$this->canAddProductToBasket( $sProductID ) ) {
00282                 $this->setCatChangeWarningState( true );
00283                 return null;
00284             } else {
00285                 $this->setCatChangeWarningState( false );
00286             }
00287         }
00288 
00289         $sItemId = $this->getItemKey( $sProductID, $aSel, $aPersParam, $blBundle );
00290         if ( $sOldBasketItemId && ( strcmp( $sOldBasketItemId, $sItemId ) != 0 ) ) {
00291             if ( isset( $this->_aBasketContents[$sItemId] ) ) {
00292                 // we are merging, so params will just go to the new key
00293                 unset( $this->_aBasketContents[$sOldBasketItemId] );
00294                 // do not override stock
00295                 $blOverride = false;
00296             } else {
00297                 // value is null - means isset will fail and real values will be filled
00298                 $this->_changeBasketItemKey( $sOldBasketItemId, $sItemId );
00299             }
00300         }
00301 
00302         // after some checks item must be removed from basket
00303         $blRemoveItem = false;
00304 
00305         // initialting exception storage
00306         $oEx = null;
00307 
00308         if ( isset( $this->_aBasketContents[$sItemId] ) ) {
00309 
00310             //updating existing
00311             try {
00312                 // setting stock check status
00313                 $this->_aBasketContents[$sItemId]->setStockCheckStatus( $this->getStockCheckMode() );
00314                 //validate amount
00315                 //possibly throws exception
00316                 $this->_aBasketContents[$sItemId]->setAmount( $dAmount, $blOverride, $sItemId );
00317             } catch( oxOutOfStockException $oEx ) {
00318                 // rethrow later
00319             }
00320 
00321         } else {
00322             //inserting new
00323             $oBasketItem = oxNew( 'oxbasketitem' );
00324             try {
00325                 $oBasketItem->setStockCheckStatus( $this->getStockCheckMode() );
00326                 $oBasketItem->init( $sProductID, $dAmount, $aSel, $aPersParam, $blBundle );
00327             } catch( oxNoArticleException $oEx ) {
00328                 // in this case that the article does not exist remove the item from the basket by setting its amount to 0
00329                 //$oBasketItem->dAmount = 0;
00330                 $blRemoveItem = true;
00331 
00332             } catch( oxOutOfStockException $oEx ) {
00333                 // rethrow later
00334             } catch ( oxArticleInputException $oEx ) {
00335                 // rethrow later
00336                 $blRemoveItem = true;
00337             }
00338 
00339             $this->_aBasketContents[$sItemId] = $oBasketItem;
00340         }
00341 
00342         //in case amount is 0 removing item
00343         if ( $this->_aBasketContents[$sItemId]->getAmount() == 0 || $blRemoveItem ) {
00344             $this->removeItem( $sItemId );
00345         } elseif ( $blBundle ) {
00346             //marking bundles
00347             $this->_aBasketContents[$sItemId]->setBundle( true );
00348         }
00349 
00350         //calling update method
00351         $this->onUpdate();
00352 
00353         if ( $oEx ) {
00354             throw $oEx;
00355         }
00356         return $this->_aBasketContents[$sItemId];
00357     }
00358 
00366     public function addOrderArticleToBasket( $oOrderArticle )
00367     {
00368         // adding only if amount > 0
00369         if ( $oOrderArticle->oxorderarticles__oxamount->value > 0 ) {
00370             $sItemId = $oOrderArticle->getId();
00371 
00372             //inserting new
00373             $this->_aBasketContents[$sItemId] = oxNew( 'oxbasketitem' );
00374             $this->_aBasketContents[$sItemId]->initFromOrderArticle( $oOrderArticle );
00375             $this->_aBasketContents[$sItemId]->setWrapping( $oOrderArticle->oxorderarticles__oxwrapid->value );
00376 
00377             //calling update method
00378             $this->onUpdate();
00379 
00380             return $this->_aBasketContents[$sItemId];
00381         }
00382     }
00383 
00391     public function setStockCheckMode( $blCheck )
00392     {
00393         $this->_blCheckStock = $blCheck;
00394     }
00395 
00401     public function getStockCheckMode()
00402     {
00403         return $this->_blCheckStock;
00404     }
00405 
00418     public function getItemKey( $sProductId, $aSel = null, $aPersParam = null, $blBundle = false, $sAdditionalParam = '' )
00419     {
00420         $aSel = ( $aSel != null) ? $aSel : array (0=>'0');
00421 
00422         $sItemKey = md5( $sProductId.'|'.serialize( $aSel ).'|'.serialize( $aPersParam ).'|'.( int ) $blBundle . '|' . serialize( $sAdditionalParam ) );
00423 
00424         return $sItemKey;
00425     }
00426 
00427 
00435     public function removeItem( $sItemKey )
00436     {
00437         if ($this->getConfig()->getConfigParam( 'blPsBasketReservationEnabled' )) {
00438             if (isset($this->_aBasketContents[$sItemKey])) {
00439                 $sArticleId = $this->_aBasketContents[$sItemKey]->getProductId();
00440                 if ($sArticleId) {
00441                     $this->getSession()
00442                             ->getBasketReservations()
00443                             ->discardArticleReservation($sArticleId);
00444                 }
00445             }
00446         }
00447         unset( $this->_aBasketContents[$sItemKey] );
00448 
00449         // basket exclude
00450         if ( !count($this->_aBasketContents) && $this->getConfig()->getConfigParam( 'blBasketExcludeEnabled' ) ) {
00451             $this->setBasketRootCatId(null);
00452         }
00453     }
00454 
00460     protected function _clearBundles()
00461     {
00462         reset( $this->_aBasketContents );
00463         while ( list( $sItemKey, $oBasketItem ) = each( $this->_aBasketContents ) ) {
00464             if ( $oBasketItem->isBundle() ) {
00465                 $this->removeItem( $sItemKey );
00466             }
00467         }
00468     }
00469 
00477     protected function _getArticleBundles( $oBasketItem )
00478     {
00479         $aBundles = array();
00480 
00481         if ( $oBasketItem->isBundle() ) {
00482             return $aBundles;
00483         }
00484 
00485         $oArticle = $oBasketItem->getArticle();
00486         if ( $oArticle && $oArticle->oxarticles__oxbundleid->value ) {
00487             $aBundles[$oArticle->oxarticles__oxbundleid->value] = 1;
00488         }
00489 
00490         return $aBundles;
00491     }
00492 
00500     protected function _getItemBundles( $oBasketItem )
00501     {
00502         if ( $oBasketItem->isBundle() ) {
00503             return array();
00504         }
00505 
00506         $aBundles = array();
00507 
00508         // does this object still exists ?
00509         if ( $oArticle = $oBasketItem->getArticle() ) {
00510             $aDiscounts = oxDiscountList::getInstance()->getBasketItemBundleDiscounts( $oArticle, $this, $this->getBasketUser() );
00511 
00512             foreach ( $aDiscounts as $oDiscount ) {
00513 
00514                 //init array element
00515                 if ( !isset( $aBundles[$oDiscount->oxdiscount__oxitmartid->value] ) ) {
00516                     $aBundles[$oDiscount->oxdiscount__oxitmartid->value] = 0;
00517                 }
00518 
00519                 $aBundles[$oDiscount->oxdiscount__oxitmartid->value] += $oDiscount->getBundleAmount( $oBasketItem->getAmount() );
00520 
00521             }
00522         }
00523 
00524         return $aBundles;
00525     }
00526 
00532     protected function _getBasketBundles()
00533     {
00534         $aBundles = array();
00535         $aDiscounts = oxDiscountList::getInstance()->getBasketBundleDiscounts( $this, $this->getBasketUser() );
00536 
00537         // calculating amount of non bundled/discount items
00538         $dAmount = 0;
00539         foreach ( $this->_aBasketContents as $oBasketItem ) {
00540             if ( !( $oBasketItem->isBundle() || $oBasketItem->isDiscountArticle() ) ) {
00541                 $dAmount += $oBasketItem->getAmount();
00542             }
00543         }
00544 
00545         foreach ( $aDiscounts as $oDiscount ) {
00546             if ($oDiscount->oxdiscount__oxitmartid->value) {
00547                 if ( !isset( $aBundles[$oDiscount->oxdiscount__oxitmartid->value] ) ) {
00548                     $aBundles[$oDiscount->oxdiscount__oxitmartid->value] = 0;
00549                 }
00550 
00551                 $aBundles[$oDiscount->oxdiscount__oxitmartid->value] += $oDiscount->getBundleAmount( $dAmount );
00552             }
00553         }
00554 
00555         return $aBundles;
00556     }
00557 
00564     protected function _addBundles()
00565     {
00566         // iterating through articles and binding bundles
00567         foreach ( $this->_aBasketContents as $key => $oBasketItem ) {
00568             try {
00569                 // adding discount type bundles
00570                 if ( !$oBasketItem->isDiscountArticle() && !$oBasketItem->isBundle() ) {
00571                     $aBundles = $this->_getItemBundles( $oBasketItem );
00572                 } else {
00573                     continue;
00574                 }
00575 
00576                 $this->_addBundlesToBasket( $aBundles );
00577 
00578                     // adding item type bundles
00579                     $aBundles = $this->_getArticleBundles( $oBasketItem );
00580 
00581                     // adding bundles to basket
00582                     $this->_addBundlesToBasket( $aBundles );
00583             } catch ( oxNoArticleException $oEx ) {
00584                 $this->removeItem( $key );
00585                 oxUtilsView::getInstance()->addErrorToDisplay( $oEx );
00586             } catch( oxArticleInputException $oEx ) {
00587                 $this->removeItem( $key );
00588                 oxUtilsView::getInstance()->addErrorToDisplay( $oEx );
00589             }
00590         }
00591 
00592         // adding global basket bundles
00593         if ( $aBundles = $this->_getBasketBundles() ) {
00594             $this->_addBundlesToBasket( $aBundles );
00595         }
00596 
00597     }
00598 
00606     protected function _addBundlesToBasket( $aBundles )
00607     {
00608         foreach ( $aBundles as $sBundleId => $dAmount ) {
00609             try {
00610                 if ( $oBundleItem = $this->addToBasket( $sBundleId, $dAmount, null, null, true, true ) ) {
00611                     $oBundleItem->setAsDiscountArticle( true );
00612                 }
00613             } catch(oxArticleException $oEx) {
00614                 // caught and ignored
00615             }
00616         }
00617 
00618     }
00619 
00625     protected function _calcItemsPrice()
00626     {
00627         // resetting
00628         $this->setSkipDiscounts( false );
00629         $this->_iProductsCnt = 0; // count different types
00630         $this->_dItemsCnt    = 0; // count of item units
00631         $this->_dWeight      = 0; // basket weight
00632 
00633         // resetting
00634         $this->_aItemDiscounts = array();
00635 
00636         $this->_oProductsPriceList = oxNew( 'oxpricelist' );
00637         $this->_oDiscountProductsPriceList = oxNew( 'oxpricelist' );
00638         $this->_oNotDiscountedProductsPriceList = oxNew( 'oxpricelist' );
00639 
00640         $oDiscountList = oxDiscountList::getInstance();
00641 
00642         foreach ( $this->_aBasketContents as $oBasketItem ) {
00643             $this->_iProductsCnt++;
00644             $this->_dItemsCnt += $oBasketItem->getAmount();
00645             $this->_dWeight   += $oBasketItem->getWeight();
00646 
00647             if ( !$oBasketItem->isDiscountArticle() && ( $oArticle = $oBasketItem->getArticle() ) ) {
00648                 $oBasketPrice = $oArticle->getBasketPrice( $oBasketItem->getAmount(), $oBasketItem->getSelList(), $this );
00649                 $oBasketItem->setPrice( $oBasketPrice );
00650                 //P adding product price
00651                 $this->_oProductsPriceList->addToPriceList( $oBasketItem->getPrice() );
00652 
00653                 $oBasketPrice->setBruttoPriceMode();
00654                 if ( !$oArticle->skipDiscounts() && $this->canCalcDiscounts() ) {
00655                     // apply basket type discounts
00656                     $aItemDiscounts = $oDiscountList->applyBasketDiscounts( $oBasketPrice, $oDiscountList->getBasketItemDiscounts( $oArticle, $this, $this->getBasketUser() ), $oBasketItem->getAmount() );
00657                     if ( is_array($this->_aItemDiscounts) && is_array($aItemDiscounts) ) {
00658                         $this->_aItemDiscounts = $this->_mergeDiscounts( $this->_aItemDiscounts, $aItemDiscounts);
00659                     }
00660                 } else {
00661                     $oBasketItem->setSkipDiscounts( true );
00662                     $this->setSkipDiscounts( true );
00663                 }
00664                 $oBasketPrice->multiply( $oBasketItem->getAmount() );
00665 
00666                 //P collect discount values for basket items which are discountable
00667                 if ( !$oArticle->skipDiscounts() ) {
00668                     $this->_oDiscountProductsPriceList->addToPriceList( $oBasketPrice );
00669                 } else {
00670                     $this->_oNotDiscountedProductsPriceList->addToPriceList( $oBasketPrice );
00671                     $oBasketItem->setSkipDiscounts( true );
00672                     $this->setSkipDiscounts( true );
00673                 }
00674             } elseif ( $oBasketItem->isBundle() ) {
00675                 // if bundles price is set to zero
00676                 $oPrice = oxNew( "oxprice");
00677                 $oBasketItem->setPrice( $oPrice );
00678             }
00679         }
00680     }
00681 
00689     public function setDiscountCalcMode( $blCalcDiscounts )
00690     {
00691         $this->_blCalcDiscounts = $blCalcDiscounts;
00692     }
00693 
00699     public function canCalcDiscounts()
00700     {
00701         return $this->_blCalcDiscounts;
00702     }
00703 
00713     protected function _mergeDiscounts( $aDiscounts, $aItemDiscounts)
00714     {
00715         foreach ( $aItemDiscounts as $sKey => $oDiscount ) {
00716             // add prices of the same discounts
00717             if ( array_key_exists ($sKey, $aDiscounts) ) {
00718                 $aDiscounts[$sKey]->dDiscount += $oDiscount->dDiscount;
00719             } else {
00720                 $aDiscounts[$sKey] = $oDiscount;
00721             }
00722         }
00723         return $aDiscounts;
00724     }
00725 
00731     protected function _calcDeliveryCost()
00732     {
00733         if ( $this->_oDeliveryPrice !== null ) {
00734             return $this->_oDeliveryPrice;
00735         }
00736         $myConfig  = $this->getConfig();
00737         $oDeliveryPrice = oxNew( 'oxprice' );
00738         $oDeliveryPrice->setBruttoPriceMode();
00739 
00740         // don't calculate if not logged in
00741         $oUser = $this->getBasketUser();
00742 
00743         if ( !$oUser && !$myConfig->getConfigParam( 'blCalculateDelCostIfNotLoggedIn' ) ) {
00744             return $oDeliveryPrice;
00745         }
00746 
00747         // VAT for delivery ?
00748         $fDelVATPercent = 0;
00749         if ( $myConfig->getConfigParam( 'blCalcVATForDelivery' ) ) {
00750             $fDelVATPercent = $this->getMostUsedVatPercent();
00751             $oDeliveryPrice->setVat( $fDelVATPercent );
00752         }
00753 
00754         // list of active delivery costs
00755         if ( $myConfig->getConfigParam('bl_perfLoadDelivery') ) {
00756             $aDeliveryList = oxDeliveryList::getInstance()->getDeliveryList( $this,
00757                                         $oUser,
00758                                         $this->_findDelivCountry(),
00759                                         $this->getShippingId()
00760                                     );
00761 
00762             if ( count( $aDeliveryList ) > 0 ) {
00763                 foreach ( $aDeliveryList as $oDelivery ) {
00764                     //debug trace
00765                     if ( $myConfig->getConfigParam( 'iDebug' ) == 5 ) {
00766                         echo( "DelCost : ".$oDelivery->oxdelivery__oxtitle->value."<br>" );
00767                     }
00768                     $oDeliveryPrice->addPrice( $oDelivery->getDeliveryPrice( $fDelVATPercent ) );
00769                 }
00770             }
00771         }
00772 
00773         return $oDeliveryPrice;
00774     }
00775 
00781     public function getBasketUser()
00782     {
00783         if ( $this->_oUser == null ) {
00784             return $this->getUser();
00785         }
00786 
00787         return $this->_oUser;
00788     }
00789 
00797     public function setBasketUser( $oUser )
00798     {
00799         $this->_oUser = $oUser;
00800     }
00801 
00802     //P
00808     public function getMostUsedVatPercent()
00809     {
00810         return $this->_oProductsPriceList->getMostUsedVatPercent();
00811     }
00812 
00813     //P
00820     protected function _calcTotalPrice()
00821     {
00822         // 1. add products price
00823         $dprice = $this->_oProductsPriceList->getBruttoSum();
00824         $this->_oPrice->setPrice( $dprice );
00825 
00826         // 2. substract discounts
00827         if ( $dprice ) {
00828 
00829             // 2.1 applying basket item discounts
00830             foreach ( $this->_aItemDiscounts as $oDiscount ) {
00831 
00832                 // skipping bundle discounts
00833                 if ( $oDiscount->sType == 'itm' ) {
00834                     continue;
00835                 }
00836                 $this->_oPrice->subtract( $oDiscount->dDiscount );
00837             }
00838 
00839             // 2.2 applying basket discounts
00840             $this->_oPrice->subtract( $this->_oTotalDiscount->getBruttoPrice() );
00841 
00842             // 2.3 applying voucher discounts
00843             if ($oVoucherDisc = $this->getVoucherDiscount()) {
00844                 $this->_oPrice->subtract( $oVoucherDisc->getBruttoPrice() );
00845             }
00846         }
00847 
00848         // 2.3 add delivery cost
00849         if ( isset( $this->_aCosts['oxdelivery'] ) ) {
00850             $this->_oPrice->add( $this->_aCosts['oxdelivery']->getBruttoPrice() );
00851         }
00852 
00853         // 2.4 add wrapping price
00854         if ( isset( $this->_aCosts['oxwrapping'] ) ) {
00855             $this->_oPrice->add( $this->_aCosts['oxwrapping']->getBruttoPrice() );
00856         }
00857 
00858         // 2.5 add payment price
00859         if ( isset( $this->_aCosts['oxpayment'] ) ) {
00860             $this->_oPrice->add( $this->_aCosts['oxpayment']->getBruttoPrice() );
00861         }
00862 
00863         // 2.6 add TS protection price
00864         if ( isset( $this->_aCosts['oxtsprotection'] ) ) {
00865             $this->_oPrice->add( $this->_aCosts['oxtsprotection']->getBruttoPrice() );
00866         }
00867 
00868     }
00869 
00877     public function setVoucherDiscount( $dDiscount )
00878     {
00879         $this->_oVoucherDiscount = oxNew( 'oxPrice' );
00880         $this->_oVoucherDiscount->setBruttoPriceMode();
00881         $this->_oVoucherDiscount->add( $dDiscount );
00882     }
00883 
00889     protected function _calcVoucherDiscount()
00890     {
00891         if ( $this->getConfig()->getConfigParam( 'bl_showVouchers' ) && ($this->_oVoucherDiscount === null || ( $this->_blUpdateNeeded && !$this->isAdmin() ) ) ) {
00892 
00893             $this->_oVoucherDiscount = oxNew( 'oxPrice' );
00894             $this->_oVoucherDiscount->setBruttoPriceMode();
00895 
00896 
00897             // calculating price to apply discount
00898             $dPrice = $this->_oDiscountProductsPriceList->getBruttoSum() - $this->_oTotalDiscount->getBruttoPrice();
00899 
00900             // recalculating
00901             if ( count( $this->_aVouchers ) ) {
00902                 $oLang = oxLang::getInstance();
00903                 foreach ( $this->_aVouchers as $sVoucherId => $oStdVoucher ) {
00904                     $oVoucher = oxNew( 'oxvoucher' );
00905                     try { // checking
00906                         $oVoucher->load( $oStdVoucher->sVoucherId );
00907 
00908                         if ( !$this->_blSkipVouchersAvailabilityChecking ) {
00909                             $oVoucher->checkBasketVoucherAvailability( $this->_aVouchers, $dPrice );
00910                             $oVoucher->checkUserAvailability( $this->getBasketUser() );
00911                         }
00912 
00913                         // assigning real voucher discount value as this is the only place where real value is calculated
00914                         $dVoucherdiscount = $oVoucher->getDiscountValue( $dPrice );
00915 
00916                         // acumulating discount value
00917                         $this->_oVoucherDiscount->add( $dVoucherdiscount );
00918 
00919                         // collecting formatted for preview
00920                         $oStdVoucher->fVoucherdiscount = $oLang->formatCurrency( $dVoucherdiscount, $this->getBasketCurrency() );
00921                         $oStdVoucher->dVoucherdiscount = $dVoucherdiscount;
00922 
00923                         // substracting voucher discount
00924                         $dPrice -= $dVoucherdiscount;
00925                     } catch ( oxVoucherException $oEx ) {
00926 
00927                         // removing voucher on error
00928                         $oVoucher->unMarkAsReserved();
00929                         unset( $this->_aVouchers[$sVoucherId] );
00930 
00931                         // storing voucher error info
00932                         oxUtilsView::getInstance()->addErrorToDisplay($oEx, false, true);
00933                     }
00934                 }
00935             }
00936         }
00937     }
00938 
00939     //V
00946     protected function _applyDiscounts()
00947     {
00948         $dBruttoPrice = 0;
00949         $this->_aDiscountedVats = array();
00950         if ( $oPriceList = $this->getDiscountProductsPrice() ) {
00951             $dBruttoPrice = $oPriceList->getBruttoSum();
00952             $this->_aDiscountedVats = $oPriceList->getVatInfo();
00953         }
00954 
00955         //apply discounts for brutto price
00956         $dDiscountedBruttoPrice = $this->getDiscountedProductsBruttoPrice();
00957         $oTotalDiscount   = $this->getTotalDiscount();
00958         $oVoucherDiscount = $this->getVoucherDiscount();
00959 
00960         //apply discount for VATs
00961         if ( $dBruttoPrice &&
00962              ( ( $oTotalDiscount && $oTotalDiscount->getBruttoPrice() ) ||
00963                ( $oVoucherDiscount && $oVoucherDiscount->getBruttoPrice() )
00964              )
00965            ) {
00966             $dPercent = ( $dDiscountedBruttoPrice / $dBruttoPrice) * 100;
00967             foreach ( $this->_aDiscountedVats as $sKey => $dVat ) {
00968                 $this->_aDiscountedVats[$sKey] = oxPrice::percent( $dVat, $dPercent);
00969             }
00970         }
00971 
00972         $oUtils = oxUtils::getInstance();
00973         $dDiscVatSum = 0;
00974         foreach ( $this->_aDiscountedVats as $dVat ) {
00975             $dDiscVatSum += $oUtils->fRound( -$dVat, $this->_oCurrency);
00976         }
00977         //calculate netto price with discounts
00978         $this->_dDiscountedProductNettoPrice = $dDiscountedBruttoPrice + $dDiscVatSum;
00979     }
00980 
00986     protected function _calcBasketDiscount()
00987     {
00988         // resetting
00989         $this->_aDiscounts = array();
00990 
00991         // P using prices sum which has discount, not sum of skipped discounts
00992         $dOldprice = $this->_oDiscountProductsPriceList->getBruttoSum();
00993 
00994         // add basket discounts
00995         $aDiscounts = oxDiscountList::getInstance()->getBasketDiscounts( $this, $this->getBasketUser() );
00996 
00997         foreach ( $aDiscounts as $oDiscount ) {
00998 
00999             // storing applied discounts
01000             $oStdDiscount = $oDiscount->getSimpleDiscount();
01001 
01002             // skipping bundle discounts
01003             if ( $oDiscount->oxdiscount__oxaddsumtype->value == 'itm' ) {
01004                 continue;
01005             }
01006 
01007             // saving discount info
01008             $oStdDiscount->dDiscount = $oDiscount->getAbsValue( $dOldprice );
01009             if ($dOldprice < $oStdDiscount->dDiscount) {
01010                 $oStdDiscount->dDiscount = $dOldprice;
01011             }
01012 
01013             if ($oStdDiscount->dDiscount != 0) {
01014                 $this->_aDiscounts[$oDiscount->getId()] = $oStdDiscount;
01015                 // substracting product price after discount
01016                 $dOldprice = $dOldprice - $oStdDiscount->dDiscount;
01017             }
01018         }
01019     }
01020 
01026     protected function _calcBasketTotalDiscount()
01027     {
01028         if ( $this->_oTotalDiscount === null || ( $this->_blUpdateNeeded && !$this->isAdmin() ) ) {
01029             $this->_oTotalDiscount = oxNew( 'oxPrice' );
01030             $this->_oTotalDiscount->setBruttoPriceMode();
01031 
01032             if ( is_array($this->_aDiscounts) ) {
01033                 foreach ( $this->_aDiscounts as $oDiscount ) {
01034 
01035                     // skipping bundle discounts
01036                     if ( $oDiscount->sType == 'itm' ) {
01037                         continue;
01038                     }
01039 
01040                     // add discount value to total basket discount
01041                     $this->_oTotalDiscount->add( $oDiscount->dDiscount );
01042                 }
01043             }
01044         }
01045     }
01046 
01056     protected function _calcBasketWrapping()
01057     {
01058         $myConfig = $this->getConfig();
01059         $oWrappingPrice = oxNew( 'oxPrice' );
01060         $oWrappingPrice->setBruttoPriceMode();
01061 
01062         // wrapping VAT
01063         if ( $myConfig->getConfigParam( 'blCalcVatForWrapping' ) ) {
01064             $oWrappingPrice->setVat( $this->getMostUsedVatPercent() );
01065         }
01066 
01067         // calculating basket items wrapping
01068         foreach ( $this->_aBasketContents as $oBasketItem ) {
01069 
01070             if ( ( $oWrapping = $oBasketItem->getWrapping() ) ) {
01071                 $oWrapPrice = $oWrapping->getWrappingPrice( $oBasketItem->getAmount() );
01072                 $oWrappingPrice->add( $oWrapPrice->getBruttoPrice() );
01073             }
01074         }
01075 
01076         // gift card price calculation
01077         if ( ( $oCard = $this->getCard() ) ) {
01078             $oCardPrice = $oCard->getWrappingPrice();
01079             $oWrappingPrice->add( $oCardPrice->getBruttoPrice() );
01080         }
01081 
01082         return $oWrappingPrice;
01083     }
01084 
01091     protected function _calcPaymentCost()
01092     {
01093         // resetting values
01094         $oPaymentPrice = oxNew( 'oxPrice' );
01095         $oPaymentPrice->setBruttoPriceMode();
01096 
01097         // payment
01098         if ( ( $this->_sPaymentId = $this->getPaymentId() ) ) {
01099 
01100             $oPayment = oxNew( 'oxpayment' );
01101             $oPayment->load( $this->_sPaymentId );
01102 
01103             $oPaymentPrice = $oPayment->getPaymentPrice( $this );
01104         }
01105 
01106         return $oPaymentPrice;
01107     }
01108 
01115     protected function _calcTsProtectionCost()
01116     {
01117         // resetting values
01118         $oProtectionPrice = oxNew( 'oxPrice' );
01119         $oProtectionPrice->setBruttoPriceMode();
01120 
01121         // payment
01122         if ( ( $this->_sTsProductId = $this->getTsProductId() ) ) {
01123 
01124             $oTsProtection = oxNew('oxtsprotection');
01125             $oTsProduct = $oTsProtection->getTsProduct( $this->_sTsProductId );
01126 
01127             $oProtectionPrice = $oTsProduct->oPrice;
01128         }
01129         return $oProtectionPrice;
01130     }
01131 
01140     public function setCost( $sCostName, $oPrice = null )
01141     {
01142         $this->_aCosts[$sCostName] = $oPrice;
01143     }
01144 
01153     public function calculateBasket( $blForceUpdate = false )
01154     {
01155         if ( !$this->isEnabled() ) {
01156             return;
01157         }
01158 
01159         if ( !$this->_blUpdateNeeded && !$blForceUpdate ) {
01160             return;
01161         }
01162 
01163         $this->_aCosts = array();
01164 
01165         $this->_oPrice = oxNew( 'oxprice' );
01166         $this->_oPrice->setBruttoPriceMode();
01167 
01168         //  1. saving basket to the database
01169         $this->_save();
01170 
01171         //  2. remove all bundles
01172         $this->_clearBundles();
01173 
01174         //  3. generate bundle items
01175         $this->_addBundles();
01176 
01177         // reserve active basket
01178         if ($this->getConfig()->getConfigParam( 'blPsBasketReservationEnabled' )) {
01179             $this->getSession()->getBasketReservations()->reserveBasket($this);
01180         }
01181 
01182         //  4. calculating item prices
01183         $this->_calcItemsPrice();
01184 
01185         //  5. calculating/applying discounts
01186         $this->_calcBasketDiscount();
01187 
01188         //  6. calculating basket total discount
01189         $this->_calcBasketTotalDiscount();
01190 
01191         //  7. check for vouchers
01192         $this->_calcVoucherDiscount();
01193 
01194         //  8. applies all discounts to pricelist
01195         $this->_applyDiscounts();
01196 
01197         //  9. calculating additional costs:
01198         //  9.1: delivery
01199         $this->setCost( 'oxdelivery', $this->_calcDeliveryCost() );
01200 
01201         //  9.2: adding wrapping costs
01202         $this->setCost( 'oxwrapping', $this->_calcBasketWrapping() );
01203 
01204         //  9.3: adding payment cost
01205         $this->setCost( 'oxpayment', $this->_calcPaymentCost() );
01206 
01207         //  9.4: adding TS protection cost
01208         $this->setCost( 'oxtsprotection', $this->_calcTsProtectionCost() );
01209 
01210         //  10. calculate total price
01211         $this->_calcTotalPrice();
01212 
01213         //  11. setting deprecated values
01214         $this->_setDeprecatedValues();
01215 
01216         //  12.setting to up-to-date status
01217         $this->afterUpdate();
01218     }
01219 
01225     public function onUpdate()
01226     {
01227         $this->_blUpdateNeeded = true;
01228     }
01229 
01235     public function afterUpdate()
01236     {
01237         $this->_blUpdateNeeded = false;
01238     }
01239 
01247     public function getBasketSummary()
01248     {
01249         if ( $this->_blUpdateNeeded || $this->_aBasketSummary === null ) {
01250             $this->_aBasketSummary = new Oxstdclass();
01251             $this->_aBasketSummary->aArticles = array();
01252             $this->_aBasketSummary->aCategories = array();
01253             $this->_aBasketSummary->iArticleCount = 0;
01254             $this->_aBasketSummary->dArticlePrice = 0;
01255             $this->_aBasketSummary->dArticleDiscountablePrice = 0;
01256         }
01257 
01258         if ( !$this->isEnabled() ) {
01259             return $this->_aBasketSummary;
01260         }
01261 
01262         $myConfig = $this->getConfig();
01263         foreach ( $this->_aBasketContents as $oBasketItem ) {
01264             if ( !$oBasketItem->isBundle() && $oArticle = $oBasketItem->getArticle(false) ) {
01265                 $aCatIds = $oArticle->getCategoryIds();
01266                 //#M530 if price is not loaded for articles
01267                 $dPrice = 0;
01268                 $dDiscountablePrice = 0;
01269                 if ( ( $oPrice = $oArticle->getPrice( $oBasketItem->getAmount() ) ) ) {
01270                     $dPrice = $oPrice->getBruttoPrice();
01271                     if ( !$oArticle->skipDiscounts() ) {
01272                         $dDiscountablePrice = $dPrice;
01273                     }
01274                 }
01275 
01276                 foreach ( $aCatIds as $sCatId ) {
01277                     if ( !isset( $this->_aBasketSummary->aCategories[$sCatId] ) ) {
01278                         $this->_aBasketSummary->aCategories[$sCatId] = new Oxstdclass();
01279                     }
01280 
01281                     $this->_aBasketSummary->aCategories[$sCatId]->dPrice  += $dPrice * $oBasketItem->getAmount();
01282                     $this->_aBasketSummary->aCategories[$sCatId]->dDiscountablePrice += $dDiscountablePrice * $oBasketItem->getAmount();
01283                     $this->_aBasketSummary->aCategories[$sCatId]->dAmount += $oBasketItem->getAmount();
01284                     $this->_aBasketSummary->aCategories[$sCatId]->iCount++;
01285                 }
01286 
01287                 // variant handling
01288                 if ( ($sParentId = $oArticle->getProductParentId()) && $myConfig->getConfigParam( 'blVariantParentBuyable' ) ) {
01289                     if ( !isset( $this->_aBasketSummary->aArticles[$sParentId] ) ) {
01290                         $this->_aBasketSummary->aArticles[$sParentId] = 0;
01291                     }
01292                     $this->_aBasketSummary->aArticles[$sParentId] += $oBasketItem->getAmount();
01293                 }
01294 
01295                 if ( !isset( $this->_aBasketSummary->aArticles[$oBasketItem->getProductId()] ) ) {
01296                     $this->_aBasketSummary->aArticles[$oBasketItem->getProductId()] = 0;
01297                 }
01298 
01299                 $this->_aBasketSummary->aArticles[$oBasketItem->getProductId()] += $oBasketItem->getAmount();
01300                 $this->_aBasketSummary->iArticleCount += $oBasketItem->getAmount();
01301                 $this->_aBasketSummary->dArticlePrice += $dPrice * $oBasketItem->getAmount();
01302                 $this->_aBasketSummary->dArticleDiscountablePrice += $dDiscountablePrice * $oBasketItem->getAmount();
01303             }
01304         }
01305         return $this->_aBasketSummary;
01306     }
01307 
01319     public function addVoucher( $sVoucherId )
01320     {
01321         // calculating price to check
01322         // P using prices sum which has discount, not sum of skipped discounts
01323         $dPrice = 0;
01324         if ( $this->_oDiscountProductsPriceList ) {
01325             $dPrice = $this->_oDiscountProductsPriceList->getBruttoSum();
01326         }
01327 
01328         try { // trying to load voucher and apply it
01329 
01330             $oVoucher = oxNew( 'oxvoucher' );
01331 
01332             if ( !$this->_blSkipVouchersAvailabilityChecking ) {
01333                 $oVoucher->getVoucherByNr( $sVoucherId, $this->_aVouchers, true );
01334                 $oVoucher->checkVoucherAvailability( $this->_aVouchers, $dPrice );
01335                 $oVoucher->checkUserAvailability( $this->getBasketUser() );
01336                 $oVoucher->markAsReserved();
01337             } else {
01338                 $oVoucher->load( $sVoucherId );
01339             }
01340 
01341             // saving voucher info
01342             $this->_aVouchers[$oVoucher->oxvouchers__oxid->value] = $oVoucher->getSimpleVoucher();
01343         } catch ( oxVoucherException $oEx ) {
01344 
01345             // problems adding voucher
01346             oxUtilsView::getInstance()->addErrorToDisplay( $oEx, false, true );
01347         }
01348 
01349         $this->onUpdate();
01350     }
01351 
01359     public function removeVoucher( $sVoucherId )
01360     {
01361         // removing if it exists
01362         if ( isset( $this->_aVouchers[$sVoucherId] ) ) {
01363 
01364             $oVoucher = oxNew( 'oxvoucher' );
01365             $oVoucher->load( $sVoucherId );
01366 
01367             $oVoucher->unMarkAsReserved();
01368 
01369             // unsetting it if exists this voucher in DB or not
01370             unset( $this->_aVouchers[$sVoucherId] );
01371             $this->onUpdate();
01372         }
01373 
01374     }
01375 
01381     public function resetUserInfo()
01382     {
01383         $this->setPayment( null );
01384         $this->setShipping( null );
01385     }
01386 
01394     protected function _setDeprecatedValues()
01395     {
01396         $this->dproductsprice    = $this->_oProductsPriceList->getBruttoSum(); // products brutto price
01397         $this->dproductsnetprice = $this->getDiscountedNettoPrice();  // products netto price();
01398 
01399         //P sum vat values
01400         $this->dVAT = array_sum( $this->_oProductsPriceList->getVatInfo() );
01401         $oLang = oxLang::getInstance();
01402 
01403         // formatting final values
01404         $this->fproductsprice    = $this->getFProductsPrice();
01405         $this->fproductsnetprice = $this->getProductsNetPrice();
01406         $this->fVAT = $oLang->formatCurrency( $this->dVAT, $this->getBasketCurrency());
01407 
01408         // delivery costs
01409         if ( $oDeliveryCost = $this->getCosts( 'oxdelivery' ) ) {
01410 
01411             $this->ddeliverycost    = $oDeliveryCost->getBruttoPrice();
01412             $this->ddeliverynetcost = $oDeliveryCost->getNettoPrice();
01413             $this->dDelVAT          = $oDeliveryCost->getVatValue();
01414             $this->fDelVATPercent   = $oDeliveryCost->getVat() / 100; // needed to divide, because in template value is multyplied by 100
01415 
01416             // formating values
01417             $this->fdeliverycost    = $oLang->formatCurrency( $this->ddeliverycost, $this->getBasketCurrency() );
01418             $this->fdeliverynetcost = $oLang->formatCurrency( $this->ddeliverynetcost, $this->getBasketCurrency() );
01419             $this->fDelVAT          = $this->getDelCostVat();
01420         }
01421 
01422         //P
01423         // wrapping costs
01424         if ( $oWrappingCost = $this->getCosts( 'oxwrapping' ) ) {
01425 
01426             $this->dWrappingPrice = $oWrappingCost->getBruttoPrice();
01427             $this->dWrappingNetto = $oWrappingCost->getNettoPrice();
01428             $this->dWrappingVAT   = $oWrappingCost->getVatValue();
01429 
01430             //formating values
01431             $this->fWrappingPrice      = $oLang->formatCurrency( $this->dWrappingPrice, $this->getBasketCurrency() );
01432             $this->fWrappingNetto      = $this->getWrappCostNet();
01433             $this->fWrappingVAT        = $this->getWrappCostVat();
01434             $this->fWrappingVATPercent = $this->getWrappCostVatPercent();
01435         }
01436 
01437         //P
01438         // payment costs
01439         if ( $oPaymentCost = $this->getCosts( 'oxpayment' ) ) {
01440 
01441             $this->dAddPaymentSum    = $this->getPaymentCosts();
01442             $this->dAddPaymentSumVAT = $oPaymentCost->getVatValue();
01443 
01444             //formating values
01445             $this->fAddPaymentSum    = $oLang->formatCurrency( $this->dAddPaymentSum, $this->getBasketCurrency() );
01446             $this->fAddPaymentSumVAT = $this->getPayCostVat();
01447             $this->fAddPaymentSumVATPercent = $this->getPayCostVatPercent();
01448             $this->fAddPaymentNetSum = $this->getPayCostNet();
01449         }
01450 
01451         //P
01452         // basket total prices
01453         $this->dprice = $this->_oPrice->getBruttoPrice();
01454         $this->fprice = $oLang->formatCurrency( $this->dprice, $this->getBasketCurrency() );
01455 
01456         // product info
01457         $this->iCntProducts = $this->getProductsCount();
01458         $this->dCntItems    = $this->getItemsCount();
01459         $this->aVATs        = $this->getProductVats();
01460         $this->aBasketContents = $this->getContents();
01461 
01462         // setting gift card information
01463         $this->giftmessage = $this->getCardMessage();
01464         $this->chosencard  = $this->getCardId();
01465 
01466         $this->oCard = $this->getCard();
01467 
01468         // discount information
01469         // formating discount value
01470         $this->aDiscounts = $this->getDiscounts();
01471         if ( count($this->aDiscounts) > 0 ) {
01472             foreach ($this->aDiscounts as $oDiscount) {
01473                 $oDiscount->fDiscount = $oLang->formatCurrency( $oDiscount->dDiscount, $this->getBasketCurrency() );
01474             }
01475         }
01476         $this->dDiscount  = $this->getTotalDiscount()->getBruttoPrice();
01477 
01478         // voucher info
01479         $this->aVouchers = $this->getVouchers();
01480         $this->dVoucherDiscount = $this->getVoucherDiscValue();
01481         $this->fVoucherDiscount = $oLang->formatCurrency( $this->dVoucherDiscount, $this->getBasketCurrency() );
01482         $this->dSkippedDiscount = $this->hasSkipedDiscount();
01483 
01484     }
01485 
01486 
01492     protected function _canSaveBasket()
01493     {
01494         $blCanSave = !$this->getConfig()->getConfigParam( 'blPerfNoBasketSaving' );
01495         return $blCanSave;
01496     }
01497 
01503     public function load()
01504     {
01505         $oUser = $this->getBasketUser();
01506         if ( !$oUser ) {
01507             return;
01508         }
01509 
01510         $oBasket = $oUser->getBasket( 'savedbasket' );
01511 
01512         // restoring from saved history
01513         $aSavedItems = $oBasket->getItems();
01514         foreach ( $aSavedItems as $oItem ) {
01515             try {
01516                 $oSelList = $oItem->getSelList();
01517 
01518                 $this->addToBasket( $oItem->oxuserbasketitems__oxartid->value, $oItem->oxuserbasketitems__oxamount->value, $oSelList, $oItem->getPersParams(), true );
01519             } catch( oxArticleException $oEx ) {
01520                 // caught and ignored
01521             }
01522         }
01523     }
01524 
01530     protected function _save()
01531     {
01532         if ( $this->_canSaveBasket() ) {
01533 
01534             if ( $oUser = $this->getBasketUser() ) {
01535                 //first delete all contents
01536                 //#2039
01537                 $oSavedBasket = $oUser->getBasket( 'savedbasket' );
01538                 $oSavedBasket->delete();
01539 
01540                 //then save
01541                 foreach ( $this->_aBasketContents as $oBasketItem ) {
01542                     $oSavedBasket->addItemToBasket( $oBasketItem->getProductId(), $oBasketItem->getAmount(), $oBasketItem->getSelList(), true, $oBasketItem->getPersParams() );
01543                 }
01544             }
01545         }
01546     }
01547 
01559     /*
01560     protected function _addItemToSavedBasket( $sProductId , $dAmount, $aSel, $blOverride = false, $aPersParam = null )
01561     {
01562         // updating basket history
01563         if ( $oUser = $this->getBasketUser() ) {
01564             $oUser->getBasket( 'savedbasket' )->addItemToBasket( $sProductId, $dAmount, $aSel, $blOverride, $aPersParam );
01565         }
01566     }*/
01567 
01575     protected function _deleteSavedBasket()
01576     {
01577         // deleting basket if session user available
01578         if ( $oUser = $this->getBasketUser() ) {
01579             $oUser->getBasket( 'savedbasket' )->delete();
01580         }
01581 
01582         // basket exclude
01583         if ( $this->getConfig()->getConfigParam( 'blBasketExcludeEnabled' )) {
01584             $this->setBasketRootCatId(null);
01585         }
01586     }
01587 
01593     protected function _findDelivCountry()
01594     {
01595         $myConfig = $this->getConfig();
01596         $oUser    = $this->getBasketUser();
01597 
01598         $sDelivCountry = null;
01599 
01600         if ( !$oUser ) {
01601             // don't calculate if not logged in unless specified otherwise
01602             $aHomeCountry = $myConfig->getConfigParam( 'aHomeCountry' );
01603             if ( $myConfig->getConfigParam( 'blCalculateDelCostIfNotLoggedIn' ) && is_array( $aHomeCountry ) ) {
01604                 $sDelivCountry = current( $aHomeCountry );
01605             }
01606         } else {
01607 
01608             // ok, logged in
01609             if ( $sCountryId = $myConfig->getGlobalParameter( 'delcountryid' ) ) {
01610                 $sDelivCountry = $sCountryId;
01611             } elseif ( $sAddressId = oxConfig::getParameter( 'deladrid' ) ) {
01612 
01613                 $oDelAdress = oxNew( 'oxaddress' );
01614                 if ( $oDelAdress->load( $sAddressId ) ) {
01615                     $sDelivCountry = $oDelAdress->oxaddress__oxcountryid->value;
01616                 }
01617             }
01618 
01619             // still not found ?
01620             if ( !$sDelivCountry ) {
01621                 $sDelivCountry = $oUser->oxuser__oxcountryid->value;
01622             }
01623         }
01624 
01625         return $sDelivCountry;
01626     }
01627 
01633     public function deleteBasket()
01634     {
01635         $this->_aBasketContents = array();
01636         $this->getSession()->delBasket();
01637 
01638         if ($this->getConfig()->getConfigParam( 'blPsBasketReservationEnabled' )) {
01639             $this->getSession()->getBasketReservations()->discardReservations();
01640         }
01641 
01642         // merging basket history
01643         if ( !$this->getConfig()->getConfigParam( 'blPerfNoBasketSaving' ) ) {
01644             $this->_deleteSavedBasket();
01645         }
01646     }
01647 
01655     public function setPayment( $sPaymentId = null )
01656     {
01657         $this->_sPaymentId = $sPaymentId;
01658     }
01659 
01665     public function getPaymentId()
01666     {
01667         if ( !$this->_sPaymentId ) {
01668              $this->_sPaymentId = oxConfig::getParameter( 'paymentid' );
01669         }
01670         return $this->_sPaymentId;
01671     }
01672 
01680     public function setShipping( $sShippingSetId = null )
01681     {
01682         $this->_sShippingSetId = $sShippingSetId;
01683         oxSession::setVar( 'sShipSet', $sShippingSetId );
01684     }
01685 
01693     public function setDeliveryPrice( $oShippingPrice = null )
01694     {
01695         $this->_oDeliveryPrice = $oShippingPrice;
01696     }
01697 
01703     public function getShippingId()
01704     {
01705         if ( !$this->_sShippingSetId ) {
01706              $this->_sShippingSetId = oxConfig::getParameter( 'sShipSet' );
01707         }
01708 
01709         $sActPaymentId = $this->getPaymentId();
01710         // setting default if none is set
01711         if ( !$this->_sShippingSetId && $sActPaymentId != 'oxempty' ) {
01712             $oUser = $this->getUser();
01713 
01714             // choosing first preferred delivery set
01715             list( , $sActShipSet ) = oxDeliverySetList::getInstance()->getDeliverySetData( null, $oUser, $this );
01716             // in case nothing was found and no user set - choosing default
01717             $this->_sShippingSetId = $sActShipSet ? $sActShipSet : ( $oUser ? null : 'oxidstandard' );
01718         } elseif ( !$this->isAdmin() && $sActPaymentId == 'oxempty' ) {
01719             // in case 'oxempty' is payment id - delivery set must be reset
01720             $this->_sShippingSetId = null;
01721         }
01722 
01723         return $this->_sShippingSetId;
01724     }
01725 
01731     public function getBasketArticles()
01732     {
01733         $aBasketArticles = array();
01734 
01735         foreach ( $this->_aBasketContents as $sItemKey => $oBasketItem ) {
01736             try {
01737                 $oProduct = $oBasketItem->getArticle();
01738 
01739                 if ( $this->getConfig()->getConfigParam( 'bl_perfLoadSelectLists' ) ) {
01740                     // marking chosen select list
01741                     $aSelList = $oBasketItem->getSelList();
01742                     if ( is_array( $aSelList ) && ( $aSelectlist = $oProduct->getSelectLists( $sItemKey ) ) ) {
01743                         reset( $aSelList );
01744                         while ( list( $conkey, $iSel ) = each( $aSelList ) ) {
01745                             $aSelectlist[$conkey][$iSel]->selected = 1;
01746                         }
01747                         $oProduct->setSelectlist( $aSelectlist );
01748                     }
01749                 }
01750             } catch ( oxNoArticleException $oEx ) {
01751                 oxUtilsView::getInstance()->addErrorToDisplay( $oEx );
01752                 $this->removeItem( $sItemKey );
01753                 $this->calculateBasket( true );
01754                 continue;
01755             } catch ( oxArticleInputException $oEx ) {
01756                 oxUtilsView::getInstance()->addErrorToDisplay( $oEx );
01757                 $this->removeItem( $sItemKey );
01758                 $this->calculateBasket( true );
01759                 continue;
01760             }
01761 
01762             $aBasketArticles[$sItemKey] = $oProduct;
01763         }
01764         return $aBasketArticles;
01765     }
01766 
01772     public function getDiscountProductsPrice()
01773     {
01774         return $this->_oDiscountProductsPriceList;
01775     }
01776 
01782     public function getProductsPrice()
01783     {
01784         if ( is_null($this->_oProductsPriceList) ) {
01785             $this->_oProductsPriceList = oxNew( 'oxPriceList' );
01786         }
01787 
01788         return $this->_oProductsPriceList;
01789     }
01790 
01796     public function getPrice()
01797     {
01798         if ( is_null($this->_oPrice) ) {
01799             $this->_oPrice = oxNew( 'oxprice' );
01800         }
01801 
01802         return $this->_oPrice;
01803     }
01804 
01811     public function getOrderId()
01812     {
01813         return $this->_sOrderId;
01814     }
01815 
01823     public function setOrderId( $sId )
01824     {
01825         $this->_sOrderId = $sId;
01826     }
01827 
01836     public function getCosts( $sId = null )
01837     {
01838         // if user want some specific cost - return it
01839         if ( $sId ) {
01840             return isset( $this->_aCosts[$sId] )?$this->_aCosts[$sId]:null;
01841         }
01842         return $this->_aCosts;
01843     }
01844 
01850     public function getVouchers()
01851     {
01852         return $this->_aVouchers;
01853     }
01854 
01860     public function getProductsCount()
01861     {
01862         return $this->_iProductsCnt;
01863     }
01864 
01870     public function getItemsCount()
01871     {
01872         return $this->_dItemsCnt;
01873     }
01874 
01880     public function getWeight()
01881     {
01882         return $this->_dWeight;
01883     }
01884 
01890     public function getContents()
01891     {
01892         return $this->_aBasketContents;
01893     }
01894 
01902     public function getProductVats( $blFormatCurrency = true)
01903     {
01904         if ( !$this->_oNotDiscountedProductsPriceList ) {
01905             return array();
01906         }
01907 
01908         $aVats = $this->_oNotDiscountedProductsPriceList->getVatInfo();
01909 
01910         $oUtils = oxUtils::getInstance();
01911         foreach ( $this->_aDiscountedVats as $sKey => $dVat ) {
01912             // add prices of the same discounts
01913             $aVats[$sKey] += $oUtils->fRound( $dVat, $this->_oCurrency);
01914         }
01915 
01916         if ( $blFormatCurrency ) {
01917             $oLang = oxLang::getInstance();
01918             foreach ( $aVats as $sKey => $dVat ) {
01919                 $aVats[$sKey] = $oLang->formatCurrency( $dVat, $this->getBasketCurrency() );
01920             }
01921         }
01922 
01923         return $aVats;
01924     }
01925 
01931     public function getDiscountedNettoPrice()
01932     {
01933         if ( $this->_oNotDiscountedProductsPriceList ) {
01934             return $this->_dDiscountedProductNettoPrice + $this->_oNotDiscountedProductsPriceList->getNettoSum();
01935         }
01936         return false;
01937     }
01938 
01946     public function setCardMessage( $sMessage )
01947     {
01948         $this->_sCardMessage = $sMessage;
01949     }
01950 
01956     public function getCardMessage()
01957     {
01958         return $this->_sCardMessage;
01959     }
01960 
01968     public function setCardId( $sCardId )
01969     {
01970         $this->_sCardId = $sCardId;
01971     }
01972 
01978     public function getCardId()
01979     {
01980         return $this->_sCardId;
01981     }
01982 
01988     public function getCard()
01989     {
01990         $oCard = null;
01991         if ( $sCardId = $this->getCardId() ) {
01992             $oCard = oxNew( 'oxwrapping' );
01993             $oCard->load( $sCardId );
01994         }
01995         return $oCard;
01996     }
01997 
02003     public function getTotalDiscount()
02004     {
02005         return $this->_oTotalDiscount;
02006     }
02007 
02013     public function getDiscounts()
02014     {
02015         if ( $this->getTotalDiscount() && $this->getTotalDiscount()->getBruttoPrice() == 0 && count($this->_aItemDiscounts) == 0) {
02016             return null;
02017         }
02018 
02019         return array_merge($this->_aItemDiscounts, $this->_aDiscounts);
02020     }
02021 
02027     public function getVoucherDiscount()
02028     {
02029         if ($this->getConfig()->getConfigParam( 'bl_showVouchers' )) {
02030             return $this->_oVoucherDiscount;
02031         }
02032         return null;
02033     }
02034 
02042     public function setBasketCurrency( $oCurrency )
02043     {
02044         $this->_oCurrency = $oCurrency;
02045     }
02046 
02052     public function getBasketCurrency()
02053     {
02054         if ( $this->_oCurrency === null ) {
02055             $this->_oCurrency = $this->getConfig()->getActShopCurrencyObject();
02056         }
02057 
02058         return $this->_oCurrency;
02059     }
02060 
02068     public function setSkipVouchersChecking( $blSkipChecking = null )
02069     {
02070         $this->_blSkipVouchersAvailabilityChecking = $blSkipChecking;
02071     }
02072 
02078     public function hasSkipedDiscount()
02079     {
02080         return $this->_blSkipDiscounts;
02081     }
02082 
02090     public function setSkipDiscounts( $blSkip )
02091     {
02092         $this->_blSkipDiscounts = $blSkip;
02093     }
02094 
02100     public function getProductsNetPrice()
02101     {
02102         return oxLang::getInstance()->formatCurrency( $this->getDiscountedNettoPrice(), $this->getBasketCurrency() );
02103     }
02104 
02110     public function getFProductsPrice()
02111     {
02112         if ( $this->_oProductsPriceList ) {
02113             return oxLang::getInstance()->formatCurrency( $this->_oProductsPriceList->getBruttoSum(), $this->getBasketCurrency() );
02114         }
02115         return null;
02116     }
02117 
02123     public function getDelCostVatPercent()
02124     {
02125         return $this->getCosts( 'oxdelivery' )->getVat();
02126     }
02127 
02133     public function getDelCostVat()
02134     {
02135         $dDelVAT = $this->getCosts( 'oxdelivery' )->getVatValue();
02136         if ( $dDelVAT > 0 ) {
02137             return oxLang::getInstance()->formatCurrency( $dDelVAT, $this->getBasketCurrency() );
02138         }
02139         return false;
02140     }
02141 
02147     public function getDelCostNet()
02148     {
02149         if ( $this->getBasketUser() || $this->getConfig()->getConfigParam( 'blCalculateDelCostIfNotLoggedIn' ) ) {
02150             return oxLang::getInstance()->formatCurrency( $this->getCosts( 'oxdelivery' )->getNettoPrice(), $this->getBasketCurrency() );
02151         }
02152         return false;
02153     }
02154 
02160     public function getPayCostVatPercent()
02161     {
02162         return $this->getCosts( 'oxpayment' )->getVat();
02163     }
02164 
02170     public function getPayCostVat()
02171     {
02172         $dPayVAT = $this->getCosts( 'oxpayment' )->getVatValue();
02173         if ( $dPayVAT > 0 ) {
02174             return oxLang::getInstance()->formatCurrency( $dPayVAT, $this->getBasketCurrency() );
02175         }
02176         return false;
02177     }
02178 
02184     public function getPayCostNet()
02185     {
02186         return oxLang::getInstance()->formatCurrency( $this->getCosts( 'oxpayment' )->getNettoPrice(), $this->getBasketCurrency() );
02187     }
02188 
02194     public function getPaymentCosts()
02195     {
02196         return $this->getCosts( 'oxpayment' )->getBruttoPrice();
02197     }
02198 
02204     public function getFPaymentCosts()
02205     {
02206         $oPaymentCost = $this->getCosts( 'oxpayment' );
02207 
02208         if ( $oPaymentCost && $oPaymentCost->getBruttoPrice() ) {
02209             return oxLang::getInstance()->formatCurrency( $oPaymentCost->getBruttoPrice(), $this->getBasketCurrency() );
02210         }
02211         return false;
02212     }
02213 
02219     public function getVoucherDiscValue()
02220     {
02221         if ( $this->getVoucherDiscount() ) {
02222             return $this->getVoucherDiscount()->getBruttoPrice();
02223         }
02224         return false;
02225     }
02226 
02232     public function getWrappCostVatPercent()
02233     {
02234         return $this->getCosts( 'oxwrapping' )->getVat();
02235     }
02236 
02242     public function getWrappCostVat()
02243     {
02244         $dWrappVAT = $this->getCosts( 'oxwrapping' )->getVatValue();
02245         if ( $dWrappVAT > 0 ) {
02246             return oxLang::getInstance()->formatCurrency( $dWrappVAT, $this->getBasketCurrency() );
02247         }
02248         return false;
02249 
02250     }
02251 
02257     public function getWrappCostNet()
02258     {
02259         $dWrappNet = $this->getCosts( 'oxwrapping' )->getNettoPrice();
02260         if ( $dWrappNet > 0 ) {
02261             return  oxLang::getInstance()->formatCurrency( $dWrappNet, $this->getBasketCurrency() );
02262         }
02263         return false;
02264     }
02265 
02271     public function getFWrappingCosts()
02272     {
02273         $oWrappingCost = $this->getCosts( 'oxwrapping' );
02274         if ( $oWrappingCost && $oWrappingCost->getBruttoPrice() ) {
02275             return oxLang::getInstance()->formatCurrency( $oWrappingCost->getBruttoPrice(), $this->getBasketCurrency() );
02276         }
02277         return false;
02278     }
02279 
02285     public function getFPrice()
02286     {
02287         return oxLang::getInstance()->formatCurrency( $this->getPrice()->getBruttoPrice(), $this->getBasketCurrency() );
02288     }
02289 
02295     public function getFDeliveryCosts()
02296     {
02297         $oDeliveryCost = $this->getCosts( 'oxdelivery' );
02298         if ( $oDeliveryCost && $oDeliveryCost->getBruttoPrice()) {
02299             return oxLang::getInstance()->formatCurrency( $oDeliveryCost->getBruttoPrice(), $this->getBasketCurrency() );
02300         }
02301         return false;
02302     }
02303 
02309     public function getDeliveryCosts()
02310     {
02311         if ( $oDeliveryCost = $this->getCosts( 'oxdelivery' ) ) {
02312             return $oDeliveryCost->getBruttoPrice();
02313         }
02314         return false;
02315     }
02316 
02324     public function setTotalDiscount( $dDiscount )
02325     {
02326         $this->_oTotalDiscount = oxNew( 'oxPrice' );
02327         $this->_oTotalDiscount->setBruttoPriceMode();
02328         $this->_oTotalDiscount->add( $dDiscount );
02329     }
02330 
02337     public function getPriceForPayment()
02338     {
02339         $dPrice = $this->getDiscountedProductsBruttoPrice();
02340         //#1905 not discounted products should be included in payment amount calculation
02341         if ( $oPriceList = $this->getNotDiscountProductsPrice() ) {
02342             $dPrice += $oPriceList->getBruttoSum();
02343         }
02344 
02345         // adding delivery price to final price
02346         if ( $oDeliveryPrice = $this->_aCosts['oxdelivery'] ) {
02347             $dPrice += $oDeliveryPrice->getBruttoPrice();
02348         }
02349 
02350         return $dPrice;
02351     }
02352 
02358     public function getDiscountedProductsBruttoPrice()
02359     {
02360         if ( $oProductsPrice = $this->getDiscountProductsPrice() ) {
02361             $dPrice = $oProductsPrice->getBruttoSum();
02362         }
02363 
02364         // substracting total discount
02365         if ( $oPrice = $this->getTotalDiscount() ) {
02366             $dPrice -= $oPrice->getBruttoPrice();
02367         }
02368 
02369         if ( $oVoucherPrice = $this->getVoucherDiscount() ) {
02370             $dPrice -= $oVoucherPrice->getBruttoPrice();
02371         }
02372 
02373         return $dPrice;
02374     }
02375 
02381     public function isBelowMinOrderPrice()
02382     {
02383         $blIsBelowMinOrderPrice = false;
02384         $sConfValue = $this->getConfig()->getConfigParam( 'iMinOrderPrice' );
02385         if ( is_numeric($sConfValue) && $this->getProductsCount() ) {
02386             $dMinOrderPrice = oxPrice::getPriceInActCurrency( ( int ) $sConfValue );
02387             $blIsBelowMinOrderPrice = ($dMinOrderPrice > $this->getDiscountedProductsBruttoPrice());
02388         }
02389 
02390         return $blIsBelowMinOrderPrice;
02391 
02392     }
02393 
02402     public function getArtStockInBasket( $sArtId, $sExpiredArtId = null )
02403     {
02404         $dArtStock = 0;
02405         foreach ( $this->_aBasketContents as $sItemKey => $oOrderArticle ) {
02406             if ( $oOrderArticle && ( $sExpiredArtId == null || $sExpiredArtId != $sItemKey ) ) {
02407                 if ( $oOrderArticle->getArticle()->getId() == $sArtId ) {
02408                     $dArtStock += $oOrderArticle->getAmount();
02409                 }
02410             }
02411         }
02412 
02413         return $dArtStock;
02414     }
02415 
02423     public function canAddProductToBasket( $sProductId )
02424     {
02425         $blCanAdd = null;
02426 
02427         // if basket category is not set..
02428         if ( $this->_sBasketCategoryId === null ) {
02429             $oCat = null;
02430 
02431             // request category
02432             if ( $oView = $this->getConfig()->getActiveView() ) {
02433                 if ( $oCat = $oView->getActCategory() ) {
02434                     if ( !$this->_isProductInRootCategory( $sProductId, $oCat->oxcategories__oxrootid->value ) ) {
02435                         $oCat = null;
02436                     } else {
02437                         $blCanAdd = true;
02438                     }
02439                 }
02440             }
02441 
02442             // product main category
02443             if ( !$oCat ) {
02444                 $oProduct = oxNew( "oxarticle" );
02445                 if ( $oProduct->load( $sProductId ) ) {
02446                     $oCat = $oProduct->getCategory();
02447                 }
02448             }
02449 
02450             // root category id
02451             if ( $oCat ) {
02452                 $this->setBasketRootCatId($oCat->oxcategories__oxrootid->value);
02453             }
02454         }
02455 
02456         // avoiding double check..
02457         if ( $blCanAdd === null ) {
02458             $blCanAdd = $this->_sBasketCategoryId ? $this->_isProductInRootCategory( $sProductId, $this->getBasketRootCatId() ) : true;
02459         }
02460 
02461         return $blCanAdd;
02462     }
02463 
02472     protected function _isProductInRootCategory( $sProductId, $sRootCatId )
02473     {
02474         $sO2CTable = getViewName( 'oxobject2category' );
02475         $sCatTable = getViewName( 'oxcategories' );
02476 
02477         $oDb = oxDb::getDb();
02478         $sParentId  = $oDb->getOne( "select oxparentid from oxarticles where oxid = ".$oDb->quote( $sProductId ) );
02479         $sProductId = $sParentId ? $sParentId : $sProductId;
02480 
02481         $sQ = "select 1 from {$sO2CTable}
02482                  left join {$sCatTable} on {$sCatTable}.oxid = {$sO2CTable}.oxcatnid
02483                  where {$sO2CTable}.oxobjectid = ".$oDb->quote( $sProductId )." and
02484                        {$sCatTable}.oxrootid = ".$oDb->quote( $sRootCatId );
02485 
02486         return (bool) $oDb->getOne( $sQ );
02487     }
02488 
02496     public function setBasketRootCatId($sRoot)
02497     {
02498         $this->_sBasketCategoryId = $sRoot;
02499     }
02500 
02506     public function getBasketRootCatId()
02507     {
02508         return $this->_sBasketCategoryId;
02509     }
02510 
02518     public function setCatChangeWarningState( $blShow )
02519     {
02520         $this->_blShowCatChangeWarning = $blShow;
02521     }
02522 
02528     public function showCatChangeWarning()
02529     {
02530         return $this->_blShowCatChangeWarning;
02531     }
02532 
02540     public function setTsProductId( $sProductId )
02541     {
02542         $this->_sTsProductId = $sProductId;
02543     }
02544 
02550     public function getTsProductId()
02551     {
02552         return $this->_sTsProductId;
02553     }
02554 
02560     public function getFTsProtectionCosts()
02561     {
02562         $oProtectionCost = $this->getCosts( 'oxtsprotection' );
02563         if ( $oProtectionCost && $oProtectionCost->getBruttoPrice() ) {
02564             return oxLang::getInstance()->formatCurrency( $oProtectionCost->getBruttoPrice(), $this->getBasketCurrency() );
02565         }
02566         return false;
02567     }
02568 
02574     public function getTsProtectionVatPercent()
02575     {
02576         return $this->getCosts( 'oxtsprotection' )->getVat();
02577     }
02578 
02584     public function getTsProtectionVat()
02585     {
02586         $dProtectionVAT = $this->getCosts( 'oxtsprotection' )->getVatValue();
02587         if ( $dProtectionVAT > 0 ) {
02588             return oxLang::getInstance()->formatCurrency( $dProtectionVAT, $this->getBasketCurrency() );
02589         }
02590         return false;
02591     }
02592 
02598     public function getTsProtectionNet()
02599     {
02600         return oxLang::getInstance()->formatCurrency( $this->getCosts( 'oxtsprotection' )->getNettoPrice(), $this->getBasketCurrency() );
02601     }
02602 
02608     public function getTsProtectionCosts()
02609     {
02610         $oProtection = $this->getCosts( 'oxtsprotection' );
02611         if ( $oProtection ) {
02612             return $oProtection->getBruttoPrice();
02613         }
02614         return false;
02615     }
02616 
02622     public function getNotDiscountProductsPrice()
02623     {
02624         return $this->_oNotDiscountedProductsPriceList;
02625     }
02626 
02627 }